| author | |
| committer | |
| log | 529ef75101e21bd45402c516138343b4770238eb |
| tree | 56c925bd7df84e5f223c31a7c8fa90606c8e2dc9 |
| parent | 1e7dcaa3ae57294ab5998b44a8c13ccc5019e7ea |
| parent | 2ad073ec6d4e2be967f18c9907844404a7eed42e |
| signature |
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 | 30 | const test_step = b.step("test", "Run all the tests"); |
| 31 | 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 | 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 | 35 | const docgen_exe = b.addExecutable(.{ |
| 35 | 36 | .name = "docgen", |
| ... | ... | @@ -166,6 +167,7 @@ pub fn build(b: *std.Build) !void { |
| 166 | 167 | exe.pie = pie; |
| 167 | 168 | exe.sanitize_thread = sanitize_thread; |
| 168 | 169 | exe.entitlements = entitlements; |
| 170 | if (no_bin) exe.emit_bin = .no_emit; | |
| 169 | 171 | |
| 170 | 172 | exe.build_id = b.option( |
| 171 | 173 | std.Build.Step.Compile.BuildId, |
doc/langref.html.in+1-1| ... | ... | @@ -10176,7 +10176,7 @@ pub fn main() void { |
| 10176 | 10176 | |
| 10177 | 10177 | {#header_open|Invalid Error Set Cast#} |
| 10178 | 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 | 10180 | const Set1 = error{ |
| 10181 | 10181 | A, |
| 10182 | 10182 | B, |
lib/std/array_list.zig+44| ... | ... | @@ -459,6 +459,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 459 | 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 | 484 | /// Remove and return the last element from the list. |
| 463 | 485 | /// Asserts the list has at least one item. |
| 464 | 486 | /// Invalidates pointers to the removed element. |
| ... | ... | @@ -949,6 +971,28 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 949 | 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 | 996 | /// Remove and return the last element from the list. |
| 953 | 997 | /// Asserts the list has at least one item. |
| 954 | 998 | /// Invalidates pointers to last element. |
lib/std/builtin.zig+3-3| ... | ... | @@ -143,7 +143,7 @@ pub const Mode = OptimizeMode; |
| 143 | 143 | |
| 144 | 144 | /// This data structure is used by the Zig language code generation and |
| 145 | 145 | /// therefore must be kept in sync with the compiler implementation. |
| 146 | pub const CallingConvention = enum { | |
| 146 | pub const CallingConvention = enum(u8) { | |
| 147 | 147 | /// This is the default Zig calling convention used when not using `export` on `fn` |
| 148 | 148 | /// and no other calling convention is specified. |
| 149 | 149 | Unspecified, |
| ... | ... | @@ -190,7 +190,7 @@ pub const CallingConvention = enum { |
| 190 | 190 | |
| 191 | 191 | /// This data structure is used by the Zig language code generation and |
| 192 | 192 | /// therefore must be kept in sync with the compiler implementation. |
| 193 | pub const AddressSpace = enum { | |
| 193 | pub const AddressSpace = enum(u5) { | |
| 194 | 194 | generic, |
| 195 | 195 | gs, |
| 196 | 196 | fs, |
| ... | ... | @@ -283,7 +283,7 @@ pub const Type = union(enum) { |
| 283 | 283 | |
| 284 | 284 | /// This data structure is used by the Zig language code generation and |
| 285 | 285 | /// therefore must be kept in sync with the compiler implementation. |
| 286 | pub const Size = enum { | |
| 286 | pub const Size = enum(u2) { | |
| 287 | 287 | One, |
| 288 | 288 | Many, |
| 289 | 289 | Slice, |
lib/std/child_process.zig+2-2| ... | ... | @@ -530,7 +530,7 @@ pub const ChildProcess = struct { |
| 530 | 530 | // can fail between fork() and execve(). |
| 531 | 531 | // Therefore, we do all the allocation for the execve() before the fork(). |
| 532 | 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 | 534 | for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr; |
| 535 | 535 | |
| 536 | 536 | const envp = m: { |
| ... | ... | @@ -542,7 +542,7 @@ pub const ChildProcess = struct { |
| 542 | 542 | } else if (builtin.output_mode == .Exe) { |
| 543 | 543 | // Then we have Zig start code and this works. |
| 544 | 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 | 546 | } else { |
| 547 | 547 | // TODO come up with a solution for this. |
| 548 | 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 | 1256 | // A single, non-overlapping memcpy suffices. |
| 1257 | 1257 | @memcpy(frag[0..first.len], first); |
| 1258 | 1258 | } else { |
| 1259 | // Need two memcpy calls because one alone would overlap. | |
| 1260 | @memcpy(frag[0..in], first[0..in]); | |
| 1261 | const leftover = first.len - in; | |
| 1262 | @memcpy(frag[in..][0..leftover], first[in..][0..leftover]); | |
| 1259 | // One memcpy call would overlap, so just do this instead. | |
| 1260 | std.mem.copyForwards(u8, frag, first); | |
| 1263 | 1261 | } |
| 1264 | 1262 | } |
| 1265 | 1263 |
lib/std/dwarf.zig+1| ... | ... | @@ -936,6 +936,7 @@ pub const DwarfInfo = struct { |
| 936 | 936 | const ranges_val = compile_unit.die.getAttr(AT.ranges) orelse continue; |
| 937 | 937 | const ranges_offset = switch (ranges_val.*) { |
| 938 | 938 | .SecOffset => |off| off, |
| 939 | .Const => |c| try c.asUnsignedLe(), | |
| 939 | 940 | .RangeListOffset => |idx| off: { |
| 940 | 941 | if (compile_unit.is_64) { |
| 941 | 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 | 36 | pub const XxHash64 = xxhash.XxHash64; |
| 37 | 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 | 53 | test { |
| 40 | 54 | _ = adler; |
| 41 | 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 | 91 | |
| 92 | 92 | // Help the optimizer see that hashing an int is easy by inlining! |
| 93 | 93 | // TODO Check if the situation is better after #561 is resolved. |
| 94 | .Int => { | |
| 95 | if (comptime meta.trait.hasUniqueRepresentation(Key)) { | |
| 96 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) }); | |
| 97 | } else { | |
| 98 | // Take only the part containing the key value, the remaining | |
| 99 | // bytes are undefined and must not be hashed! | |
| 100 | const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Key), 8) catch unreachable; | |
| 101 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key)[0..byte_size] }); | |
| 102 | } | |
| 94 | .Int => |int| switch (int.signedness) { | |
| 95 | .signed => hash(hasher, @bitCast(@Type(.{ .Int = .{ | |
| 96 | .bits = int.bits, | |
| 97 | .signedness = .unsigned, | |
| 98 | } }), key), strat), | |
| 99 | .unsigned => { | |
| 100 | if (comptime meta.trait.hasUniqueRepresentation(Key)) { | |
| 101 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) }); | |
| 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 | 111 | .Bool => hash(hasher, @boolToInt(key), strat), |
lib/std/math/big/int.zig+5-2| ... | ... | @@ -2158,6 +2158,9 @@ pub const Const = struct { |
| 2158 | 2158 | pub fn to(self: Const, comptime T: type) ConvertError!T { |
| 2159 | 2159 | switch (@typeInfo(T)) { |
| 2160 | 2160 | .Int => |info| { |
| 2161 | // Make sure -0 is handled correctly. | |
| 2162 | if (self.eqZero()) return 0; | |
| 2163 | ||
| 2161 | 2164 | const UT = std.meta.Int(.unsigned, info.bits); |
| 2162 | 2165 | |
| 2163 | 2166 | if (!self.fitsInTwosComp(info.signedness, info.bits)) { |
| ... | ... | @@ -2509,7 +2512,7 @@ pub const Const = struct { |
| 2509 | 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 | 2516 | // Limbs are stored in little-endian order. |
| 2514 | 2517 | var result: Limb = 0; |
| 2515 | 2518 | for (a.limbs) |limb| { |
| ... | ... | @@ -2517,7 +2520,7 @@ pub const Const = struct { |
| 2517 | 2520 | result += limb_tz; |
| 2518 | 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 | 4226 | /// The alignment must be a power of 2 and greater than 0. |
| 4227 | 4227 | /// Asserts that rounding up the address does not cause integer overflow. |
| 4228 | 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 | 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 | 1131 | defer arena_allocator.deinit(); |
| 1132 | 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 | 1135 | for (argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr; |
| 1136 | 1136 | |
| 1137 | 1137 | const envp = m: { |
| ... | ... | @@ -1143,7 +1143,7 @@ pub fn execve( |
| 1143 | 1143 | } else if (builtin.output_mode == .Exe) { |
| 1144 | 1144 | // Then we have Zig start code and this works. |
| 1145 | 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 | 1147 | } else { |
| 1148 | 1148 | // TODO come up with a solution for this. |
| 1149 | 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 | 5 | |
| 6 | 6 | const std = @import("std"); |
| 7 | 7 | const builtin = @import("builtin"); |
| 8 | const Value = @import("value.zig").Value; | |
| 9 | const Type = @import("type.zig").Type; | |
| 10 | 8 | const assert = std.debug.assert; |
| 9 | ||
| 11 | 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 | 16 | instructions: std.MultiArrayList(Inst).Slice, |
| 14 | 17 | /// The meaning of this data is determined by `Inst.Tag` value. |
| 15 | 18 | /// The first few indexes are reserved. See `ExtraIndex` for the values. |
| 16 | 19 | extra: []const u32, |
| 17 | values: []const Value, | |
| 18 | 20 | |
| 19 | 21 | pub const ExtraIndex = enum(u32) { |
| 20 | 22 | /// Payload index of the main `Block` in the `extra` array. |
| ... | ... | @@ -183,6 +185,18 @@ pub const Inst = struct { |
| 183 | 185 | /// Allocates stack local memory. |
| 184 | 186 | /// Uses the `ty` field. |
| 185 | 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 | 200 | /// If the function will pass the result by-ref, this instruction returns the |
| 187 | 201 | /// result pointer. Otherwise it is equivalent to `alloc`. |
| 188 | 202 | /// Uses the `ty` field. |
| ... | ... | @@ -394,11 +408,9 @@ pub const Inst = struct { |
| 394 | 408 | /// was executed on the operand. |
| 395 | 409 | /// Uses the `ty_pl` field. Payload is `TryPtr`. |
| 396 | 410 | try_ptr, |
| 397 | /// A comptime-known value. Uses the `ty_pl` field, payload is index of | |
| 398 | /// `values` array. | |
| 399 | constant, | |
| 400 | /// A comptime-known type. Uses the `ty` field. | |
| 401 | const_ty, | |
| 411 | /// A comptime-known value via an index into the InternPool. | |
| 412 | /// Uses the `interned` field. | |
| 413 | interned, | |
| 402 | 414 | /// Notes the beginning of a source code statement and marks the line and column. |
| 403 | 415 | /// Result type is always void. |
| 404 | 416 | /// Uses the `dbg_stmt` field. |
| ... | ... | @@ -408,10 +420,10 @@ pub const Inst = struct { |
| 408 | 420 | /// Marks the end of a semantic scope for debug info variables. |
| 409 | 421 | dbg_block_end, |
| 410 | 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 | 424 | dbg_inline_begin, |
| 413 | 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 | 427 | dbg_inline_end, |
| 416 | 428 | /// Marks the beginning of a local variable. The operand is a pointer pointing |
| 417 | 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 | 849 | /// The position of an AIR instruction within the `Air` instructions array. |
| 838 | 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 | 943 | /// All instructions have an 8-byte payload, which is contained within |
| 843 | 944 | /// this union. `Tag` determines which union field is active, as well as |
| ... | ... | @@ -845,6 +946,7 @@ pub const Inst = struct { |
| 845 | 946 | pub const Data = union { |
| 846 | 947 | no_op: void, |
| 847 | 948 | un_op: Ref, |
| 949 | interned: InternPool.Index, | |
| 848 | 950 | |
| 849 | 951 | bin_op: struct { |
| 850 | 952 | lhs: Ref, |
| ... | ... | @@ -864,6 +966,10 @@ pub const Inst = struct { |
| 864 | 966 | // Index into a different array. |
| 865 | 967 | payload: u32, |
| 866 | 968 | }, |
| 969 | ty_fn: struct { | |
| 970 | ty: Ref, | |
| 971 | func: Module.Fn.Index, | |
| 972 | }, | |
| 867 | 973 | br: struct { |
| 868 | 974 | block_inst: Index, |
| 869 | 975 | operand: Ref, |
| ... | ... | @@ -896,6 +1002,19 @@ pub const Inst = struct { |
| 896 | 1002 | // Index into a different array. |
| 897 | 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 | 1019 | // Make sure we don't accidentally add a field to make this union |
| 901 | 1020 | // bigger than expected. Note that in Debug builds, Zig is allowed |
| ... | ... | @@ -974,8 +1093,7 @@ pub const FieldParentPtr = struct { |
| 974 | 1093 | pub const Shuffle = struct { |
| 975 | 1094 | a: Inst.Ref, |
| 976 | 1095 | b: Inst.Ref, |
| 977 | // index to air_values | |
| 978 | mask: u32, | |
| 1096 | mask: InternPool.Index, | |
| 979 | 1097 | mask_len: u32, |
| 980 | 1098 | }; |
| 981 | 1099 | |
| ... | ... | @@ -1064,15 +1182,15 @@ pub fn getMainBody(air: Air) []const Air.Inst.Index { |
| 1064 | 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 | 1186 | const ref_int = @enumToInt(inst); |
| 1069 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | |
| 1070 | return Air.Inst.Ref.typed_value_map[ref_int].ty; | |
| 1187 | if (ref_int < InternPool.static_keys.len) { | |
| 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 | 1194 | const datas = air.instructions.items(.data); |
| 1077 | 1195 | switch (air.instructions.items(.tag)[inst]) { |
| 1078 | 1196 | .add, |
| ... | ... | @@ -1114,7 +1232,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1114 | 1232 | .div_exact_optimized, |
| 1115 | 1233 | .rem_optimized, |
| 1116 | 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 | 1237 | .sqrt, |
| 1120 | 1238 | .sin, |
| ... | ... | @@ -1132,7 +1250,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1132 | 1250 | .trunc_float, |
| 1133 | 1251 | .neg, |
| 1134 | 1252 | .neg_optimized, |
| 1135 | => return air.typeOf(datas[inst].un_op), | |
| 1253 | => return air.typeOf(datas[inst].un_op, ip), | |
| 1136 | 1254 | |
| 1137 | 1255 | .cmp_lt, |
| 1138 | 1256 | .cmp_lte, |
| ... | ... | @@ -1159,8 +1277,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1159 | 1277 | .error_set_has_value, |
| 1160 | 1278 | => return Type.bool, |
| 1161 | 1279 | |
| 1162 | .const_ty => return Type.type, | |
| 1163 | ||
| 1164 | 1280 | .alloc, |
| 1165 | 1281 | .ret_ptr, |
| 1166 | 1282 | .err_return_trace, |
| ... | ... | @@ -1171,7 +1287,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1171 | 1287 | |
| 1172 | 1288 | .assembly, |
| 1173 | 1289 | .block, |
| 1174 | .constant, | |
| 1175 | 1290 | .struct_field_ptr, |
| 1176 | 1291 | .struct_field_val, |
| 1177 | 1292 | .slice_elem_ptr, |
| ... | ... | @@ -1194,6 +1309,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1194 | 1309 | .try_ptr, |
| 1195 | 1310 | => return air.getRefType(datas[inst].ty_pl.ty), |
| 1196 | 1311 | |
| 1312 | .interned => return ip.typeOf(datas[inst].interned).toType(), | |
| 1313 | ||
| 1197 | 1314 | .not, |
| 1198 | 1315 | .bitcast, |
| 1199 | 1316 | .load, |
| ... | ... | @@ -1243,7 +1360,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1243 | 1360 | .ret_load, |
| 1244 | 1361 | .unreach, |
| 1245 | 1362 | .trap, |
| 1246 | => return Type.initTag(.noreturn), | |
| 1363 | => return Type.noreturn, | |
| 1247 | 1364 | |
| 1248 | 1365 | .breakpoint, |
| 1249 | 1366 | .dbg_stmt, |
| ... | ... | @@ -1280,63 +1397,67 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1280 | 1397 | .wasm_memory_grow => return Type.i32, |
| 1281 | 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 | 1404 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { |
| 1288 | const callee_ty = air.typeOf(datas[inst].pl_op.operand); | |
| 1289 | switch (callee_ty.zigTypeTag()) { | |
| 1290 | .Fn => return callee_ty.fnReturnType(), | |
| 1291 | .Pointer => return callee_ty.childType().fnReturnType(), | |
| 1292 | else => unreachable, | |
| 1293 | } | |
| 1405 | const callee_ty = air.typeOf(datas[inst].pl_op.operand, ip); | |
| 1406 | return callee_ty.fnReturnTypeIp(ip); | |
| 1294 | 1407 | }, |
| 1295 | 1408 | |
| 1296 | 1409 | .slice_elem_val, .ptr_elem_val, .array_elem_val => { |
| 1297 | const ptr_ty = air.typeOf(datas[inst].bin_op.lhs); | |
| 1298 | return ptr_ty.elemType(); | |
| 1410 | const ptr_ty = air.typeOf(datas[inst].bin_op.lhs, ip); | |
| 1411 | return ptr_ty.childTypeIp(ip); | |
| 1299 | 1412 | }, |
| 1300 | 1413 | .atomic_load => { |
| 1301 | const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr); | |
| 1302 | return ptr_ty.elemType(); | |
| 1414 | const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr, ip); | |
| 1415 | return ptr_ty.childTypeIp(ip); | |
| 1303 | 1416 | }, |
| 1304 | 1417 | .atomic_rmw => { |
| 1305 | const ptr_ty = air.typeOf(datas[inst].pl_op.operand); | |
| 1306 | return ptr_ty.elemType(); | |
| 1418 | const ptr_ty = air.typeOf(datas[inst].pl_op.operand, ip); | |
| 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 | 1428 | .select => { |
| 1313 | 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 | 1433 | .@"try" => { |
| 1318 | const err_union_ty = air.typeOf(datas[inst].pl_op.operand); | |
| 1319 | return err_union_ty.errorUnionPayload(); | |
| 1434 | const err_union_ty = air.typeOf(datas[inst].pl_op.operand, ip); | |
| 1435 | return ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type.toType(); | |
| 1320 | 1436 | }, |
| 1321 | 1437 | |
| 1322 | 1438 | .work_item_id, |
| 1323 | 1439 | .work_group_size, |
| 1324 | 1440 | .work_group_id, |
| 1325 | 1441 | => return Type.u32, |
| 1442 | ||
| 1443 | .inferred_alloc => unreachable, | |
| 1444 | .inferred_alloc_comptime => unreachable, | |
| 1326 | 1445 | } |
| 1327 | 1446 | } |
| 1328 | 1447 | |
| 1329 | 1448 | pub fn getRefType(air: Air, ref: Air.Inst.Ref) Type { |
| 1330 | 1449 | const ref_int = @enumToInt(ref); |
| 1331 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | |
| 1332 | var buffer: Value.ToTypeBuffer = undefined; | |
| 1333 | return Air.Inst.Ref.typed_value_map[ref_int].val.toType(&buffer); | |
| 1450 | if (ref_int < ref_start_index) { | |
| 1451 | const ip_index = @intToEnum(InternPool.Index, ref_int); | |
| 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 | 1455 | const air_tags = air.instructions.items(.tag); |
| 1337 | 1456 | const air_datas = air.instructions.items(.data); |
| 1338 | assert(air_tags[inst_index] == .const_ty); | |
| 1339 | return air_datas[inst_index].ty; | |
| 1457 | return switch (air_tags[inst_index]) { | |
| 1458 | .interned => air_datas[inst_index].interned.toType(), | |
| 1459 | else => unreachable, | |
| 1460 | }; | |
| 1340 | 1461 | } |
| 1341 | 1462 | |
| 1342 | 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 | 1471 | u32 => air.extra[i], |
| 1351 | 1472 | Inst.Ref => @intToEnum(Inst.Ref, air.extra[i]), |
| 1352 | 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 | 1477 | i += 1; |
| 1356 | 1478 | } |
| ... | ... | @@ -1363,17 +1485,17 @@ pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end |
| 1363 | 1485 | pub fn deinit(air: *Air, gpa: std.mem.Allocator) void { |
| 1364 | 1486 | air.instructions.deinit(gpa); |
| 1365 | 1487 | gpa.free(air.extra); |
| 1366 | gpa.free(air.values); | |
| 1367 | 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 { | |
| 1373 | return @intToEnum(Air.Inst.Ref, ref_start_index + inst); | |
| 1493 | pub fn indexToRef(inst: Inst.Index) Inst.Ref { | |
| 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 | 1499 | const ref_int = @enumToInt(inst); |
| 1378 | 1500 | if (ref_int >= ref_start_index) { |
| 1379 | 1501 | return ref_int - ref_start_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 | 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 | 1514 | const ref_int = @enumToInt(inst); |
| 1388 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | |
| 1389 | return Air.Inst.Ref.typed_value_map[ref_int].val; | |
| 1515 | if (ref_int < ref_start_index) { | |
| 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 | 1520 | const air_datas = air.instructions.items(.data); |
| 1393 | 1521 | switch (air.instructions.items(.tag)[inst_index]) { |
| 1394 | .constant => return air.values[air_datas[inst_index].ty_pl.payload], | |
| 1395 | .const_ty => unreachable, | |
| 1396 | else => return air.typeOfIndex(inst_index).onePossibleValue(), | |
| 1522 | .interned => return air_datas[inst_index].interned.toValue(), | |
| 1523 | else => return air.typeOfIndex(inst_index, &mod.intern_pool).onePossibleValue(mod), | |
| 1397 | 1524 | } |
| 1398 | 1525 | } |
| 1399 | 1526 | |
| ... | ... | @@ -1406,10 +1533,11 @@ pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 { |
| 1406 | 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 | |
| 1410 | /// side effects. If an instruction does not need to be lowered, and Liveness determines its result | |
| 1411 | /// is unused, backends should avoid lowering it. | |
| 1412 | pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { | |
| 1536 | /// Returns whether the given instruction must always be lowered, for instance | |
| 1537 | /// because it can cause side effects. If an instruction does not need to be | |
| 1538 | /// lowered, and Liveness determines its result is unused, backends should | |
| 1539 | /// avoid lowering it. | |
| 1540 | pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { | |
| 1413 | 1541 | const data = air.instructions.items(.data)[inst]; |
| 1414 | 1542 | return switch (air.instructions.items(.tag)[inst]) { |
| 1415 | 1543 | .arg, |
| ... | ... | @@ -1498,6 +1626,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { |
| 1498 | 1626 | .mul_with_overflow, |
| 1499 | 1627 | .shl_with_overflow, |
| 1500 | 1628 | .alloc, |
| 1629 | .inferred_alloc, | |
| 1630 | .inferred_alloc_comptime, | |
| 1501 | 1631 | .ret_ptr, |
| 1502 | 1632 | .bit_and, |
| 1503 | 1633 | .bit_or, |
| ... | ... | @@ -1546,8 +1676,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { |
| 1546 | 1676 | .cmp_neq_optimized, |
| 1547 | 1677 | .cmp_vector, |
| 1548 | 1678 | .cmp_vector_optimized, |
| 1549 | .constant, | |
| 1550 | .const_ty, | |
| 1679 | .interned, | |
| 1551 | 1680 | .is_null, |
| 1552 | 1681 | .is_non_null, |
| 1553 | 1682 | .is_null_ptr, |
| ... | ... | @@ -1616,8 +1745,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { |
| 1616 | 1745 | => false, |
| 1617 | 1746 | |
| 1618 | 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(), | |
| 1620 | .slice_elem_val, .ptr_elem_val => air.typeOf(data.bin_op.lhs).isVolatilePtr(), | |
| 1621 | .atomic_load => air.typeOf(data.atomic_load.ptr).isVolatilePtr(), | |
| 1748 | .load => air.typeOf(data.ty_op.operand, ip).isVolatilePtrIp(ip), | |
| 1749 | .slice_elem_val, .ptr_elem_val => air.typeOf(data.bin_op.lhs, ip).isVolatilePtrIp(ip), | |
| 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 | 3934 | var section_gz = decl_gz.makeSubBlock(params_scope); |
| 3935 | 3935 | defer section_gz.unstack(); |
| 3936 | 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 | 3938 | if (section_gz.instructionsSlice().len == 0) { |
| 3939 | 3939 | // In this case we will send a len=0 body which can be encoded more efficiently. |
| 3940 | 3940 | break :inst inst; |
| ... | ... | @@ -4137,7 +4137,7 @@ fn globalVarDecl( |
| 4137 | 4137 | break :inst try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .address_space_type } }, var_decl.ast.addrspace_node); |
| 4138 | 4138 | }; |
| 4139 | 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 | 4142 | const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none; |
| 4143 | 4143 | wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace); |
| ... | ... | @@ -4497,7 +4497,7 @@ fn testDecl( |
| 4497 | 4497 | .cc_gz = null, |
| 4498 | 4498 | .align_ref = .none, |
| 4499 | 4499 | .align_gz = null, |
| 4500 | .ret_ref = .void_type, | |
| 4500 | .ret_ref = .anyerror_void_error_union_type, | |
| 4501 | 4501 | .ret_gz = null, |
| 4502 | 4502 | .section_ref = .none, |
| 4503 | 4503 | .section_gz = null, |
| ... | ... | @@ -4510,7 +4510,7 @@ fn testDecl( |
| 4510 | 4510 | .body_gz = &fn_block, |
| 4511 | 4511 | .lib_name = 0, |
| 4512 | 4512 | .is_var_args = false, |
| 4513 | .is_inferred_error = true, | |
| 4513 | .is_inferred_error = false, | |
| 4514 | 4514 | .is_test = true, |
| 4515 | 4515 | .is_extern = false, |
| 4516 | 4516 | .is_noinline = false, |
| ... | ... | @@ -7878,7 +7878,7 @@ fn unionInit( |
| 7878 | 7878 | params: []const Ast.Node.Index, |
| 7879 | 7879 | ) InnerError!Zir.Inst.Ref { |
| 7880 | 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 | 7882 | const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ |
| 7883 | 7883 | .container_type = union_type, |
| 7884 | 7884 | .field_name = field_name, |
| ... | ... | @@ -8100,12 +8100,12 @@ fn builtinCall( |
| 8100 | 8100 | if (ri.rl == .ref) { |
| 8101 | 8101 | return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ |
| 8102 | 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 | 8106 | const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ |
| 8107 | 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 | 8110 | return rvalue(gz, ri, result, node); |
| 8111 | 8111 | }, |
| ... | ... | @@ -8271,11 +8271,11 @@ fn builtinCall( |
| 8271 | 8271 | .align_of => return simpleUnOpType(gz, scope, ri, node, params[0], .align_of), |
| 8272 | 8272 | |
| 8273 | 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 | 8275 | .set_eval_branch_quota => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .set_eval_branch_quota), |
| 8276 | 8276 | .enum_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .enum_to_int), |
| 8277 | 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 | 8279 | .error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .anyerror_type } }, params[0], .error_name), |
| 8280 | 8280 | .set_runtime_safety => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_runtime_safety), |
| 8281 | 8281 | .sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt), |
| ... | ... | @@ -8334,7 +8334,7 @@ fn builtinCall( |
| 8334 | 8334 | }, |
| 8335 | 8335 | .panic => { |
| 8336 | 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 | 8339 | .trap => { |
| 8340 | 8340 | try emitDbgNode(gz, node); |
| ... | ... | @@ -8450,7 +8450,7 @@ fn builtinCall( |
| 8450 | 8450 | }, |
| 8451 | 8451 | .c_define => { |
| 8452 | 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 | 8454 | const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); |
| 8455 | 8455 | const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ |
| 8456 | 8456 | .node = gz.nodeIndexToRelative(node), |
| ... | ... | @@ -8530,7 +8530,7 @@ fn builtinCall( |
| 8530 | 8530 | return rvalue(gz, ri, result, node); |
| 8531 | 8531 | }, |
| 8532 | 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 | 8534 | const callee = try expr(gz, scope, .{ .rl = .none }, params[1]); |
| 8535 | 8535 | const args = try expr(gz, scope, .{ .rl = .none }, params[2]); |
| 8536 | 8536 | const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ |
| ... | ... | @@ -8546,7 +8546,7 @@ fn builtinCall( |
| 8546 | 8546 | }, |
| 8547 | 8547 | .field_parent_ptr => { |
| 8548 | 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 | 8550 | const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ |
| 8551 | 8551 | .parent_type = parent_type, |
| 8552 | 8552 | .field_name = field_name, |
| ... | ... | @@ -8701,7 +8701,7 @@ fn hasDeclOrField( |
| 8701 | 8701 | tag: Zir.Inst.Tag, |
| 8702 | 8702 | ) InnerError!Zir.Inst.Ref { |
| 8703 | 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 | 8705 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ |
| 8706 | 8706 | .lhs = container_type, |
| 8707 | 8707 | .rhs = name, |
| ... | ... | @@ -8851,7 +8851,7 @@ fn simpleCBuiltin( |
| 8851 | 8851 | ) InnerError!Zir.Inst.Ref { |
| 8852 | 8852 | const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; |
| 8853 | 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 | 8855 | _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ |
| 8856 | 8856 | .node = gz.nodeIndexToRelative(node), |
| 8857 | 8857 | .operand = operand, |
| ... | ... | @@ -8869,7 +8869,7 @@ fn offsetOf( |
| 8869 | 8869 | tag: Zir.Inst.Tag, |
| 8870 | 8870 | ) InnerError!Zir.Inst.Ref { |
| 8871 | 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 | 8873 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ |
| 8874 | 8874 | .lhs = type_inst, |
| 8875 | 8875 | .rhs = field_name, |
| ... | ... | @@ -10271,6 +10271,8 @@ fn rvalue( |
| 10271 | 10271 | as_ty | @enumToInt(Zir.Inst.Ref.i32_type), |
| 10272 | 10272 | as_ty | @enumToInt(Zir.Inst.Ref.u64_type), |
| 10273 | 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 | 10276 | as_ty | @enumToInt(Zir.Inst.Ref.usize_type), |
| 10275 | 10277 | as_ty | @enumToInt(Zir.Inst.Ref.isize_type), |
| 10276 | 10278 | as_ty | @enumToInt(Zir.Inst.Ref.c_char_type), |
| ... | ... | @@ -10296,15 +10298,30 @@ fn rvalue( |
| 10296 | 10298 | as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type), |
| 10297 | 10299 | as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type), |
| 10298 | 10300 | as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type), |
| 10301 | as_ty | @enumToInt(Zir.Inst.Ref.anyframe_type), | |
| 10299 | 10302 | as_ty | @enumToInt(Zir.Inst.Ref.null_type), |
| 10300 | 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 | 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 | 10325 | as_comptime_int | @enumToInt(Zir.Inst.Ref.zero), |
| 10309 | 10326 | as_comptime_int | @enumToInt(Zir.Inst.Ref.one), |
| 10310 | 10327 | as_bool | @enumToInt(Zir.Inst.Ref.bool_true), |
| ... | ... | @@ -10677,8 +10694,8 @@ fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 { |
| 10677 | 10694 | const string_bytes = &astgen.string_bytes; |
| 10678 | 10695 | const str_index = @intCast(u32, string_bytes.items.len); |
| 10679 | 10696 | try astgen.appendIdentStr(ident_token, string_bytes); |
| 10680 | const key = string_bytes.items[str_index..]; | |
| 10681 | const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ | |
| 10697 | const key: []const u8 = string_bytes.items[str_index..]; | |
| 10698 | const gop = try astgen.string_table.getOrPutContextAdapted(gpa, key, StringIndexAdapter{ | |
| 10682 | 10699 | .bytes = string_bytes, |
| 10683 | 10700 | }, StringIndexContext{ |
| 10684 | 10701 | .bytes = string_bytes, |
src/Autodoc.zig+23-24| ... | ... | @@ -8,6 +8,7 @@ const CompilationModule = @import("Module.zig"); |
| 8 | 8 | const File = CompilationModule.File; |
| 9 | 9 | const Module = @import("Package.zig"); |
| 10 | 10 | const Tokenizer = std.zig.Tokenizer; |
| 11 | const InternPool = @import("InternPool.zig"); | |
| 11 | 12 | const Zir = @import("Zir.zig"); |
| 12 | 13 | const Ref = Zir.Inst.Ref; |
| 13 | 14 | const log = std.log.scoped(.autodoc); |
| ... | ... | @@ -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 | 99 | const root_src_dir = self.comp_module.main_pkg.root_src_directory; |
| 101 | 100 | const root_src_path = self.comp_module.main_pkg.root_src_path; |
| 102 | 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 | 107 | const file = self.comp_module.import_table.get(abs_root_src_path).?; // file is expected to be present in the import table |
| 109 | 108 | // Append all the types in Zir.Inst.Ref. |
| 110 | 109 | { |
| 111 | try self.types.append(self.arena, .{ | |
| 112 | .ComptimeExpr = .{ .name = "ComptimeExpr" }, | |
| 113 | }); | |
| 114 | ||
| 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) { | |
| 110 | comptime std.debug.assert(@enumToInt(InternPool.Index.first_type) == 0); | |
| 111 | var i: u32 = 0; | |
| 112 | while (i <= @enumToInt(InternPool.Index.last_type)) : (i += 1) { | |
| 113 | const ip_index = @intToEnum(InternPool.Index, i); | |
| 118 | 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 | 121 | try self.types.append( |
| 121 | 122 | self.arena, |
| 122 | switch (@intToEnum(Ref, i)) { | |
| 123 | switch (ip_index) { | |
| 123 | 124 | else => blk: { |
| 124 | 125 | // TODO: map the remaining refs to a correct type |
| 125 | 126 | // instead of just assinging "array" to them. |
| ... | ... | @@ -1040,7 +1041,7 @@ fn walkInstruction( |
| 1040 | 1041 | .ret_load => { |
| 1041 | 1042 | const un_node = data[inst_index].un_node; |
| 1042 | 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 | 1045 | // TODO: this instruction doesn't let us know trivially if there's |
| 1045 | 1046 | // branching involved or not. For now here's the strat: |
| 1046 | 1047 | // We search backwarts until `ret_ptr` for `store_node`, |
| ... | ... | @@ -2157,11 +2158,10 @@ fn walkInstruction( |
| 2157 | 2158 | const lhs_ref = blk: { |
| 2158 | 2159 | var lhs_extra = extra; |
| 2159 | 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 | 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 | 2165 | if (tags[lhs] != .field_val and |
| 2166 | 2166 | tags[lhs] != .field_ptr and |
| 2167 | 2167 | tags[lhs] != .field_type) break :blk lhs_extra.data.lhs; |
| ... | ... | @@ -2188,8 +2188,7 @@ fn walkInstruction( |
| 2188 | 2188 | // TODO: double check that we really don't need type info here |
| 2189 | 2189 | |
| 2190 | 2190 | const wr = blk: { |
| 2191 | if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) { | |
| 2192 | const lhs_inst = @enumToInt(lhs_ref) - Ref.typed_value_map.len; | |
| 2191 | if (Zir.refToIndex(lhs_ref)) |lhs_inst| { | |
| 2193 | 2192 | if (tags[lhs_inst] == .call or tags[lhs_inst] == .field_call) { |
| 2194 | 2193 | break :blk DocData.WalkResult{ |
| 2195 | 2194 | .expr = .{ |
| ... | ... | @@ -4672,16 +4671,19 @@ fn walkRef( |
| 4672 | 4671 | ref: Ref, |
| 4673 | 4672 | need_type: bool, // true when the caller needs also a typeRef for the return value |
| 4674 | 4673 | ) AutodocErrors!DocData.WalkResult { |
| 4675 | const enum_value = @enumToInt(ref); | |
| 4676 | if (enum_value <= @enumToInt(Ref.anyerror_void_error_union_type)) { | |
| 4674 | if (ref == .none) { | |
| 4675 | return .{ .expr = .{ .comptimeExpr = 0 } }; | |
| 4676 | } else if (@enumToInt(ref) <= @enumToInt(InternPool.Index.last_type)) { | |
| 4677 | 4677 | // We can just return a type that indexes into `types` with the |
| 4678 | 4678 | // enum value because in the beginning we pre-filled `types` with |
| 4679 | 4679 | // the types that are listed in `Ref`. |
| 4680 | 4680 | return DocData.WalkResult{ |
| 4681 | 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 | 4687 | switch (ref) { |
| 4686 | 4688 | else => { |
| 4687 | 4689 | panicWithContext( |
| ... | ... | @@ -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 | 87 | /// Whether to print clang argvs to stdout. |
| 88 | 88 | verbose_cc: bool, |
| 89 | 89 | verbose_air: bool, |
| 90 | verbose_intern_pool: bool, | |
| 90 | 91 | verbose_llvm_ir: ?[]const u8, |
| 91 | 92 | verbose_llvm_bc: ?[]const u8, |
| 92 | 93 | verbose_cimport: bool, |
| ... | ... | @@ -226,7 +227,7 @@ const Job = union(enum) { |
| 226 | 227 | /// Write the constant value for a Decl to the output file. |
| 227 | 228 | codegen_decl: Module.Decl.Index, |
| 228 | 229 | /// Write the machine code for a function to the output file. |
| 229 | codegen_func: *Module.Fn, | |
| 230 | codegen_func: Module.Fn.Index, | |
| 230 | 231 | /// Render the .h file snippet for the Decl. |
| 231 | 232 | emit_h_decl: Module.Decl.Index, |
| 232 | 233 | /// The Decl needs to be analyzed and possibly export itself. |
| ... | ... | @@ -593,6 +594,7 @@ pub const InitOptions = struct { |
| 593 | 594 | verbose_cc: bool = false, |
| 594 | 595 | verbose_link: bool = false, |
| 595 | 596 | verbose_air: bool = false, |
| 597 | verbose_intern_pool: bool = false, | |
| 596 | 598 | verbose_llvm_ir: ?[]const u8 = null, |
| 597 | 599 | verbose_llvm_bc: ?[]const u8 = null, |
| 598 | 600 | verbose_cimport: bool = false, |
| ... | ... | @@ -1315,9 +1317,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1315 | 1317 | .global_zir_cache = global_zir_cache, |
| 1316 | 1318 | .local_zir_cache = local_zir_cache, |
| 1317 | 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 | 1324 | break :blk module; |
| 1323 | 1325 | } else blk: { |
| ... | ... | @@ -1574,6 +1576,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1574 | 1576 | .clang_preprocessor_mode = options.clang_preprocessor_mode, |
| 1575 | 1577 | .verbose_cc = options.verbose_cc, |
| 1576 | 1578 | .verbose_air = options.verbose_air, |
| 1579 | .verbose_intern_pool = options.verbose_intern_pool, | |
| 1577 | 1580 | .verbose_llvm_ir = options.verbose_llvm_ir, |
| 1578 | 1581 | .verbose_llvm_bc = options.verbose_llvm_bc, |
| 1579 | 1582 | .verbose_cimport = options.verbose_cimport, |
| ... | ... | @@ -2026,6 +2029,13 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void |
| 2026 | 2029 | try comp.performAllTheWork(main_progress_node); |
| 2027 | 2030 | |
| 2028 | 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 | 2039 | if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { |
| 2030 | 2040 | // The `test_functions` decl has been intentionally postponed until now, |
| 2031 | 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 | 2052 | assert(decl.deletion_flag); |
| 2043 | 2053 | assert(decl.dependants.count() == 0); |
| 2044 | 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 | 2056 | } else false; |
| 2047 | 2057 | |
| 2048 | 2058 | try module.clearDecl(decl_index, null); |
| ... | ... | @@ -2523,8 +2533,7 @@ pub fn totalErrorCount(self: *Compilation) u32 { |
| 2523 | 2533 | // the previous parse success, including compile errors, but we cannot |
| 2524 | 2534 | // emit them until the file succeeds parsing. |
| 2525 | 2535 | for (module.failed_decls.keys()) |key| { |
| 2526 | const decl = module.declPtr(key); | |
| 2527 | if (decl.getFileScope().okToReportErrors()) { | |
| 2536 | if (module.declFileScope(key).okToReportErrors()) { | |
| 2528 | 2537 | total += 1; |
| 2529 | 2538 | if (module.cimport_errors.get(key)) |errors| { |
| 2530 | 2539 | total += errors.len; |
| ... | ... | @@ -2533,8 +2542,7 @@ pub fn totalErrorCount(self: *Compilation) u32 { |
| 2533 | 2542 | } |
| 2534 | 2543 | if (module.emit_h) |emit_h| { |
| 2535 | 2544 | for (emit_h.failed_decls.keys()) |key| { |
| 2536 | const decl = module.declPtr(key); | |
| 2537 | if (decl.getFileScope().okToReportErrors()) { | |
| 2545 | if (module.declFileScope(key).okToReportErrors()) { | |
| 2538 | 2546 | total += 1; |
| 2539 | 2547 | } |
| 2540 | 2548 | } |
| ... | ... | @@ -2618,7 +2626,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2618 | 2626 | var it = module.failed_files.iterator(); |
| 2619 | 2627 | while (it.next()) |entry| { |
| 2620 | 2628 | if (entry.value_ptr.*) |msg| { |
| 2621 | try addModuleErrorMsg(&bundle, msg.*); | |
| 2629 | try addModuleErrorMsg(module, &bundle, msg.*); | |
| 2622 | 2630 | } else { |
| 2623 | 2631 | // Must be ZIR errors. Note that this may include AST errors. |
| 2624 | 2632 | // addZirErrorMessages asserts that the tree is loaded. |
| ... | ... | @@ -2631,17 +2639,17 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2631 | 2639 | var it = module.failed_embed_files.iterator(); |
| 2632 | 2640 | while (it.next()) |entry| { |
| 2633 | 2641 | const msg = entry.value_ptr.*; |
| 2634 | try addModuleErrorMsg(&bundle, msg.*); | |
| 2642 | try addModuleErrorMsg(module, &bundle, msg.*); | |
| 2635 | 2643 | } |
| 2636 | 2644 | } |
| 2637 | 2645 | { |
| 2638 | 2646 | var it = module.failed_decls.iterator(); |
| 2639 | 2647 | while (it.next()) |entry| { |
| 2640 | const decl = module.declPtr(entry.key_ptr.*); | |
| 2648 | const decl_index = entry.key_ptr.*; | |
| 2641 | 2649 | // Skip errors for Decls within files that had a parse failure. |
| 2642 | 2650 | // We'll try again once parsing succeeds. |
| 2643 | if (decl.getFileScope().okToReportErrors()) { | |
| 2644 | try addModuleErrorMsg(&bundle, entry.value_ptr.*.*); | |
| 2651 | if (module.declFileScope(decl_index).okToReportErrors()) { | |
| 2652 | try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*); | |
| 2645 | 2653 | if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| { |
| 2646 | 2654 | try bundle.addRootErrorMessage(.{ |
| 2647 | 2655 | .msg = try bundle.addString(std.mem.span(c_error.msg)), |
| ... | ... | @@ -2662,16 +2670,16 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2662 | 2670 | if (module.emit_h) |emit_h| { |
| 2663 | 2671 | var it = emit_h.failed_decls.iterator(); |
| 2664 | 2672 | while (it.next()) |entry| { |
| 2665 | const decl = module.declPtr(entry.key_ptr.*); | |
| 2673 | const decl_index = entry.key_ptr.*; | |
| 2666 | 2674 | // Skip errors for Decls within files that had a parse failure. |
| 2667 | 2675 | // We'll try again once parsing succeeds. |
| 2668 | if (decl.getFileScope().okToReportErrors()) { | |
| 2669 | try addModuleErrorMsg(&bundle, entry.value_ptr.*.*); | |
| 2676 | if (module.declFileScope(decl_index).okToReportErrors()) { | |
| 2677 | try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*); | |
| 2670 | 2678 | } |
| 2671 | 2679 | } |
| 2672 | 2680 | } |
| 2673 | 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 | 2711 | const values = module.compile_log_decls.values(); |
| 2704 | 2712 | // First one will be the error; subsequent ones will be notes. |
| 2705 | 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 | 2715 | const err_msg = Module.ErrorMsg{ |
| 2708 | 2716 | .src_loc = src_loc, |
| 2709 | 2717 | .msg = "found compile log statement", |
| ... | ... | @@ -2714,12 +2722,12 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2714 | 2722 | for (keys[1..], 0..) |key, i| { |
| 2715 | 2723 | const note_decl = module.declPtr(key); |
| 2716 | 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 | 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 | 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 | 2787 | const gpa = eb.gpa; |
| 2788 | const ip = &mod.intern_pool; | |
| 2780 | 2789 | const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| { |
| 2781 | 2790 | const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa); |
| 2782 | 2791 | defer gpa.free(file_path); |
| ... | ... | @@ -2802,7 +2811,7 @@ pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) |
| 2802 | 2811 | .src_loc = .none, |
| 2803 | 2812 | }); |
| 2804 | 2813 | break; |
| 2805 | } else if (module_reference.decl == null) { | |
| 2814 | } else if (module_reference.decl == .none) { | |
| 2806 | 2815 | try ref_traces.append(gpa, .{ |
| 2807 | 2816 | .decl_name = 0, |
| 2808 | 2817 | .src_loc = .none, |
| ... | ... | @@ -2815,7 +2824,7 @@ pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) |
| 2815 | 2824 | const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa); |
| 2816 | 2825 | defer gpa.free(rt_file_path); |
| 2817 | 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 | 2828 | .src_loc = try eb.addSourceLocation(.{ |
| 2820 | 2829 | .src_path = try eb.addString(rt_file_path), |
| 2821 | 2830 | .span_start = span.start, |
| ... | ... | @@ -3204,7 +3213,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v |
| 3204 | 3213 | // Tests are always emitted in test binaries. The decl_refs are created by |
| 3205 | 3214 | // Module.populateTestFunctions, but this will not queue body analysis, so do |
| 3206 | 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 | 3220 | .update_embed_file => |embed_file| { |
| ... | ... | @@ -3228,7 +3238,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v |
| 3228 | 3238 | try module.failed_decls.ensureUnusedCapacity(gpa, 1); |
| 3229 | 3239 | module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( |
| 3230 | 3240 | gpa, |
| 3231 | decl.srcLoc(), | |
| 3241 | decl.srcLoc(module), | |
| 3232 | 3242 | "unable to update line number: {s}", |
| 3233 | 3243 | .{@errorName(err)}, |
| 3234 | 3244 | )); |
| ... | ... | @@ -3841,7 +3851,7 @@ fn reportRetryableEmbedFileError( |
| 3841 | 3851 | const mod = comp.bin_file.options.module.?; |
| 3842 | 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 | 3856 | const err_msg = if (embed_file.pkg.root_src_directory.path) |dir_path| |
| 3847 | 3857 | try Module.ErrorMsg.create( |
| ... | ... | @@ -5417,6 +5427,7 @@ fn buildOutputFromZig( |
| 5417 | 5427 | .verbose_cc = comp.verbose_cc, |
| 5418 | 5428 | .verbose_link = comp.bin_file.options.verbose_link, |
| 5419 | 5429 | .verbose_air = comp.verbose_air, |
| 5430 | .verbose_intern_pool = comp.verbose_intern_pool, | |
| 5420 | 5431 | .verbose_llvm_ir = comp.verbose_llvm_ir, |
| 5421 | 5432 | .verbose_llvm_bc = comp.verbose_llvm_bc, |
| 5422 | 5433 | .verbose_cimport = comp.verbose_cimport, |
| ... | ... | @@ -5495,6 +5506,7 @@ pub fn build_crt_file( |
| 5495 | 5506 | .verbose_cc = comp.verbose_cc, |
| 5496 | 5507 | .verbose_link = comp.bin_file.options.verbose_link, |
| 5497 | 5508 | .verbose_air = comp.verbose_air, |
| 5509 | .verbose_intern_pool = comp.verbose_intern_pool, | |
| 5498 | 5510 | .verbose_llvm_ir = comp.verbose_llvm_ir, |
| 5499 | 5511 | .verbose_llvm_bc = comp.verbose_llvm_bc, |
| 5500 | 5512 | .verbose_cimport = comp.verbose_cimport, |
src/InternPool.zig+5742-266| ... | ... | @@ -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 | 8 | map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, |
| 2 | 9 | items: std.MultiArrayList(Item) = .{}, |
| 3 | 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 | 66 | const std = @import("std"); |
| 7 | 67 | const Allocator = std.mem.Allocator; |
| 8 | 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 | 78 | const KeyAdapter = struct { |
| 11 | 79 | intern_pool: *const InternPool, |
| 12 | 80 | |
| 13 | 81 | pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool { |
| 14 | 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 | 86 | pub fn hash(ctx: @This(), a: Key) u32 { |
| 19 | _ = ctx; | |
| 20 | return a.hash(); | |
| 87 | return a.hash32(ctx.intern_pool); | |
| 21 | 88 | } |
| 22 | 89 | }; |
| 23 | 90 | |
| 24 | pub const Key = union(enum) { | |
| 25 | int_type: struct { | |
| 26 | signedness: std.builtin.Signedness, | |
| 27 | bits: u16, | |
| 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, | |
| 91 | /// An index into `maps` which might be `none`. | |
| 92 | pub const OptionalMapIndex = enum(u32) { | |
| 93 | none = std.math.maxInt(u32), | |
| 94 | _, | |
| 56 | 95 | |
| 57 | pub fn hash(key: Key) u32 { | |
| 58 | var hasher = std.hash.Wyhash.init(0); | |
| 59 | switch (key) { | |
| 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()); | |
| 96 | pub fn unwrap(oi: OptionalMapIndex) ?MapIndex { | |
| 97 | if (oi == .none) return null; | |
| 98 | return @intToEnum(MapIndex, @enumToInt(oi)); | |
| 69 | 99 | } |
| 100 | }; | |
| 70 | 101 | |
| 71 | pub fn eql(a: Key, b: Key) bool { | |
| 72 | const KeyTag = std.meta.Tag(Key); | |
| 73 | const a_tag: KeyTag = a; | |
| 74 | const b_tag: KeyTag = b; | |
| 75 | if (a_tag != b_tag) return false; | |
| 76 | switch (a) { | |
| 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 | } | |
| 102 | /// An index into `maps`. | |
| 103 | pub const MapIndex = enum(u32) { | |
| 104 | _, | |
| 105 | ||
| 106 | pub fn toOptional(i: MapIndex) OptionalMapIndex { | |
| 107 | return @intToEnum(OptionalMapIndex, @enumToInt(i)); | |
| 87 | 108 | } |
| 88 | 109 | }; |
| 89 | 110 | |
| 90 | pub const Item = struct { | |
| 91 | tag: Tag, | |
| 92 | /// The doc comments on the respective Tag explain how to interpret this. | |
| 93 | data: u32, | |
| 111 | pub const RuntimeIndex = enum(u32) { | |
| 112 | zero = 0, | |
| 113 | comptime_field_ptr = std.math.maxInt(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 | |
| 97 | /// of a `Value` within this `InternPool`. The values are typed. | |
| 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), | |
| 121 | /// An index into `string_bytes`. | |
| 122 | pub const String = enum(u32) { | |
| 103 | 123 | _, |
| 104 | 124 | }; |
| 105 | 125 | |
| 106 | pub const Tag = enum(u8) { | |
| 107 | /// An integer type. | |
| 108 | /// data is number of bits | |
| 109 | type_int_signed, | |
| 110 | /// An integer type. | |
| 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 | }; | |
| 126 | /// An index into `string_bytes`. | |
| 127 | pub const NullTerminatedString = enum(u32) { | |
| 128 | /// This is distinct from `none` - it is a valid index that represents empty string. | |
| 129 | empty = 0, | |
| 130 | _, | |
| 141 | 131 | |
| 142 | pub const Simple = enum(u32) { | |
| 143 | f16, | |
| 144 | f32, | |
| 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 | }; | |
| 132 | pub fn toString(self: NullTerminatedString) String { | |
| 133 | return @intToEnum(String, @enumToInt(self)); | |
| 134 | } | |
| 177 | 135 | |
| 178 | pub const Array = struct { | |
| 179 | len: u32, | |
| 180 | child: Index, | |
| 181 | }; | |
| 136 | pub fn toOptional(self: NullTerminatedString) OptionalNullTerminatedString { | |
| 137 | return @intToEnum(OptionalNullTerminatedString, @enumToInt(self)); | |
| 138 | } | |
| 182 | 139 | |
| 183 | pub fn deinit(ip: *InternPool, gpa: Allocator) void { | |
| 184 | ip.map.deinit(gpa); | |
| 185 | ip.items.deinit(gpa); | |
| 186 | ip.extra.deinit(gpa); | |
| 187 | } | |
| 140 | const Adapter = struct { | |
| 141 | strings: []const NullTerminatedString, | |
| 188 | 142 | |
| 189 | pub fn indexToKey(ip: InternPool, index: Index) Key { | |
| 190 | const item = ip.items.get(@enumToInt(index)); | |
| 191 | const data = item.data; | |
| 192 | return switch (item.tag) { | |
| 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) }, | |
| 143 | pub fn eql(ctx: @This(), a: NullTerminatedString, b_void: void, b_map_index: usize) bool { | |
| 144 | _ = b_void; | |
| 145 | return a == ctx.strings[b_map_index]; | |
| 146 | } | |
| 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 { | |
| 220 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | |
| 221 | const gop = try ip.map.getOrPutAdapted(gpa, key, adapter); | |
| 222 | if (gop.found_existing) { | |
| 223 | return @intToEnum(Index, gop.index); | |
| 154 | /// Compare based on integer value alone, ignoring the string contents. | |
| 155 | pub fn indexLessThan(ctx: void, a: NullTerminatedString, b: NullTerminatedString) bool { | |
| 156 | _ = ctx; | |
| 157 | return @enumToInt(a) < @enumToInt(b); | |
| 224 | 158 | } |
| 225 | switch (key) { | |
| 226 | .int_type => |int_type| { | |
| 227 | const tag: Tag = switch (int_type.signedness) { | |
| 228 | .signed => .type_int_signed, | |
| 229 | .unsigned => .type_int_unsigned, | |
| 230 | }; | |
| 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"), | |
| 159 | ||
| 160 | pub fn toUnsigned(self: NullTerminatedString, ip: *const InternPool) ?u32 { | |
| 161 | const s = ip.stringToSlice(self); | |
| 162 | if (s.len > 1 and s[0] == '0') return null; | |
| 163 | if (std.mem.indexOfScalar(u8, s, '_')) |_| return null; | |
| 164 | return std.fmt.parseUnsigned(u32, s, 10) catch null; | |
| 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 { | |
| 253 | const fields = std.meta.fields(@TypeOf(extra)); | |
| 254 | try ip.extra.ensureUnusedCapacity(gpa, fields.len); | |
| 255 | return ip.addExtraAssumeCapacity(extra); | |
| 256 | } | |
| 167 | const FormatData = struct { | |
| 168 | string: NullTerminatedString, | |
| 169 | ip: *const InternPool, | |
| 170 | }; | |
| 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 { | |
| 259 | const fields = std.meta.fields(@TypeOf(extra)); | |
| 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 | }); | |
| 185 | pub fn fmt(self: NullTerminatedString, ip: *const InternPool) std.fmt.Formatter(format) { | |
| 186 | return .{ .data = .{ .string = self, .ip = ip } }; | |
| 268 | 187 | } |
| 269 | return result; | |
| 270 | } | |
| 188 | }; | |
| 271 | 189 | |
| 272 | fn extraData(ip: InternPool, comptime T: type, index: usize) T { | |
| 273 | const fields = std.meta.fields(T); | |
| 274 | var i: usize = index; | |
| 275 | var result: T = undefined; | |
| 276 | inline for (fields) |field| { | |
| 277 | @field(result, field.name) = switch (field.type) { | |
| 278 | u32 => ip.extra.items[i], | |
| 279 | Index => @intToEnum(Index, ip.extra.items[i]), | |
| 280 | i32 => @bitCast(i32, ip.extra.items[i]), | |
| 281 | else => @compileError("bad field type"), | |
| 282 | }; | |
| 283 | i += 1; | |
| 190 | /// An index into `string_bytes` which might be `none`. | |
| 191 | pub const OptionalNullTerminatedString = enum(u32) { | |
| 192 | /// This is distinct from `none` - it is a valid index that represents empty string. | |
| 193 | empty = 0, | |
| 194 | none = std.math.maxInt(u32), | |
| 195 | _, | |
| 196 | ||
| 197 | pub fn unwrap(oi: OptionalNullTerminatedString) ?NullTerminatedString { | |
| 198 | if (oi == .none) return null; | |
| 199 | return @intToEnum(NullTerminatedString, @enumToInt(oi)); | |
| 284 | 200 | } |
| 285 | return result; | |
| 286 | } | |
| 201 | }; | |
| 287 | 202 | |
| 288 | test "basic usage" { | |
| 289 | const gpa = std.testing.allocator; | |
| 203 | pub const Key = union(enum) { | |
| 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 = .{}; | |
| 292 | defer ip.deinit(gpa); | |
| 229 | /// Typed `undefined`. This will never be `none`; untyped `undefined` is represented | |
| 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 = .{ | |
| 295 | .signedness = .signed, | |
| 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 | } }); | |
| 258 | /// A comptime function call with a memoized result. | |
| 259 | memoized_call: Key.MemoizedCall, | |
| 303 | 260 | |
| 304 | const another_i32_type = try ip.get(gpa, .{ .int_type = .{ | |
| 305 | .signedness = .signed, | |
| 306 | .bits = 32, | |
| 307 | } }); | |
| 308 | try std.testing.expect(another_i32_type == i32_type); | |
| 261 | pub const TypeValue = extern struct { | |
| 262 | ty: Index, | |
| 263 | val: Index, | |
| 264 | }; | |
| 309 | 265 | |
| 310 | const another_array_i32 = try ip.get(gpa, .{ .array_type = .{ | |
| 311 | .len = 10, | |
| 312 | .child = i32_type, | |
| 313 | .sentinel = .none, | |
| 314 | } }); | |
| 315 | try std.testing.expect(another_array_i32 == array_i32); | |
| 266 | pub const IntType = std.builtin.Type.Int; | |
| 267 | ||
| 268 | /// Extern for hashing via memory reinterpretation. | |
| 269 | pub const ErrorUnionType = extern struct { | |
| 270 | error_set_type: Index, | |
| 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 | 5 | //! Some instructions are special, such as: |
| 6 | 6 | //! * Conditional Branches |
| 7 | 7 | //! * Switch Branches |
| 8 | const Liveness = @This(); | |
| 9 | 8 | const std = @import("std"); |
| 10 | const trace = @import("tracy.zig").trace; | |
| 11 | 9 | const log = std.log.scoped(.liveness); |
| 12 | 10 | const assert = std.debug.assert; |
| 13 | 11 | const Allocator = std.mem.Allocator; |
| 14 | const Air = @import("Air.zig"); | |
| 15 | 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 | 19 | pub const Verify = @import("Liveness/Verify.zig"); |
| 18 | 20 | |
| 19 | 21 | /// This array is split into sets of 4 bits per AIR instruction. |
| ... | ... | @@ -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 | 135 | const tracy = trace(@src()); |
| 134 | 136 | defer tracy.end(); |
| 135 | 137 | |
| ... | ... | @@ -142,6 +144,7 @@ pub fn analyze(gpa: Allocator, air: Air) Allocator.Error!Liveness { |
| 142 | 144 | ), |
| 143 | 145 | .extra = .{}, |
| 144 | 146 | .special = .{}, |
| 147 | .intern_pool = intern_pool, | |
| 145 | 148 | }; |
| 146 | 149 | errdefer gpa.free(a.tomb_bits); |
| 147 | 150 | errdefer a.special.deinit(gpa); |
| ... | ... | @@ -222,6 +225,7 @@ pub fn categorizeOperand( |
| 222 | 225 | air: Air, |
| 223 | 226 | inst: Air.Inst.Index, |
| 224 | 227 | operand: Air.Inst.Index, |
| 228 | ip: *const InternPool, | |
| 225 | 229 | ) OperandCategory { |
| 226 | 230 | const air_tags = air.instructions.items(.tag); |
| 227 | 231 | const air_datas = air.instructions.items(.data); |
| ... | ... | @@ -317,9 +321,10 @@ pub fn categorizeOperand( |
| 317 | 321 | |
| 318 | 322 | .arg, |
| 319 | 323 | .alloc, |
| 324 | .inferred_alloc, | |
| 325 | .inferred_alloc_comptime, | |
| 320 | 326 | .ret_ptr, |
| 321 | .constant, | |
| 322 | .const_ty, | |
| 327 | .interned, | |
| 323 | 328 | .trap, |
| 324 | 329 | .breakpoint, |
| 325 | 330 | .dbg_stmt, |
| ... | ... | @@ -530,7 +535,7 @@ pub fn categorizeOperand( |
| 530 | 535 | .aggregate_init => { |
| 531 | 536 | const ty_pl = air_datas[inst].ty_pl; |
| 532 | 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 | 539 | const elements = @ptrCast([]const Air.Inst.Ref, air.extra[ty_pl.payload..][0..len]); |
| 535 | 540 | |
| 536 | 541 | if (elements.len <= bpi - 1) { |
| ... | ... | @@ -621,7 +626,7 @@ pub fn categorizeOperand( |
| 621 | 626 | |
| 622 | 627 | var operand_live: bool = true; |
| 623 | 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 | 630 | operand_live = false; |
| 626 | 631 | |
| 627 | 632 | switch (air_tags[cond_inst]) { |
| ... | ... | @@ -818,6 +823,7 @@ pub const BigTomb = struct { |
| 818 | 823 | const Analysis = struct { |
| 819 | 824 | gpa: Allocator, |
| 820 | 825 | air: Air, |
| 826 | intern_pool: *const InternPool, | |
| 821 | 827 | tomb_bits: []usize, |
| 822 | 828 | special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32), |
| 823 | 829 | extra: std.ArrayListUnmanaged(u32), |
| ... | ... | @@ -867,6 +873,7 @@ fn analyzeInst( |
| 867 | 873 | data: *LivenessPassData(pass), |
| 868 | 874 | inst: Air.Inst.Index, |
| 869 | 875 | ) Allocator.Error!void { |
| 876 | const ip = a.intern_pool; | |
| 870 | 877 | const inst_tags = a.air.instructions.items(.tag); |
| 871 | 878 | const inst_datas = a.air.instructions.items(.data); |
| 872 | 879 | |
| ... | ... | @@ -967,9 +974,7 @@ fn analyzeInst( |
| 967 | 974 | .work_group_id, |
| 968 | 975 | => return analyzeOperands(a, pass, data, inst, .{ .none, .none, .none }), |
| 969 | 976 | |
| 970 | .constant, | |
| 971 | .const_ty, | |
| 972 | => unreachable, | |
| 977 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 973 | 978 | |
| 974 | 979 | .trap, |
| 975 | 980 | .unreach, |
| ... | ... | @@ -1134,7 +1139,7 @@ fn analyzeInst( |
| 1134 | 1139 | .aggregate_init => { |
| 1135 | 1140 | const ty_pl = inst_datas[inst].ty_pl; |
| 1136 | 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 | 1143 | const elements = @ptrCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]); |
| 1139 | 1144 | |
| 1140 | 1145 | if (elements.len <= bpi - 1) { |
| ... | ... | @@ -1253,19 +1258,17 @@ fn analyzeOperands( |
| 1253 | 1258 | ) Allocator.Error!void { |
| 1254 | 1259 | const gpa = a.gpa; |
| 1255 | 1260 | const inst_tags = a.air.instructions.items(.tag); |
| 1261 | const ip = a.intern_pool; | |
| 1256 | 1262 | |
| 1257 | 1263 | switch (pass) { |
| 1258 | 1264 | .loop_analysis => { |
| 1259 | 1265 | _ = data.live_set.remove(inst); |
| 1260 | 1266 | |
| 1261 | 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 | 1270 | // Don't compute any liveness for constants |
| 1265 | switch (inst_tags[operand]) { | |
| 1266 | .constant, .const_ty => continue, | |
| 1267 | else => {}, | |
| 1268 | } | |
| 1271 | if (inst_tags[operand] == .interned) continue; | |
| 1269 | 1272 | |
| 1270 | 1273 | _ = try data.live_set.put(gpa, operand, {}); |
| 1271 | 1274 | } |
| ... | ... | @@ -1288,20 +1291,17 @@ fn analyzeOperands( |
| 1288 | 1291 | // If our result is unused and the instruction doesn't need to be lowered, backends will |
| 1289 | 1292 | // skip the lowering of this instruction, so we don't want to record uses of operands. |
| 1290 | 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 | 1295 | // Note that it's important we iterate over the operands backwards, so that if a dying |
| 1293 | 1296 | // operand is used multiple times we mark its last use as its death. |
| 1294 | 1297 | var i = operands.len; |
| 1295 | 1298 | while (i > 0) { |
| 1296 | 1299 | i -= 1; |
| 1297 | 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 | 1303 | // Don't compute any liveness for constants |
| 1301 | switch (inst_tags[operand]) { | |
| 1302 | .constant, .const_ty => continue, | |
| 1303 | else => {}, | |
| 1304 | } | |
| 1304 | if (inst_tags[operand] == .interned) continue; | |
| 1305 | 1305 | |
| 1306 | 1306 | const mask = @as(Bpi, 1) << @intCast(OperandInt, i); |
| 1307 | 1307 | |
| ... | ... | @@ -1407,7 +1407,7 @@ fn analyzeInstBlock( |
| 1407 | 1407 | |
| 1408 | 1408 | // If the block is noreturn, block deaths not only aren't useful, they're impossible to |
| 1409 | 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 | 1411 | // The block kills the difference in the live sets |
| 1412 | 1412 | const block_scope = data.block_scopes.get(inst).?; |
| 1413 | 1413 | const num_deaths = data.live_set.count() - block_scope.live_set.count(); |
| ... | ... | @@ -1819,6 +1819,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { |
| 1819 | 1819 | |
| 1820 | 1820 | /// Must be called with operands in reverse order. |
| 1821 | 1821 | fn feed(big: *Self, op_ref: Air.Inst.Ref) !void { |
| 1822 | const ip = big.a.intern_pool; | |
| 1822 | 1823 | // Note that after this, `operands_remaining` becomes the index of the current operand |
| 1823 | 1824 | big.operands_remaining -= 1; |
| 1824 | 1825 | |
| ... | ... | @@ -1831,15 +1832,12 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { |
| 1831 | 1832 | |
| 1832 | 1833 | // Don't compute any liveness for constants |
| 1833 | 1834 | const inst_tags = big.a.air.instructions.items(.tag); |
| 1834 | switch (inst_tags[operand]) { | |
| 1835 | .constant, .const_ty => return, | |
| 1836 | else => {}, | |
| 1837 | } | |
| 1835 | if (inst_tags[operand] == .interned) return | |
| 1838 | 1836 | |
| 1839 | 1837 | // If our result is unused and the instruction doesn't need to be lowered, backends will |
| 1840 | 1838 | // skip the lowering of this instruction, so we don't want to record uses of operands. |
| 1841 | 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 | 1842 | const extra_byte = (big.operands_remaining - (bpi - 1)) / 31; |
| 1845 | 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 | 5 | liveness: Liveness, |
| 6 | 6 | live: LiveMap = .{}, |
| 7 | 7 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, LiveMap) = .{}, |
| 8 | intern_pool: *const InternPool, | |
| 8 | 9 | |
| 9 | 10 | pub const Error = error{ LivenessInvalid, OutOfMemory }; |
| 10 | 11 | |
| ... | ... | @@ -27,10 +28,11 @@ pub fn verify(self: *Verify) Error!void { |
| 27 | 28 | const LiveMap = std.AutoHashMapUnmanaged(Air.Inst.Index, void); |
| 28 | 29 | |
| 29 | 30 | fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 31 | const ip = self.intern_pool; | |
| 30 | 32 | const tag = self.air.instructions.items(.tag); |
| 31 | 33 | const data = self.air.instructions.items(.data); |
| 32 | 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 | 36 | // This instruction will not be lowered and should be ignored. |
| 35 | 37 | continue; |
| 36 | 38 | } |
| ... | ... | @@ -39,9 +41,10 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 39 | 41 | // no operands |
| 40 | 42 | .arg, |
| 41 | 43 | .alloc, |
| 44 | .inferred_alloc, | |
| 45 | .inferred_alloc_comptime, | |
| 42 | 46 | .ret_ptr, |
| 43 | .constant, | |
| 44 | .const_ty, | |
| 47 | .interned, | |
| 45 | 48 | .breakpoint, |
| 46 | 49 | .dbg_stmt, |
| 47 | 50 | .dbg_inline_begin, |
| ... | ... | @@ -58,10 +61,10 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 58 | 61 | .work_item_id, |
| 59 | 62 | .work_group_size, |
| 60 | 63 | .work_group_id, |
| 61 | => try self.verifyInst(inst, .{ .none, .none, .none }), | |
| 64 | => try self.verifyInstOperands(inst, .{ .none, .none, .none }), | |
| 62 | 65 | |
| 63 | 66 | .trap, .unreach => { |
| 64 | try self.verifyInst(inst, .{ .none, .none, .none }); | |
| 67 | try self.verifyInstOperands(inst, .{ .none, .none, .none }); | |
| 65 | 68 | // This instruction terminates the function, so everything should be dead |
| 66 | 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 | 113 | .c_va_copy, |
| 111 | 114 | => { |
| 112 | 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 | 118 | .is_null, |
| 116 | 119 | .is_non_null, |
| ... | ... | @@ -146,13 +149,13 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 146 | 149 | .c_va_end, |
| 147 | 150 | => { |
| 148 | 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 | 154 | .ret, |
| 152 | 155 | .ret_load, |
| 153 | 156 | => { |
| 154 | 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 | 159 | // This instruction terminates the function, so everything should be dead |
| 157 | 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 | 164 | .wasm_memory_grow, |
| 162 | 165 | => { |
| 163 | 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 | 169 | .prefetch => { |
| 167 | 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 | 173 | .reduce, |
| 171 | 174 | .reduce_optimized, |
| 172 | 175 | => { |
| 173 | 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 | 179 | .union_init => { |
| 177 | 180 | const ty_pl = data[inst].ty_pl; |
| 178 | 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 | 184 | .struct_field_ptr, .struct_field_val => { |
| 182 | 185 | const ty_pl = data[inst].ty_pl; |
| 183 | 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 | 189 | .field_parent_ptr => { |
| 187 | 190 | const ty_pl = data[inst].ty_pl; |
| 188 | 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 | 194 | .atomic_load => { |
| 192 | 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 | 199 | // binary |
| ... | ... | @@ -260,7 +263,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 260 | 263 | .memcpy, |
| 261 | 264 | => { |
| 262 | 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 | 268 | .add_with_overflow, |
| 266 | 269 | .sub_with_overflow, |
| ... | ... | @@ -274,62 +277,62 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 274 | 277 | => { |
| 275 | 278 | const ty_pl = data[inst].ty_pl; |
| 276 | 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 | 282 | .shuffle => { |
| 280 | 283 | const ty_pl = data[inst].ty_pl; |
| 281 | 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 | 287 | .cmp_vector, |
| 285 | 288 | .cmp_vector_optimized, |
| 286 | 289 | => { |
| 287 | 290 | const ty_pl = data[inst].ty_pl; |
| 288 | 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 | 294 | .atomic_rmw => { |
| 292 | 295 | const pl_op = data[inst].pl_op; |
| 293 | 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 | 300 | // ternary |
| 298 | 301 | .select => { |
| 299 | 302 | const pl_op = data[inst].pl_op; |
| 300 | 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 | 306 | .mul_add => { |
| 304 | 307 | const pl_op = data[inst].pl_op; |
| 305 | 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 | 311 | .vector_store_elem => { |
| 309 | 312 | const vector_store_elem = data[inst].vector_store_elem; |
| 310 | 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 | 316 | .cmpxchg_strong, |
| 314 | 317 | .cmpxchg_weak, |
| 315 | 318 | => { |
| 316 | 319 | const ty_pl = data[inst].ty_pl; |
| 317 | 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 | 324 | // big tombs |
| 322 | 325 | .aggregate_init => { |
| 323 | 326 | const ty_pl = data[inst].ty_pl; |
| 324 | 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 | 329 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 327 | 330 | |
| 328 | 331 | var bt = self.liveness.iterateBigTomb(inst); |
| 329 | 332 | for (elements) |element| { |
| 330 | 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 | 337 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { |
| 335 | 338 | const pl_op = data[inst].pl_op; |
| ... | ... | @@ -344,7 +347,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 344 | 347 | for (args) |arg| { |
| 345 | 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 | 352 | .assembly => { |
| 350 | 353 | const ty_pl = data[inst].ty_pl; |
| ... | ... | @@ -370,7 +373,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 370 | 373 | for (inputs) |input| { |
| 371 | 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 | 379 | // control flow |
| ... | ... | @@ -394,7 +397,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 394 | 397 | |
| 395 | 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 | 402 | .try_ptr => { |
| 400 | 403 | const ty_pl = data[inst].ty_pl; |
| ... | ... | @@ -416,7 +419,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 416 | 419 | |
| 417 | 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 | 424 | .br => { |
| 422 | 425 | const br = data[inst].br; |
| ... | ... | @@ -428,7 +431,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 428 | 431 | } else { |
| 429 | 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 | 436 | .block => { |
| 434 | 437 | const ty_pl = data[inst].ty_pl; |
| ... | ... | @@ -450,7 +453,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 450 | 453 | |
| 451 | 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 | 457 | assert(!self.blocks.contains(inst)); |
| 455 | 458 | } else { |
| 456 | 459 | var live = self.blocks.fetchRemove(inst).?.value; |
| ... | ... | @@ -459,7 +462,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 459 | 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 | 467 | .loop => { |
| 465 | 468 | const ty_pl = data[inst].ty_pl; |
| ... | ... | @@ -474,7 +477,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 474 | 477 | // The same stuff should be alive after the loop as before it |
| 475 | 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 | 482 | .cond_br => { |
| 480 | 483 | const pl_op = data[inst].pl_op; |
| ... | ... | @@ -497,7 +500,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 497 | 500 | for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death); |
| 498 | 501 | try self.verifyBody(else_body); |
| 499 | 502 | |
| 500 | try self.verifyInst(inst, .{ .none, .none, .none }); | |
| 503 | try self.verifyInst(inst); | |
| 501 | 504 | }, |
| 502 | 505 | .switch_br => { |
| 503 | 506 | const pl_op = data[inst].pl_op; |
| ... | ... | @@ -541,7 +544,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 541 | 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 | 555 | } |
| 553 | 556 | |
| 554 | 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; | |
| 556 | switch (self.air.instructions.items(.tag)[operand]) { | |
| 557 | .constant, .const_ty => {}, | |
| 558 | else => { | |
| 559 | if (dies) { | |
| 560 | if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand }); | |
| 561 | } else { | |
| 562 | if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand }); | |
| 563 | } | |
| 564 | }, | |
| 558 | const operand = Air.refToIndexAllowNone(op_ref) orelse { | |
| 559 | assert(!dies); | |
| 560 | return; | |
| 561 | }; | |
| 562 | if (self.air.instructions.items(.tag)[operand] == .interned) { | |
| 563 | assert(!dies); | |
| 564 | return; | |
| 565 | } | |
| 566 | if (dies) { | |
| 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 | 574 | self: *Verify, |
| 570 | 575 | inst: Air.Inst.Index, |
| 571 | 576 | operands: [Liveness.bpi - 1]Air.Inst.Ref, |
| ... | ... | @@ -574,16 +579,15 @@ fn verifyInst( |
| 574 | 579 | const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index)); |
| 575 | 580 | try self.verifyOperand(inst, operand, dies); |
| 576 | 581 | } |
| 577 | const tag = self.air.instructions.items(.tag); | |
| 578 | switch (tag[inst]) { | |
| 579 | .constant, .const_ty => unreachable, | |
| 580 | else => { | |
| 581 | if (self.liveness.isUnused(inst)) { | |
| 582 | assert(!self.live.contains(inst)); | |
| 583 | } else { | |
| 584 | try self.live.putNoClobber(self.gpa, inst, {}); | |
| 585 | } | |
| 586 | }, | |
| 582 | try self.verifyInst(inst); | |
| 583 | } | |
| 584 | ||
| 585 | fn verifyInst(self: *Verify, inst: Air.Inst.Index) Error!void { | |
| 586 | if (self.air.instructions.items(.tag)[inst] == .interned) return; | |
| 587 | if (self.liveness.isUnused(inst)) { | |
| 588 | assert(!self.live.contains(inst)); | |
| 589 | } else { | |
| 590 | try self.live.putNoClobber(self.gpa, inst, {}); | |
| 587 | 591 | } |
| 588 | 592 | } |
| 589 | 593 | |
| ... | ... | @@ -604,4 +608,5 @@ const log = std.log.scoped(.liveness_verify); |
| 604 | 608 | |
| 605 | 609 | const Air = @import("../Air.zig"); |
| 606 | 610 | const Liveness = @import("../Liveness.zig"); |
| 611 | const InternPool = @import("../InternPool.zig"); | |
| 607 | 612 | const Verify = @This(); |
src/Module.zig+1440-1086| ... | ... | @@ -32,6 +32,19 @@ const build_options = @import("build_options"); |
| 32 | 32 | const Liveness = @import("Liveness.zig"); |
| 33 | 33 | const isUpDir = @import("introspect.zig").isUpDir; |
| 34 | 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 | 49 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 37 | 50 | gpa: Allocator, |
| ... | ... | @@ -72,28 +85,29 @@ import_table: std.StringArrayHashMapUnmanaged(*File) = .{}, |
| 72 | 85 | /// Keys are fully resolved file paths. This table owns the keys and values. |
| 73 | 86 | embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{}, |
| 74 | 87 | |
| 75 | /// This is a temporary addition to stage2 in order to match legacy behavior, | |
| 76 | /// however the end-game once the lang spec is settled will be to use a global | |
| 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) = .{}, | |
| 88 | /// Stores all Type and Value objects; periodically garbage collected. | |
| 89 | intern_pool: InternPool = .{}, | |
| 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 | 103 | /// The set of all the generic function instantiations. This is used so that when a generic |
| 87 | 104 | /// function is called twice with the same comptime parameter arguments, both calls dispatch |
| 88 | 105 | /// to the same function. |
| 89 | 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 | 107 | /// Contains the values from `@setAlignStack`. A sparse table is used here |
| 94 | 108 | /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while |
| 95 | 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 | 112 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| 99 | 113 | /// error messages and mapping outside of `Decl`. |
| ... | ... | @@ -120,13 +134,8 @@ cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, []CImportError) = .{}, |
| 120 | 134 | /// contains Decls that need to be deleted if they end up having no references to them. |
| 121 | 135 | deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, |
| 122 | 136 | |
| 123 | /// Error tags and their values, tag names are duped with mod.gpa. | |
| 124 | /// Corresponds with `error_name_list`. | |
| 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), | |
| 137 | /// Key is the error name, index is the error tag value. Index 0 has a length-0 string. | |
| 138 | global_error_set: GlobalErrorSet = .{}, | |
| 130 | 139 | |
| 131 | 140 | /// Incrementing integer used to compare against the corresponding Decl |
| 132 | 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 | 174 | /// When a Decl object is freed from `allocated_decls`, it is pushed into this stack. |
| 166 | 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 | 182 | global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{}, |
| 169 | 183 | |
| 170 | 184 | reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { |
| ... | ... | @@ -172,6 +186,8 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { |
| 172 | 186 | src: LazySrcLoc, |
| 173 | 187 | }) = .{}, |
| 174 | 188 | |
| 189 | pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); | |
| 190 | ||
| 175 | 191 | pub const CImportError = struct { |
| 176 | 192 | offset: u32, |
| 177 | 193 | line: u32, |
| ... | ... | @@ -187,108 +203,40 @@ pub const CImportError = struct { |
| 187 | 203 | } |
| 188 | 204 | }; |
| 189 | 205 | |
| 190 | pub const StringLiteralContext = struct { | |
| 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), | |
| 206 | pub const MonomorphedFuncKey = struct { func: Fn.Index, args_index: u32, args_len: u32 }; | |
| 211 | 207 | |
| 212 | pub fn eql(self: @This(), a_slice: []const u8, b: StringLiteralContext.Key) bool { | |
| 213 | const b_slice = self.bytes.items[b.index..][0..b.len]; | |
| 214 | return mem.eql(u8, a_slice, b_slice); | |
| 215 | } | |
| 208 | pub const MonomorphedFuncAdaptedKey = struct { func: Fn.Index, args: []const InternPool.Index }; | |
| 216 | 209 | |
| 217 | pub fn hash(self: @This(), adapted_key: []const u8) u64 { | |
| 218 | _ = self; | |
| 219 | return std.hash_map.hashString(adapted_key); | |
| 220 | } | |
| 221 | }; | |
| 222 | ||
| 223 | const MonomorphedFuncsSet = std.HashMapUnmanaged( | |
| 224 | *Fn, | |
| 225 | void, | |
| 210 | pub const MonomorphedFuncsSet = std.HashMapUnmanaged( | |
| 211 | MonomorphedFuncKey, | |
| 212 | InternPool.Index, | |
| 226 | 213 | MonomorphedFuncsContext, |
| 227 | 214 | std.hash_map.default_max_load_percentage, |
| 228 | 215 | ); |
| 229 | 216 | |
| 230 | const MonomorphedFuncsContext = struct { | |
| 231 | pub fn eql(ctx: @This(), a: *Fn, b: *Fn) bool { | |
| 232 | _ = ctx; | |
| 233 | return a == b; | |
| 217 | pub const MonomorphedFuncsContext = struct { | |
| 218 | mod: *Module, | |
| 219 | ||
| 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`. | |
| 237 | pub fn hash(ctx: @This(), key: *Fn) u64 { | |
| 238 | _ = ctx; | |
| 239 | return key.hash; | |
| 224 | pub fn hash(ctx: @This(), key: MonomorphedFuncKey) u64 { | |
| 225 | const key_args = ctx.mod.monomorphed_func_keys.items[key.args_index..][0..key.args_len]; | |
| 226 | return std.hash.Wyhash.hash(@enumToInt(key.func), std.mem.sliceAsBytes(key_args)); | |
| 240 | 227 | } |
| 241 | 228 | }; |
| 242 | 229 | |
| 243 | pub const MemoizedCallSet = std.HashMapUnmanaged( | |
| 244 | MemoizedCall.Key, | |
| 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 | } | |
| 230 | pub const MonomorphedFuncsAdaptedContext = struct { | |
| 231 | mod: *Module, | |
| 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`. | |
| 278 | pub fn hash(ctx: @This(), key: Key) u64 { | |
| 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(); | |
| 238 | pub fn hash(_: @This(), adapted_key: MonomorphedFuncAdaptedKey) u64 { | |
| 239 | return std.hash.Wyhash.hash(@enumToInt(adapted_key.func), std.mem.sliceAsBytes(adapted_key.args)); | |
| 292 | 240 | } |
| 293 | 241 | }; |
| 294 | 242 | |
| ... | ... | @@ -322,7 +270,7 @@ pub const GlobalEmitH = struct { |
| 322 | 270 | pub const ErrorInt = u32; |
| 323 | 271 | |
| 324 | 272 | pub const Export = struct { |
| 325 | options: std.builtin.ExportOptions, | |
| 273 | opts: Options, | |
| 326 | 274 | src: LazySrcLoc, |
| 327 | 275 | /// The Decl that performs the export. Note that this is *not* the Decl being exported. |
| 328 | 276 | owner_decl: Decl.Index, |
| ... | ... | @@ -340,10 +288,17 @@ pub const Export = struct { |
| 340 | 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 | 298 | pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc { |
| 344 | 299 | const src_decl = mod.declPtr(exp.src_decl); |
| 345 | 300 | return .{ |
| 346 | .file_scope = src_decl.getFileScope(), | |
| 301 | .file_scope = src_decl.getFileScope(mod), | |
| 347 | 302 | .parent_decl_node = src_decl.src_node, |
| 348 | 303 | .lazy = exp.src, |
| 349 | 304 | }; |
| ... | ... | @@ -351,61 +306,76 @@ pub const Export = struct { |
| 351 | 306 | }; |
| 352 | 307 | |
| 353 | 308 | pub const CaptureScope = struct { |
| 309 | refs: u32, | |
| 354 | 310 | parent: ?*CaptureScope, |
| 355 | 311 | |
| 356 | 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. | |
| 358 | /// During sema, this map is backed by the gpa. Once sema completes, | |
| 359 | /// it is reallocated using the value_arena. | |
| 360 | captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, TypedValue) = .{}, | |
| 313 | /// child decls. This map is backed by the gpa, and deinited when | |
| 314 | /// the refcount reaches 0. | |
| 315 | captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Capture) = .{}, | |
| 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 | 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 | 328 | self.captures.available = 0; |
| 368 | 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 | 347 | pub const WipCaptureScope = struct { |
| 373 | 348 | scope: *CaptureScope, |
| 374 | 349 | finalized: bool, |
| 375 | 350 | gpa: Allocator, |
| 376 | perm_arena: Allocator, | |
| 377 | 351 | |
| 378 | pub fn init(gpa: Allocator, perm_arena: Allocator, parent: ?*CaptureScope) !@This() { | |
| 379 | const scope = try perm_arena.create(CaptureScope); | |
| 380 | scope.* = .{ .parent = parent }; | |
| 381 | return @This(){ | |
| 352 | pub fn init(gpa: Allocator, parent: ?*CaptureScope) !WipCaptureScope { | |
| 353 | const scope = try gpa.create(CaptureScope); | |
| 354 | if (parent) |p| p.incRef(); | |
| 355 | scope.* = .{ .refs = 1, .parent = parent }; | |
| 356 | return .{ | |
| 382 | 357 | .scope = scope, |
| 383 | 358 | .finalized = false, |
| 384 | 359 | .gpa = gpa, |
| 385 | .perm_arena = perm_arena, | |
| 386 | 360 | }; |
| 387 | 361 | } |
| 388 | 362 | |
| 389 | pub fn finalize(noalias self: *@This()) !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; | |
| 363 | pub fn finalize(noalias self: *WipCaptureScope) !void { | |
| 395 | 364 | self.finalized = true; |
| 396 | 365 | } |
| 397 | 366 | |
| 398 | pub fn reset(noalias self: *@This(), parent: ?*CaptureScope) !void { | |
| 399 | if (!self.finalized) try self.finalize(); | |
| 400 | self.scope = try self.perm_arena.create(CaptureScope); | |
| 401 | self.scope.* = .{ .parent = parent }; | |
| 402 | self.finalized = false; | |
| 367 | pub fn reset(noalias self: *WipCaptureScope, parent: ?*CaptureScope) !void { | |
| 368 | self.scope.decRef(self.gpa); | |
| 369 | self.scope = try self.gpa.create(CaptureScope); | |
| 370 | if (parent) |p| p.incRef(); | |
| 371 | self.scope.* = .{ .refs = 1, .parent = parent }; | |
| 403 | 372 | } |
| 404 | 373 | |
| 405 | pub fn deinit(noalias self: *@This()) void { | |
| 406 | if (!self.finalized) { | |
| 407 | self.scope.captures.deinit(self.gpa); | |
| 408 | self.scope.fail(); | |
| 374 | pub fn deinit(noalias self: *WipCaptureScope) void { | |
| 375 | if (self.finalized) { | |
| 376 | self.scope.decRef(self.gpa); | |
| 377 | } else { | |
| 378 | self.scope.fail(self.gpa); | |
| 409 | 379 | } |
| 410 | 380 | self.* = undefined; |
| 411 | 381 | } |
| ... | ... | @@ -452,8 +422,7 @@ const ValueArena = struct { |
| 452 | 422 | }; |
| 453 | 423 | |
| 454 | 424 | pub const Decl = struct { |
| 455 | /// Allocated with Module's allocator; outlives the ZIR code. | |
| 456 | name: [*:0]const u8, | |
| 425 | name: InternPool.NullTerminatedString, | |
| 457 | 426 | /// The most recent Type of the Decl after a successful semantic analysis. |
| 458 | 427 | /// Populated when `has_tv`. |
| 459 | 428 | ty: Type, |
| ... | ... | @@ -461,20 +430,16 @@ pub const Decl = struct { |
| 461 | 430 | /// Populated when `has_tv`. |
| 462 | 431 | val: Value, |
| 463 | 432 | /// Populated when `has_tv`. |
| 464 | /// Points to memory inside value_arena. | |
| 465 | @"linksection": ?[*:0]const u8, | |
| 433 | @"linksection": InternPool.OptionalNullTerminatedString, | |
| 466 | 434 | /// Populated when `has_tv`. |
| 467 | 435 | @"align": u32, |
| 468 | 436 | /// Populated when `has_tv`. |
| 469 | 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 | 438 | /// The direct parent namespace of the Decl. |
| 474 | 439 | /// Reference to externally owned memory. |
| 475 | 440 | /// In the case of the Decl corresponding to a file, this is |
| 476 | 441 | /// the namespace of the struct, since there is no parent. |
| 477 | src_namespace: *Namespace, | |
| 442 | src_namespace: Namespace.Index, | |
| 478 | 443 | |
| 479 | 444 | /// The scope which lexically contains this decl. A decl must depend |
| 480 | 445 | /// on its lexical parent, in order to ensure that this pointer is valid. |
| ... | ... | @@ -624,55 +589,17 @@ pub const Decl = struct { |
| 624 | 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 | 592 | pub fn clearValues(decl: *Decl, mod: *Module) void { |
| 633 | const gpa = mod.gpa; | |
| 634 | if (decl.getExternFn()) |extern_fn| { | |
| 635 | extern_fn.deinit(gpa); | |
| 636 | gpa.destroy(extern_fn); | |
| 637 | } | |
| 638 | if (decl.getFunction()) |func| { | |
| 593 | if (decl.getOwnedFunctionIndex(mod).unwrap()) |func| { | |
| 639 | 594 | _ = mod.align_stack_fns.remove(func); |
| 640 | if (func.comptime_args != null) { | |
| 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; | |
| 595 | mod.destroyFunc(func); | |
| 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 | 599 | /// This name is relative to the containing namespace of the decl. |
| 673 | 600 | /// The memory is owned by the containing File ZIR. |
| 674 | pub fn getName(decl: Decl) ?[:0]const u8 { | |
| 675 | const zir = decl.getFileScope().zir; | |
| 601 | pub fn getName(decl: Decl, mod: *Module) ?[:0]const u8 { | |
| 602 | const zir = decl.getFileScope(mod).zir; | |
| 676 | 603 | return decl.getNameZir(zir); |
| 677 | 604 | } |
| 678 | 605 | |
| ... | ... | @@ -683,8 +610,8 @@ pub const Decl = struct { |
| 683 | 610 | return zir.nullTerminatedString(name_index); |
| 684 | 611 | } |
| 685 | 612 | |
| 686 | pub fn contentsHash(decl: Decl) std.zig.SrcHash { | |
| 687 | const zir = decl.getFileScope().zir; | |
| 613 | pub fn contentsHash(decl: Decl, mod: *Module) std.zig.SrcHash { | |
| 614 | const zir = decl.getFileScope(mod).zir; | |
| 688 | 615 | return decl.contentsHashZir(zir); |
| 689 | 616 | } |
| 690 | 617 | |
| ... | ... | @@ -695,31 +622,31 @@ pub const Decl = struct { |
| 695 | 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 | 626 | assert(decl.zir_decl_index != 0); |
| 700 | const zir = decl.getFileScope().zir; | |
| 627 | const zir = decl.getFileScope(mod).zir; | |
| 701 | 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 | 632 | if (!decl.has_align) return .none; |
| 706 | 633 | assert(decl.zir_decl_index != 0); |
| 707 | const zir = decl.getFileScope().zir; | |
| 634 | const zir = decl.getFileScope(mod).zir; | |
| 708 | 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 | 639 | if (!decl.has_linksection_or_addrspace) return .none; |
| 713 | 640 | assert(decl.zir_decl_index != 0); |
| 714 | const zir = decl.getFileScope().zir; | |
| 641 | const zir = decl.getFileScope(mod).zir; | |
| 715 | 642 | const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align); |
| 716 | 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 | 647 | if (!decl.has_linksection_or_addrspace) return .none; |
| 721 | 648 | assert(decl.zir_decl_index != 0); |
| 722 | const zir = decl.getFileScope().zir; | |
| 649 | const zir = decl.getFileScope(mod).zir; | |
| 723 | 650 | const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align) + 1; |
| 724 | 651 | return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); |
| 725 | 652 | } |
| ... | ... | @@ -744,154 +671,167 @@ pub const Decl = struct { |
| 744 | 671 | return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index)); |
| 745 | 672 | } |
| 746 | 673 | |
| 747 | pub fn srcLoc(decl: Decl) SrcLoc { | |
| 748 | return decl.nodeOffsetSrcLoc(0); | |
| 674 | pub fn srcLoc(decl: Decl, mod: *Module) SrcLoc { | |
| 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 | 679 | return .{ |
| 753 | .file_scope = decl.getFileScope(), | |
| 680 | .file_scope = decl.getFileScope(mod), | |
| 754 | 681 | .parent_decl_node = decl.src_node, |
| 755 | 682 | .lazy = LazySrcLoc.nodeOffset(node_offset), |
| 756 | 683 | }; |
| 757 | 684 | } |
| 758 | 685 | |
| 759 | pub fn srcToken(decl: Decl) Ast.TokenIndex { | |
| 760 | const tree = &decl.getFileScope().tree; | |
| 686 | pub fn srcToken(decl: Decl, mod: *Module) Ast.TokenIndex { | |
| 687 | const tree = &decl.getFileScope(mod).tree; | |
| 761 | 688 | return tree.firstToken(decl.src_node); |
| 762 | 689 | } |
| 763 | 690 | |
| 764 | pub fn srcByteOffset(decl: Decl) u32 { | |
| 765 | const tree = &decl.getFileScope().tree; | |
| 691 | pub fn srcByteOffset(decl: Decl, mod: *Module) u32 { | |
| 692 | const tree = &decl.getFileScope(mod).tree; | |
| 766 | 693 | return tree.tokens.items(.start)[decl.srcToken()]; |
| 767 | 694 | } |
| 768 | 695 | |
| 769 | 696 | pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void { |
| 770 | const unqualified_name = mem.sliceTo(decl.name, 0); | |
| 771 | 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 | 704 | pub fn renderFullyQualifiedDebugName(decl: Decl, mod: *Module, writer: anytype) !void { |
| 778 | const unqualified_name = mem.sliceTo(decl.name, 0); | |
| 779 | return decl.src_namespace.renderFullyQualifiedDebugName(mod, unqualified_name, writer); | |
| 705 | return mod.namespacePtr(decl.src_namespace).renderFullyQualifiedDebugName(mod, decl.name, writer); | |
| 780 | 706 | } |
| 781 | 707 | |
| 782 | pub fn getFullyQualifiedName(decl: Decl, mod: *Module) ![:0]u8 { | |
| 783 | var buffer = std.ArrayList(u8).init(mod.gpa); | |
| 784 | defer buffer.deinit(); | |
| 785 | try decl.renderFullyQualifiedName(mod, buffer.writer()); | |
| 708 | pub fn getFullyQualifiedName(decl: Decl, mod: *Module) !InternPool.NullTerminatedString { | |
| 709 | if (decl.name_fully_qualified) return decl.name; | |
| 710 | ||
| 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 | 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 | 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 | 738 | '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', |
| 791 | 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 | 746 | pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { |
| 799 | 747 | if (!decl.has_tv) return error.AnalysisFail; |
| 800 | return TypedValue{ | |
| 801 | .ty = decl.ty, | |
| 802 | .val = decl.val, | |
| 803 | }; | |
| 748 | return TypedValue{ .ty = decl.ty, .val = decl.val }; | |
| 804 | 749 | } |
| 805 | 750 | |
| 806 | pub fn value(decl: *Decl) error{AnalysisFail}!Value { | |
| 807 | return (try decl.typedValue()).val; | |
| 751 | pub fn internValue(decl: *Decl, mod: *Module) Allocator.Error!InternPool.Index { | |
| 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 | 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 | 764 | /// otherwise null. |
| 817 | pub fn getStruct(decl: *Decl) ?*Struct { | |
| 818 | if (!decl.owns_tv) return null; | |
| 819 | const ty = (decl.val.castTag(.ty) orelse return null).data; | |
| 820 | const struct_obj = (ty.castTag(.@"struct") orelse return null).data; | |
| 821 | return struct_obj; | |
| 765 | pub fn getOwnedStruct(decl: Decl, mod: *Module) ?*Struct { | |
| 766 | return mod.structPtrUnwrap(decl.getOwnedStructIndex(mod)); | |
| 767 | } | |
| 768 | ||
| 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 | 776 | /// otherwise null. |
| 826 | pub fn getUnion(decl: *Decl) ?*Union { | |
| 777 | pub fn getOwnedUnion(decl: Decl, mod: *Module) ?*Union { | |
| 827 | 778 | if (!decl.owns_tv) return null; |
| 828 | const ty = (decl.val.castTag(.ty) orelse return null).data; | |
| 829 | const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data; | |
| 830 | return union_obj; | |
| 779 | if (decl.val.ip_index == .none) return null; | |
| 780 | return mod.typeToUnion(decl.val.toType()); | |
| 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 | 784 | /// otherwise null. |
| 835 | pub fn getFunction(decl: *const Decl) ?*Fn { | |
| 836 | if (!decl.owns_tv) return null; | |
| 837 | const func = (decl.val.castTag(.function) orelse return null).data; | |
| 838 | return func; | |
| 785 | pub fn getOwnedFunction(decl: Decl, mod: *Module) ?*Fn { | |
| 786 | return mod.funcPtrUnwrap(decl.getOwnedFunctionIndex(mod)); | |
| 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 | 794 | /// otherwise null. |
| 843 | pub fn getExternFn(decl: *const Decl) ?*ExternFn { | |
| 844 | if (!decl.owns_tv) return null; | |
| 845 | const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data; | |
| 846 | return extern_fn; | |
| 795 | pub fn getOwnedExternFunc(decl: Decl, mod: *Module) ?InternPool.Key.ExternFunc { | |
| 796 | return if (decl.owns_tv) decl.val.getExternFunc(mod) else null; | |
| 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 | 800 | /// otherwise null. |
| 851 | pub fn getVariable(decl: *const Decl) ?*Var { | |
| 852 | if (!decl.owns_tv) return null; | |
| 853 | const variable = (decl.val.castTag(.variable) orelse return null).data; | |
| 854 | return variable; | |
| 801 | pub fn getOwnedVariable(decl: Decl, mod: *Module) ?InternPool.Key.Variable { | |
| 802 | return if (decl.owns_tv) decl.val.getVariable(mod) else null; | |
| 855 | 803 | } |
| 856 | 804 | |
| 857 | 805 | /// Gets the namespace that this Decl creates by being a struct, union, |
| 858 | 806 | /// enum, or opaque. |
| 859 | 807 | /// Only returns it if the Decl is the owner. |
| 860 | pub fn getInnerNamespace(decl: *Decl) ?*Namespace { | |
| 861 | if (!decl.owns_tv) return null; | |
| 862 | const ty = (decl.val.castTag(.ty) orelse return null).data; | |
| 863 | switch (ty.tag()) { | |
| 864 | .@"struct" => { | |
| 865 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 866 | return &struct_obj.namespace; | |
| 867 | }, | |
| 868 | .enum_full, .enum_nonexhaustive => { | |
| 869 | const enum_obj = ty.cast(Type.Payload.EnumFull).?.data; | |
| 870 | return &enum_obj.namespace; | |
| 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; | |
| 808 | pub fn getOwnedInnerNamespaceIndex(decl: Decl, mod: *Module) Namespace.OptionalIndex { | |
| 809 | if (!decl.owns_tv) return .none; | |
| 810 | return switch (decl.val.ip_index) { | |
| 811 | .empty_struct_type => .none, | |
| 812 | .none => .none, | |
| 813 | else => switch (mod.intern_pool.indexToKey(decl.val.toIntern())) { | |
| 814 | .opaque_type => |opaque_type| opaque_type.namespace.toOptional(), | |
| 815 | .struct_type => |struct_type| struct_type.namespace, | |
| 816 | .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(), | |
| 817 | .enum_type => |enum_type| enum_type.namespace, | |
| 818 | else => .none, | |
| 882 | 819 | }, |
| 820 | }; | |
| 821 | } | |
| 883 | 822 | |
| 884 | else => return null, | |
| 885 | } | |
| 823 | /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer. | |
| 824 | pub fn getOwnedInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { | |
| 825 | return mod.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(mod)); | |
| 886 | 826 | } |
| 887 | 827 | |
| 888 | 828 | pub fn dump(decl: *Decl) void { |
| 889 | 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 | 831 | decl.scope.sub_file_path, |
| 892 | 832 | loc.line + 1, |
| 893 | 833 | loc.column + 1, |
| 894 | mem.sliceTo(decl.name, 0), | |
| 834 | @enumToInt(decl.name), | |
| 895 | 835 | @tagName(decl.analysis), |
| 896 | 836 | }); |
| 897 | 837 | if (decl.has_tv) { |
| ... | ... | @@ -900,8 +840,8 @@ pub const Decl = struct { |
| 900 | 840 | std.debug.print("\n", .{}); |
| 901 | 841 | } |
| 902 | 842 | |
| 903 | pub fn getFileScope(decl: Decl) *File { | |
| 904 | return decl.src_namespace.file_scope; | |
| 843 | pub fn getFileScope(decl: Decl, mod: *Module) *File { | |
| 844 | return mod.namespacePtr(decl.src_namespace).file_scope; | |
| 905 | 845 | } |
| 906 | 846 | |
| 907 | 847 | pub fn removeDependant(decl: *Decl, other: Decl.Index) void { |
| ... | ... | @@ -912,25 +852,29 @@ pub const Decl = struct { |
| 912 | 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 | 856 | assert(decl.has_tv); |
| 917 | return switch (decl.val.tag()) { | |
| 918 | .extern_fn => true, | |
| 919 | .variable => decl.val.castTag(.variable).?.data.init.tag() == .unreachable_value, | |
| 857 | return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) { | |
| 858 | .variable => |variable| variable.is_extern, | |
| 859 | .extern_func => true, | |
| 920 | 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 | 865 | assert(decl.has_tv); |
| 926 | 866 | if (decl.@"align" != 0) { |
| 927 | 867 | // Explicit alignment. |
| 928 | 868 | return decl.@"align"; |
| 929 | 869 | } else { |
| 930 | 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 | 880 | /// This state is attached to every Decl when Module emit_h is non-null. |
| ... | ... | @@ -938,38 +882,6 @@ pub const EmitH = struct { |
| 938 | 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 | 885 | pub const PropertyBoolean = enum { no, yes, unknown, wip }; |
| 974 | 886 | |
| 975 | 887 | /// Represents the data that a struct declaration provides. |
| ... | ... | @@ -977,7 +889,7 @@ pub const Struct = struct { |
| 977 | 889 | /// Set of field names in declaration order. |
| 978 | 890 | fields: Fields, |
| 979 | 891 | /// Represents the declarations inside this struct. |
| 980 | namespace: Namespace, | |
| 892 | namespace: Namespace.Index, | |
| 981 | 893 | /// The Decl that corresponds to the struct itself. |
| 982 | 894 | owner_decl: Decl.Index, |
| 983 | 895 | /// Index of the struct_decl ZIR instruction. |
| ... | ... | @@ -989,7 +901,7 @@ pub const Struct = struct { |
| 989 | 901 | /// If the layout is packed, this is the backing integer type of the packed struct. |
| 990 | 902 | /// Whether zig chooses this type or the user specifies it, it is stored here. |
| 991 | 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 | 905 | status: enum { |
| 994 | 906 | none, |
| 995 | 907 | field_types_wip, |
| ... | ... | @@ -1011,15 +923,37 @@ pub const Struct = struct { |
| 1011 | 923 | is_tuple: bool, |
| 1012 | 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 | 950 | /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl. |
| 1017 | 951 | pub const Field = struct { |
| 1018 | 952 | /// Uses `noreturn` to indicate `anytype`. |
| 1019 | 953 | /// undefined until `status` is >= `have_field_types`. |
| 1020 | 954 | ty: Type, |
| 1021 | /// Uses `unreachable_value` to indicate no default. | |
| 1022 | default_val: Value, | |
| 955 | /// Uses `none` to indicate no default. | |
| 956 | default_val: InternPool.Index, | |
| 1023 | 957 | /// Zero means to use the ABI alignment of the type. |
| 1024 | 958 | abi_align: u32, |
| 1025 | 959 | /// undefined until `status` is `have_layout`. |
| ... | ... | @@ -1030,7 +964,7 @@ pub const Struct = struct { |
| 1030 | 964 | /// Returns the field alignment. If the struct is packed, returns 0. |
| 1031 | 965 | pub fn alignment( |
| 1032 | 966 | field: Field, |
| 1033 | target: Target, | |
| 967 | mod: *Module, | |
| 1034 | 968 | layout: std.builtin.Type.ContainerLayout, |
| 1035 | 969 | ) u32 { |
| 1036 | 970 | if (field.abi_align != 0) { |
| ... | ... | @@ -1038,24 +972,26 @@ pub const Struct = struct { |
| 1038 | 972 | return field.abi_align; |
| 1039 | 973 | } |
| 1040 | 974 | |
| 975 | const target = mod.getTarget(); | |
| 976 | ||
| 1041 | 977 | switch (layout) { |
| 1042 | 978 | .Packed => return 0, |
| 1043 | 979 | .Auto => { |
| 1044 | 980 | if (target.ofmt == .c) { |
| 1045 | return alignmentExtern(field, target); | |
| 981 | return alignmentExtern(field, mod); | |
| 1046 | 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 | 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 | 995 | // The C ABI requires 128 bit integer fields of structs |
| 1060 | 996 | // to be 16-bytes aligned. |
| 1061 | 997 | return @max(ty_abi_align, 16); |
| ... | ... | @@ -1069,39 +1005,12 @@ pub const Struct = struct { |
| 1069 | 1005 | /// runtime version of the struct. |
| 1070 | 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 | 1009 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); |
| 1074 | 1010 | } |
| 1075 | 1011 | |
| 1076 | 1012 | pub fn srcLoc(s: Struct, mod: *Module) SrcLoc { |
| 1077 | const owner_decl = mod.declPtr(s.owner_decl); | |
| 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 | } | |
| 1013 | return mod.declPtr(s.owner_decl).srcLoc(mod); | |
| 1105 | 1014 | } |
| 1106 | 1015 | |
| 1107 | 1016 | pub fn haveFieldTypes(s: Struct) bool { |
| ... | ... | @@ -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 | 1045 | assert(s.layout == .Packed); |
| 1137 | 1046 | assert(s.haveLayout()); |
| 1138 | 1047 | var bit_sum: u64 = 0; |
| ... | ... | @@ -1140,12 +1049,13 @@ pub const Struct = struct { |
| 1140 | 1049 | if (i == index) { |
| 1141 | 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 | 1054 | unreachable; // index out of bounds |
| 1146 | 1055 | } |
| 1147 | 1056 | |
| 1148 | 1057 | pub const RuntimeFieldIterator = struct { |
| 1058 | module: *Module, | |
| 1149 | 1059 | struct_obj: *const Struct, |
| 1150 | 1060 | index: u32 = 0, |
| 1151 | 1061 | |
| ... | ... | @@ -1155,6 +1065,7 @@ pub const Struct = struct { |
| 1155 | 1065 | }; |
| 1156 | 1066 | |
| 1157 | 1067 | pub fn next(it: *RuntimeFieldIterator) ?FieldAndIndex { |
| 1068 | const mod = it.module; | |
| 1158 | 1069 | while (true) { |
| 1159 | 1070 | var i = it.index; |
| 1160 | 1071 | it.index += 1; |
| ... | ... | @@ -1167,120 +1078,19 @@ pub const Struct = struct { |
| 1167 | 1078 | } |
| 1168 | 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 | 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 { | |
| 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); | |
| 1088 | pub fn runtimeFieldIterator(s: *const Struct, module: *Module) RuntimeFieldIterator { | |
| 1257 | 1089 | return .{ |
| 1258 | .file_scope = owner_decl.getFileScope(), | |
| 1259 | .parent_decl_node = owner_decl.src_node, | |
| 1260 | .lazy = LazySrcLoc.nodeOffset(0), | |
| 1090 | .struct_obj = s, | |
| 1091 | .module = module, | |
| 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 | 1096 | pub const Union = struct { |
| ... | ... | @@ -1293,7 +1103,7 @@ pub const Union = struct { |
| 1293 | 1103 | /// Set of field names in declaration order. |
| 1294 | 1104 | fields: Fields, |
| 1295 | 1105 | /// Represents the declarations inside this union. |
| 1296 | namespace: Namespace, | |
| 1106 | namespace: Namespace.Index, | |
| 1297 | 1107 | /// The Decl that corresponds to the union itself. |
| 1298 | 1108 | owner_decl: Decl.Index, |
| 1299 | 1109 | /// Index of the union_decl ZIR instruction. |
| ... | ... | @@ -1314,6 +1124,28 @@ pub const Union = struct { |
| 1314 | 1124 | requires_comptime: PropertyBoolean = .unknown, |
| 1315 | 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 | 1149 | pub const Field = struct { |
| 1318 | 1150 | /// undefined until `status` is `have_field_types` or `have_layout`. |
| 1319 | 1151 | ty: Type, |
| ... | ... | @@ -1323,52 +1155,30 @@ pub const Union = struct { |
| 1323 | 1155 | /// Returns the field alignment, assuming the union is not packed. |
| 1324 | 1156 | /// Keep implementation in sync with `Sema.unionFieldAlignment`. |
| 1325 | 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 | 1159 | if (field.abi_align == 0) { |
| 1328 | return field.ty.abiAlignment(target); | |
| 1160 | return field.ty.abiAlignment(mod); | |
| 1329 | 1161 | } else { |
| 1330 | 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 | 1170 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); |
| 1339 | 1171 | } |
| 1340 | 1172 | |
| 1341 | 1173 | pub fn srcLoc(self: Union, mod: *Module) SrcLoc { |
| 1342 | 1174 | const owner_decl = mod.declPtr(self.owner_decl); |
| 1343 | 1175 | return .{ |
| 1344 | .file_scope = owner_decl.getFileScope(), | |
| 1176 | .file_scope = owner_decl.getFileScope(mod), | |
| 1345 | 1177 | .parent_decl_node = owner_decl.src_node, |
| 1346 | 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 | 1182 | pub fn haveFieldTypes(u: Union) bool { |
| 1373 | 1183 | return switch (u.status) { |
| 1374 | 1184 | .none, |
| ... | ... | @@ -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 | 1197 | assert(u.haveFieldTypes()); |
| 1388 | 1198 | for (u.fields.values()) |field| { |
| 1389 | if (field.ty.hasRuntimeBits()) return false; | |
| 1199 | if (field.ty.hasRuntimeBits(mod)) return false; | |
| 1390 | 1200 | } |
| 1391 | 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 | 1205 | assert(u.haveFieldTypes()); |
| 1396 | 1206 | var most_alignment: u32 = 0; |
| 1397 | 1207 | var most_index: usize = undefined; |
| 1398 | 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 | 1212 | if (field_align > most_alignment) { |
| 1403 | 1213 | most_alignment = field_align; |
| 1404 | 1214 | most_index = i; |
| ... | ... | @@ -1408,20 +1218,20 @@ pub const Union = struct { |
| 1408 | 1218 | } |
| 1409 | 1219 | |
| 1410 | 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 | 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 | 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 | 1228 | max_align = @max(max_align, field_align); |
| 1419 | 1229 | } |
| 1420 | 1230 | return max_align; |
| 1421 | 1231 | } |
| 1422 | 1232 | |
| 1423 | pub fn abiSize(u: Union, target: Target, have_tag: bool) u64 { | |
| 1424 | return u.getLayout(target, have_tag).abi_size; | |
| 1233 | pub fn abiSize(u: Union, mod: *Module, have_tag: bool) u64 { | |
| 1234 | return u.getLayout(mod, have_tag).abi_size; | |
| 1425 | 1235 | } |
| 1426 | 1236 | |
| 1427 | 1237 | pub const Layout = 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 | 1265 | assert(u.haveLayout()); |
| 1456 | 1266 | var most_aligned_field: u32 = undefined; |
| 1457 | 1267 | var most_aligned_field_size: u64 = undefined; |
| ... | ... | @@ -1460,16 +1270,16 @@ pub const Union = struct { |
| 1460 | 1270 | var payload_align: u32 = 0; |
| 1461 | 1271 | const fields = u.fields.values(); |
| 1462 | 1272 | for (fields, 0..) |field, i| { |
| 1463 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1273 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1464 | 1274 | |
| 1465 | 1275 | const field_align = a: { |
| 1466 | 1276 | if (field.abi_align == 0) { |
| 1467 | break :a field.ty.abiAlignment(target); | |
| 1277 | break :a field.ty.abiAlignment(mod); | |
| 1468 | 1278 | } else { |
| 1469 | 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 | 1283 | if (field_size > payload_size) { |
| 1474 | 1284 | payload_size = field_size; |
| 1475 | 1285 | biggest_field = @intCast(u32, i); |
| ... | ... | @@ -1481,7 +1291,7 @@ pub const Union = struct { |
| 1481 | 1291 | } |
| 1482 | 1292 | } |
| 1483 | 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 | 1295 | return .{ |
| 1486 | 1296 | .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align), |
| 1487 | 1297 | .abi_align = payload_align, |
| ... | ... | @@ -1497,8 +1307,8 @@ pub const Union = struct { |
| 1497 | 1307 | } |
| 1498 | 1308 | // Put the tag before or after the payload depending on which one's |
| 1499 | 1309 | // alignment is greater. |
| 1500 | const tag_size = u.tag_ty.abiSize(target); | |
| 1501 | const tag_align = @max(1, u.tag_ty.abiAlignment(target)); | |
| 1310 | const tag_size = u.tag_ty.abiSize(mod); | |
| 1311 | const tag_align = @max(1, u.tag_ty.abiAlignment(mod)); | |
| 1502 | 1312 | var size: u64 = 0; |
| 1503 | 1313 | var padding: u32 = undefined; |
| 1504 | 1314 | if (tag_align >= payload_align) { |
| ... | ... | @@ -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 | 1346 | /// Some extern function struct memory is owned by the Decl's TypedValue.Managed |
| 1557 | 1347 | /// arena allocator. |
| 1558 | 1348 | pub const ExternFn = struct { |
| ... | ... | @@ -1630,12 +1420,27 @@ pub const Fn = struct { |
| 1630 | 1420 | is_noinline: bool, |
| 1631 | 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 | |
| 1634 | /// inferred error sets of any inline/comptime functions called. Not to be confused | |
| 1635 | /// with inferred error sets of generic instantiations of this function, which are | |
| 1636 | /// *not* tracked here - they are tracked in the new `Fn` object created for the | |
| 1637 | /// instantiations. | |
| 1638 | inferred_error_sets: InferredErrorSetList = .{}, | |
| 1423 | pub const Index = enum(u32) { | |
| 1424 | _, | |
| 1425 | ||
| 1426 | pub fn toOptional(i: Index) OptionalIndex { | |
| 1427 | return @intToEnum(OptionalIndex, @enumToInt(i)); | |
| 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 | 1445 | pub const Analysis = enum { |
| 1641 | 1446 | /// This function has not yet undergone analysis, because we have not |
| ... | ... | @@ -1662,16 +1467,16 @@ pub const Fn = struct { |
| 1662 | 1467 | /// or comptime functions. |
| 1663 | 1468 | pub const InferredErrorSet = struct { |
| 1664 | 1469 | /// The function from which this error set originates. |
| 1665 | func: *Fn, | |
| 1470 | func: Fn.Index, | |
| 1666 | 1471 | |
| 1667 | 1472 | /// All currently known errors that this error set contains. This includes |
| 1668 | 1473 | /// direct additions via `return error.Foo;`, and possibly also errors that |
| 1669 | 1474 | /// are returned from any dependent functions. When the inferred error set is |
| 1670 | 1475 | /// fully resolved, this map contains all the errors that the function might return. |
| 1671 | errors: ErrorSet.NameMap = .{}, | |
| 1476 | errors: NameMap = .{}, | |
| 1672 | 1477 | |
| 1673 | 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 | 1481 | /// Whether the function returned anyerror. This is true if either of |
| 1677 | 1482 | /// the dependent functions returns anyerror. |
| ... | ... | @@ -1681,52 +1486,57 @@ pub const Fn = struct { |
| 1681 | 1486 | /// can skip resolving any dependents of this inferred error set. |
| 1682 | 1487 | is_resolved: bool = false, |
| 1683 | 1488 | |
| 1684 | pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void { | |
| 1685 | switch (err_set_ty.tag()) { | |
| 1686 | .error_set => { | |
| 1687 | const names = err_set_ty.castTag(.error_set).?.data.names.keys(); | |
| 1688 | for (names) |name| { | |
| 1689 | try self.errors.put(gpa, name, {}); | |
| 1690 | } | |
| 1691 | }, | |
| 1692 | .error_set_single => { | |
| 1693 | const name = err_set_ty.castTag(.error_set_single).?.data; | |
| 1694 | try self.errors.put(gpa, name, {}); | |
| 1695 | }, | |
| 1696 | .error_set_inferred => { | |
| 1697 | const ies = err_set_ty.castTag(.error_set_inferred).?.data; | |
| 1698 | try self.inferred_error_sets.put(gpa, ies, {}); | |
| 1699 | }, | |
| 1700 | .error_set_merged => { | |
| 1701 | const names = err_set_ty.castTag(.error_set_merged).?.data.keys(); | |
| 1702 | for (names) |name| { | |
| 1703 | try self.errors.put(gpa, name, {}); | |
| 1704 | } | |
| 1705 | }, | |
| 1706 | .anyerror => { | |
| 1489 | pub const NameMap = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); | |
| 1490 | ||
| 1491 | pub const Index = enum(u32) { | |
| 1492 | _, | |
| 1493 | ||
| 1494 | pub fn toOptional(i: InferredErrorSet.Index) InferredErrorSet.OptionalIndex { | |
| 1495 | return @intToEnum(InferredErrorSet.OptionalIndex, @enumToInt(i)); | |
| 1496 | } | |
| 1497 | }; | |
| 1498 | ||
| 1499 | pub const OptionalIndex = enum(u32) { | |
| 1500 | none = std.math.maxInt(u32), | |
| 1501 | _, | |
| 1502 | ||
| 1503 | pub fn init(oi: ?InferredErrorSet.Index) InferredErrorSet.OptionalIndex { | |
| 1504 | return @intToEnum(InferredErrorSet.OptionalIndex, @enumToInt(oi orelse return .none)); | |
| 1505 | } | |
| 1506 | ||
| 1507 | pub fn unwrap(oi: InferredErrorSet.OptionalIndex) ?InferredErrorSet.Index { | |
| 1508 | if (oi == .none) return null; | |
| 1509 | return @intToEnum(InferredErrorSet.Index, @enumToInt(oi)); | |
| 1510 | } | |
| 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 | 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 | 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 | 1541 | const tags = file.zir.instructions.items(.tag); |
| 1732 | 1542 | |
| ... | ... | @@ -1741,7 +1551,7 @@ pub const Fn = struct { |
| 1741 | 1551 | } |
| 1742 | 1552 | |
| 1743 | 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 | 1556 | const tags = file.zir.instructions.items(.tag); |
| 1747 | 1557 | const data = file.zir.instructions.items(.data); |
| ... | ... | @@ -1764,7 +1574,7 @@ pub const Fn = struct { |
| 1764 | 1574 | |
| 1765 | 1575 | pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool { |
| 1766 | 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 | 1578 | const zir_tags = zir.instructions.items(.tag); |
| 1769 | 1579 | switch (zir_tags[func.zir_body_inst]) { |
| 1770 | 1580 | .func => return false, |
| ... | ... | @@ -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 | 1592 | pub const DeclAdapter = struct { |
| 1805 | 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 | 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 | 1601 | _ = b_index; |
| 1814 | 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 | 1607 | /// The container that structs, enums, unions, and opaques have. |
| 1820 | 1608 | pub const Namespace = struct { |
| 1821 | parent: ?*Namespace, | |
| 1609 | parent: OptionalIndex, | |
| 1822 | 1610 | file_scope: *File, |
| 1823 | 1611 | /// Will be a struct, enum, union, or opaque. |
| 1824 | 1612 | ty: Type, |
| ... | ... | @@ -1836,21 +1624,41 @@ pub const Namespace = struct { |
| 1836 | 1624 | /// Value is whether the usingnamespace decl is marked `pub`. |
| 1837 | 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 | 1649 | const DeclContext = struct { |
| 1840 | 1650 | module: *Module, |
| 1841 | 1651 | |
| 1842 | 1652 | pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 { |
| 1843 | 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 | 1657 | pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool { |
| 1848 | 1658 | _ = b_index; |
| 1849 | 1659 | const a_decl = ctx.module.declPtr(a_decl_index); |
| 1850 | 1660 | const b_decl = ctx.module.declPtr(b_decl_index); |
| 1851 | const a_name = mem.sliceTo(a_decl.name, 0); | |
| 1852 | const b_name = mem.sliceTo(b_decl.name, 0); | |
| 1853 | return mem.eql(u8, a_name, b_name); | |
| 1661 | return a_decl.name == b_decl.name; | |
| 1854 | 1662 | } |
| 1855 | 1663 | }; |
| 1856 | 1664 | |
| ... | ... | @@ -1862,8 +1670,6 @@ pub const Namespace = struct { |
| 1862 | 1670 | pub fn destroyDecls(ns: *Namespace, mod: *Module) void { |
| 1863 | 1671 | const gpa = mod.gpa; |
| 1864 | 1672 | |
| 1865 | log.debug("destroyDecls {*}", .{ns}); | |
| 1866 | ||
| 1867 | 1673 | var decls = ns.decls; |
| 1868 | 1674 | ns.decls = .{}; |
| 1869 | 1675 | |
| ... | ... | @@ -1889,8 +1695,6 @@ pub const Namespace = struct { |
| 1889 | 1695 | ) !void { |
| 1890 | 1696 | const gpa = mod.gpa; |
| 1891 | 1697 | |
| 1892 | log.debug("deleteAllDecls {*}", .{ns}); | |
| 1893 | ||
| 1894 | 1698 | var decls = ns.decls; |
| 1895 | 1699 | ns.decls = .{}; |
| 1896 | 1700 | |
| ... | ... | @@ -1919,46 +1723,38 @@ pub const Namespace = struct { |
| 1919 | 1723 | pub fn renderFullyQualifiedName( |
| 1920 | 1724 | ns: Namespace, |
| 1921 | 1725 | mod: *Module, |
| 1922 | name: []const u8, | |
| 1726 | name: InternPool.NullTerminatedString, | |
| 1923 | 1727 | writer: anytype, |
| 1924 | 1728 | ) @TypeOf(writer).Error!void { |
| 1925 | if (ns.parent) |parent| { | |
| 1926 | const decl_index = ns.getDeclIndex(); | |
| 1927 | const decl = mod.declPtr(decl_index); | |
| 1928 | try parent.renderFullyQualifiedName(mod, mem.sliceTo(decl.name, 0), writer); | |
| 1729 | if (ns.parent.unwrap()) |parent| { | |
| 1730 | const decl = mod.declPtr(ns.getDeclIndex(mod)); | |
| 1731 | try mod.namespacePtr(parent).renderFullyQualifiedName(mod, decl.name, writer); | |
| 1929 | 1732 | } else { |
| 1930 | 1733 | try ns.file_scope.renderFullyQualifiedName(writer); |
| 1931 | 1734 | } |
| 1932 | if (name.len != 0) { | |
| 1933 | try writer.writeAll("."); | |
| 1934 | try writer.writeAll(name); | |
| 1935 | } | |
| 1735 | if (name != .empty) try writer.print(".{}", .{name.fmt(&mod.intern_pool)}); | |
| 1936 | 1736 | } |
| 1937 | 1737 | |
| 1938 | 1738 | /// This renders e.g. "std/fs.zig:Dir.OpenOptions" |
| 1939 | 1739 | pub fn renderFullyQualifiedDebugName( |
| 1940 | 1740 | ns: Namespace, |
| 1941 | 1741 | mod: *Module, |
| 1942 | name: []const u8, | |
| 1742 | name: InternPool.NullTerminatedString, | |
| 1943 | 1743 | writer: anytype, |
| 1944 | 1744 | ) @TypeOf(writer).Error!void { |
| 1945 | var separator_char: u8 = '.'; | |
| 1946 | if (ns.parent) |parent| { | |
| 1947 | const decl_index = ns.getDeclIndex(); | |
| 1948 | const decl = mod.declPtr(decl_index); | |
| 1949 | try parent.renderFullyQualifiedDebugName(mod, mem.sliceTo(decl.name, 0), writer); | |
| 1950 | } else { | |
| 1745 | const separator_char: u8 = if (ns.parent.unwrap()) |parent| sep: { | |
| 1746 | const decl = mod.declPtr(ns.getDeclIndex(mod)); | |
| 1747 | try mod.namespacePtr(parent).renderFullyQualifiedDebugName(mod, decl.name, writer); | |
| 1748 | break :sep '.'; | |
| 1749 | } else sep: { | |
| 1951 | 1750 | try ns.file_scope.renderFullyQualifiedDebugName(writer); |
| 1952 | separator_char = ':'; | |
| 1953 | } | |
| 1954 | if (name.len != 0) { | |
| 1955 | try writer.writeByte(separator_char); | |
| 1956 | try writer.writeAll(name); | |
| 1957 | } | |
| 1751 | break :sep ':'; | |
| 1752 | }; | |
| 1753 | if (name != .empty) try writer.print("{c}{}", .{ separator_char, name.fmt(&mod.intern_pool) }); | |
| 1958 | 1754 | } |
| 1959 | 1755 | |
| 1960 | pub fn getDeclIndex(ns: Namespace) Decl.Index { | |
| 1961 | return ns.ty.getOwnerDecl(); | |
| 1756 | pub fn getDeclIndex(ns: Namespace, mod: *Module) Decl.Index { | |
| 1757 | return ns.ty.getOwnerDecl(mod); | |
| 1962 | 1758 | } |
| 1963 | 1759 | }; |
| 1964 | 1760 | |
| ... | ... | @@ -2140,11 +1936,11 @@ pub const File = struct { |
| 2140 | 1936 | }; |
| 2141 | 1937 | } |
| 2142 | 1938 | |
| 2143 | pub fn fullyQualifiedNameZ(file: File, gpa: Allocator) ![:0]u8 { | |
| 2144 | var buf = std.ArrayList(u8).init(gpa); | |
| 2145 | defer buf.deinit(); | |
| 2146 | try file.renderFullyQualifiedName(buf.writer()); | |
| 2147 | return buf.toOwnedSliceSentinel(0); | |
| 1939 | pub fn fullyQualifiedName(file: File, mod: *Module) !InternPool.NullTerminatedString { | |
| 1940 | const ip = &mod.intern_pool; | |
| 1941 | const start = ip.string_bytes.items.len; | |
| 1942 | try file.renderFullyQualifiedName(ip.string_bytes.writer(mod.gpa)); | |
| 1943 | return ip.getOrPutTrailingString(mod.gpa, ip.string_bytes.items.len - start); | |
| 2148 | 1944 | } |
| 2149 | 1945 | |
| 2150 | 1946 | /// Returns the full path to this file relative to its package. |
| ... | ... | @@ -2268,7 +2064,7 @@ pub const ErrorMsg = struct { |
| 2268 | 2064 | reference_trace: []Trace = &.{}, |
| 2269 | 2065 | |
| 2270 | 2066 | pub const Trace = struct { |
| 2271 | decl: ?[*:0]const u8, | |
| 2067 | decl: InternPool.OptionalNullTerminatedString, | |
| 2272 | 2068 | src_loc: SrcLoc, |
| 2273 | 2069 | hidden: u32 = 0, |
| 2274 | 2070 | }; |
| ... | ... | @@ -2281,7 +2077,7 @@ pub const ErrorMsg = struct { |
| 2281 | 2077 | ) !*ErrorMsg { |
| 2282 | 2078 | const err_msg = try gpa.create(ErrorMsg); |
| 2283 | 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 | 2081 | return err_msg; |
| 2286 | 2082 | } |
| 2287 | 2083 | |
| ... | ... | @@ -3287,7 +3083,7 @@ pub const LazySrcLoc = union(enum) { |
| 3287 | 3083 | } |
| 3288 | 3084 | |
| 3289 | 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 | 3087 | return switch (lazy) { |
| 3292 | 3088 | .unneeded, |
| 3293 | 3089 | .entire_file, |
| ... | ... | @@ -3295,7 +3091,7 @@ pub const LazySrcLoc = union(enum) { |
| 3295 | 3091 | .token_abs, |
| 3296 | 3092 | .node_abs, |
| 3297 | 3093 | => .{ |
| 3298 | .file_scope = decl.getFileScope(), | |
| 3094 | .file_scope = decl.getFileScope(mod), | |
| 3299 | 3095 | .parent_decl_node = 0, |
| 3300 | 3096 | .lazy = lazy, |
| 3301 | 3097 | }, |
| ... | ... | @@ -3361,7 +3157,7 @@ pub const LazySrcLoc = union(enum) { |
| 3361 | 3157 | .for_input, |
| 3362 | 3158 | .for_capture_from_input, |
| 3363 | 3159 | => .{ |
| 3364 | .file_scope = decl.getFileScope(), | |
| 3160 | .file_scope = decl.getFileScope(mod), | |
| 3365 | 3161 | .parent_decl_node = decl.src_node, |
| 3366 | 3162 | .lazy = lazy, |
| 3367 | 3163 | }, |
| ... | ... | @@ -3391,6 +3187,12 @@ pub const CompileError = error{ |
| 3391 | 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 | 3196 | pub fn deinit(mod: *Module) void { |
| 3395 | 3197 | const gpa = mod.gpa; |
| 3396 | 3198 | |
| ... | ... | @@ -3489,42 +3291,29 @@ pub fn deinit(mod: *Module) void { |
| 3489 | 3291 | } |
| 3490 | 3292 | mod.export_owners.deinit(gpa); |
| 3491 | 3293 | |
| 3492 | { | |
| 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 | } | |
| 3294 | mod.global_error_set.deinit(gpa); | |
| 3499 | 3295 | |
| 3500 | mod.error_name_list.deinit(gpa); | |
| 3501 | 3296 | mod.test_functions.deinit(gpa); |
| 3502 | 3297 | mod.align_stack_fns.deinit(gpa); |
| 3503 | 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 | 3300 | mod.decls_free_list.deinit(gpa); |
| 3515 | 3301 | mod.allocated_decls.deinit(gpa); |
| 3516 | 3302 | mod.global_assembly.deinit(gpa); |
| 3517 | 3303 | mod.reference_table.deinit(gpa); |
| 3518 | 3304 | |
| 3519 | mod.string_literal_table.deinit(gpa); | |
| 3520 | mod.string_literal_bytes.deinit(gpa); | |
| 3305 | mod.namespaces_free_list.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 | 3313 | pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { |
| 3524 | 3314 | const gpa = mod.gpa; |
| 3525 | 3315 | { |
| 3526 | 3316 | const decl = mod.declPtr(decl_index); |
| 3527 | log.debug("destroy {*} ({s})", .{ decl, decl.name }); | |
| 3528 | 3317 | _ = mod.test_functions.swapRemove(decl_index); |
| 3529 | 3318 | if (decl.deletion_flag) { |
| 3530 | 3319 | assert(mod.deletion_set.swapRemove(decl_index)); |
| ... | ... | @@ -3533,14 +3322,15 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { |
| 3533 | 3322 | gpa.free(kv.value); |
| 3534 | 3323 | } |
| 3535 | 3324 | if (decl.has_tv) { |
| 3536 | if (decl.getInnerNamespace()) |namespace| { | |
| 3537 | namespace.destroyDecls(mod); | |
| 3325 | if (decl.getOwnedInnerNamespaceIndex(mod).unwrap()) |i| { | |
| 3326 | mod.namespacePtr(i).destroyDecls(mod); | |
| 3327 | mod.destroyNamespace(i); | |
| 3538 | 3328 | } |
| 3539 | 3329 | } |
| 3330 | if (decl.src_scope) |scope| scope.decRef(gpa); | |
| 3540 | 3331 | decl.clearValues(mod); |
| 3541 | 3332 | decl.dependants.deinit(gpa); |
| 3542 | 3333 | decl.dependencies.deinit(gpa); |
| 3543 | decl.clearName(gpa); | |
| 3544 | 3334 | decl.* = undefined; |
| 3545 | 3335 | } |
| 3546 | 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 | 3344 | } |
| 3555 | 3345 | } |
| 3556 | 3346 | |
| 3557 | pub fn declPtr(mod: *Module, decl_index: Decl.Index) *Decl { | |
| 3558 | return mod.allocated_decls.at(@enumToInt(decl_index)); | |
| 3347 | pub fn declPtr(mod: *Module, index: Decl.Index) *Decl { | |
| 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 | 3385 | /// Returns true if and only if the Decl is the top level struct associated with a File. |
| 3562 | 3386 | pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { |
| 3563 | 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 | 3390 | return false; |
| 3566 | return decl_index == decl.src_namespace.getDeclIndex(); | |
| 3391 | return decl_index == namespace.getDeclIndex(mod); | |
| 3567 | 3392 | } |
| 3568 | 3393 | |
| 3569 | 3394 | fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void { |
| 3570 | for (export_list.items) |exp| { | |
| 3571 | gpa.free(exp.options.name); | |
| 3572 | if (exp.options.section) |s| gpa.free(s); | |
| 3573 | gpa.destroy(exp); | |
| 3574 | } | |
| 3395 | for (export_list.items) |exp| gpa.destroy(exp); | |
| 3575 | 3396 | export_list.deinit(gpa); |
| 3576 | 3397 | } |
| 3577 | 3398 | |
| ... | ... | @@ -3990,9 +3811,6 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { |
| 3990 | 3811 | if (decl.zir_decl_index != 0) { |
| 3991 | 3812 | const old_zir_decl_index = decl.zir_decl_index; |
| 3992 | 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 | 3814 | try file.deleted_decls.append(gpa, decl_index); |
| 3997 | 3815 | continue; |
| 3998 | 3816 | }; |
| ... | ... | @@ -4000,41 +3818,34 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { |
| 4000 | 3818 | decl.zir_decl_index = new_zir_decl_index; |
| 4001 | 3819 | const new_hash = decl.contentsHashZir(new_zir); |
| 4002 | 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 | 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 | 3825 | if (!decl.owns_tv) continue; |
| 4015 | 3826 | |
| 4016 | if (decl.getStruct()) |struct_obj| { | |
| 3827 | if (decl.getOwnedStruct(mod)) |struct_obj| { | |
| 4017 | 3828 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { |
| 4018 | 3829 | try file.deleted_decls.append(gpa, decl_index); |
| 4019 | 3830 | continue; |
| 4020 | 3831 | }; |
| 4021 | 3832 | } |
| 4022 | 3833 | |
| 4023 | if (decl.getUnion()) |union_obj| { | |
| 3834 | if (decl.getOwnedUnion(mod)) |union_obj| { | |
| 4024 | 3835 | union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse { |
| 4025 | 3836 | try file.deleted_decls.append(gpa, decl_index); |
| 4026 | 3837 | continue; |
| 4027 | 3838 | }; |
| 4028 | 3839 | } |
| 4029 | 3840 | |
| 4030 | if (decl.getFunction()) |func| { | |
| 3841 | if (decl.getOwnedFunction(mod)) |func| { | |
| 4031 | 3842 | func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { |
| 4032 | 3843 | try file.deleted_decls.append(gpa, decl_index); |
| 4033 | 3844 | continue; |
| 4034 | 3845 | }; |
| 4035 | 3846 | } |
| 4036 | 3847 | |
| 4037 | if (decl.getInnerNamespace()) |namespace| { | |
| 3848 | if (decl.getOwnedInnerNamespace(mod)) |namespace| { | |
| 4038 | 3849 | for (namespace.decls.keys()) |sub_decl| { |
| 4039 | 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 | 4018 | .complete => return, |
| 4208 | 4019 | |
| 4209 | 4020 | .outdated => blk: { |
| 4210 | log.debug("re-analyzing {*} ({s})", .{ decl, decl.name }); | |
| 4211 | ||
| 4212 | 4021 | // The exports this Decl performs will be re-discovered, so we remove them here |
| 4213 | 4022 | // prior to re-analysis. |
| 4214 | 4023 | try mod.deleteDeclExports(decl_index); |
| 4215 | 4024 | |
| 4216 | 4025 | // Similarly, `@setAlignStack` invocations will be re-discovered. |
| 4217 | if (decl.getFunction()) |func| { | |
| 4026 | if (decl.getOwnedFunctionIndex(mod).unwrap()) |func| { | |
| 4218 | 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 | 4032 | const dep = mod.declPtr(dep_index); |
| 4224 | 4033 | dep.removeDependant(decl_index); |
| 4225 | 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 | 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 | 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 | 4047 | decl_prog_node.activate(); |
| 4242 | 4048 | defer decl_prog_node.end(); |
| 4243 | 4049 | |
| ... | ... | @@ -4264,7 +4070,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4264 | 4070 | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); |
| 4265 | 4071 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 4266 | 4072 | mod.gpa, |
| 4267 | decl.srcLoc(), | |
| 4073 | decl.srcLoc(mod), | |
| 4268 | 4074 | "unable to analyze: {s}", |
| 4269 | 4075 | .{@errorName(e)}, |
| 4270 | 4076 | )); |
| ... | ... | @@ -4277,7 +4083,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4277 | 4083 | // Update all dependents which have at least this level of dependency. |
| 4278 | 4084 | // If our type remained the same and we're a function, only update |
| 4279 | 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 | 4088 | for (decl.dependants.keys(), decl.dependants.values()) |dep_index, dep_type| { |
| 4283 | 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 | 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 | 4114 | const tracy = trace(@src()); |
| 4309 | 4115 | defer tracy.end(); |
| 4310 | 4116 | |
| 4117 | const func = mod.funcPtr(func_index); | |
| 4311 | 4118 | const decl_index = func.owner_decl; |
| 4312 | 4119 | const decl = mod.declPtr(decl_index); |
| 4313 | 4120 | |
| ... | ... | @@ -4339,7 +4146,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4339 | 4146 | defer tmp_arena.deinit(); |
| 4340 | 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 | 4150 | error.AnalysisFail => { |
| 4344 | 4151 | if (func.state == .in_progress) { |
| 4345 | 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 | 4172 | |
| 4366 | 4173 | if (no_bin_file and !dump_air and !dump_llvm_ir) return; |
| 4367 | 4174 | |
| 4368 | log.debug("analyze liveness of {s}", .{decl.name}); | |
| 4369 | var liveness = try Liveness.analyze(gpa, air); | |
| 4175 | var liveness = try Liveness.analyze(gpa, air, &mod.intern_pool); | |
| 4370 | 4176 | defer liveness.deinit(gpa); |
| 4371 | 4177 | |
| 4372 | 4178 | if (dump_air) { |
| 4373 | 4179 | const fqn = try decl.getFullyQualifiedName(mod); |
| 4374 | defer mod.gpa.free(fqn); | |
| 4375 | ||
| 4376 | std.debug.print("# Begin Function AIR: {s}:\n", .{fqn}); | |
| 4180 | std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(&mod.intern_pool)}); | |
| 4377 | 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 | 4185 | if (std.debug.runtime_safety) { |
| ... | ... | @@ -4383,6 +4187,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4383 | 4187 | .gpa = gpa, |
| 4384 | 4188 | .air = air, |
| 4385 | 4189 | .liveness = liveness, |
| 4190 | .intern_pool = &mod.intern_pool, | |
| 4386 | 4191 | }; |
| 4387 | 4192 | defer verify.deinit(); |
| 4388 | 4193 | |
| ... | ... | @@ -4394,7 +4199,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4394 | 4199 | decl_index, |
| 4395 | 4200 | try Module.ErrorMsg.create( |
| 4396 | 4201 | gpa, |
| 4397 | decl.srcLoc(), | |
| 4202 | decl.srcLoc(mod), | |
| 4398 | 4203 | "invalid liveness: {s}", |
| 4399 | 4204 | .{@errorName(err)}, |
| 4400 | 4205 | ), |
| ... | ... | @@ -4407,7 +4212,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4407 | 4212 | |
| 4408 | 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 | 4216 | error.OutOfMemory => return error.OutOfMemory, |
| 4412 | 4217 | error.AnalysisFail => { |
| 4413 | 4218 | decl.analysis = .codegen_failure; |
| ... | ... | @@ -4417,7 +4222,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4417 | 4222 | try mod.failed_decls.ensureUnusedCapacity(gpa, 1); |
| 4418 | 4223 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( |
| 4419 | 4224 | gpa, |
| 4420 | decl.srcLoc(), | |
| 4225 | decl.srcLoc(mod), | |
| 4421 | 4226 | "unable to codegen: {s}", |
| 4422 | 4227 | .{@errorName(err)}, |
| 4423 | 4228 | )); |
| ... | ... | @@ -4437,7 +4242,8 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4437 | 4242 | /// analyzed, and for ensuring it can exist at runtime (see |
| 4438 | 4243 | /// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body |
| 4439 | 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 | 4247 | const decl_index = func.owner_decl; |
| 4442 | 4248 | const decl = mod.declPtr(decl_index); |
| 4443 | 4249 | |
| ... | ... | @@ -4475,7 +4281,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func: *Fn) !void { |
| 4475 | 4281 | |
| 4476 | 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 | 4285 | if (mod.emit_h != null) { |
| 4480 | 4286 | // TODO: we ideally only want to do this if the function's type changed |
| 4481 | 4287 | // since the last update |
| ... | ... | @@ -4527,42 +4333,54 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4527 | 4333 | if (file.root_decl != .none) return; |
| 4528 | 4334 | |
| 4529 | 4335 | const gpa = mod.gpa; |
| 4530 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | |
| 4531 | errdefer new_decl_arena.deinit(); | |
| 4532 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 4533 | ||
| 4534 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); | |
| 4535 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); | |
| 4536 | const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); | |
| 4537 | const ty_ty = comptime Type.initTag(.type); | |
| 4538 | struct_obj.* = .{ | |
| 4539 | .owner_decl = undefined, // set below | |
| 4336 | ||
| 4337 | // Because these three things each reference each other, `undefined` | |
| 4338 | // placeholders are used before being set after the struct type gains an | |
| 4339 | // InternPool index. | |
| 4340 | const new_namespace_index = try mod.createNamespace(.{ | |
| 4341 | .parent = .none, | |
| 4342 | .ty = undefined, | |
| 4343 | .file_scope = file, | |
| 4344 | }); | |
| 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 | 4354 | .fields = .{}, |
| 4541 | 4355 | .zir_index = undefined, // set below |
| 4542 | 4356 | .layout = .Auto, |
| 4543 | 4357 | .status = .none, |
| 4544 | 4358 | .known_non_opv = undefined, |
| 4545 | 4359 | .is_tuple = undefined, // set below |
| 4546 | .namespace = .{ | |
| 4547 | .parent = null, | |
| 4548 | .ty = struct_ty, | |
| 4549 | .file_scope = file, | |
| 4550 | }, | |
| 4551 | }; | |
| 4552 | const new_decl_index = try mod.allocateNewDecl(&struct_obj.namespace, 0, null); | |
| 4553 | const new_decl = mod.declPtr(new_decl_index); | |
| 4360 | .namespace = new_namespace_index, | |
| 4361 | }); | |
| 4362 | errdefer mod.destroyStruct(struct_index); | |
| 4363 | ||
| 4364 | const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ | |
| 4365 | .index = struct_index.toOptional(), | |
| 4366 | .namespace = new_namespace_index.toOptional(), | |
| 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 | 4372 | file.root_decl = new_decl_index.toOptional(); |
| 4555 | struct_obj.owner_decl = new_decl_index; | |
| 4556 | new_decl.name = try file.fullyQualifiedNameZ(gpa); | |
| 4373 | ||
| 4374 | new_decl.name = try file.fullyQualifiedName(mod); | |
| 4557 | 4375 | new_decl.src_line = 0; |
| 4558 | 4376 | new_decl.is_pub = true; |
| 4559 | 4377 | new_decl.is_exported = false; |
| 4560 | 4378 | new_decl.has_align = false; |
| 4561 | 4379 | new_decl.has_linksection_or_addrspace = false; |
| 4562 | new_decl.ty = ty_ty; | |
| 4563 | new_decl.val = struct_val; | |
| 4380 | new_decl.ty = Type.type; | |
| 4381 | new_decl.val = struct_ty.toValue(); | |
| 4564 | 4382 | new_decl.@"align" = 0; |
| 4565 | new_decl.@"linksection" = null; | |
| 4383 | new_decl.@"linksection" = .none; | |
| 4566 | 4384 | new_decl.has_tv = true; |
| 4567 | 4385 | new_decl.owns_tv = true; |
| 4568 | 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 | 4391 | if (file.status == .success_zir) { |
| 4574 | 4392 | assert(file.zir_loaded); |
| 4575 | 4393 | const main_struct_inst = Zir.main_struct_inst; |
| 4394 | const struct_obj = mod.structPtr(struct_index); | |
| 4576 | 4395 | struct_obj.zir_index = main_struct_inst; |
| 4577 | 4396 | const extended = file.zir.instructions.items(.data)[main_struct_inst].extended; |
| 4578 | 4397 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| ... | ... | @@ -4582,25 +4401,34 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4582 | 4401 | defer sema_arena.deinit(); |
| 4583 | 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 | 4407 | var sema: Sema = .{ |
| 4586 | 4408 | .mod = mod, |
| 4587 | 4409 | .gpa = gpa, |
| 4588 | 4410 | .arena = sema_arena_allocator, |
| 4589 | .perm_arena = new_decl_arena_allocator, | |
| 4590 | 4411 | .code = file.zir, |
| 4591 | 4412 | .owner_decl = new_decl, |
| 4592 | 4413 | .owner_decl_index = new_decl_index, |
| 4593 | 4414 | .func = null, |
| 4415 | .func_index = .none, | |
| 4594 | 4416 | .fn_ret_ty = Type.void, |
| 4595 | 4417 | .owner_func = null, |
| 4418 | .owner_func_index = .none, | |
| 4419 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 4596 | 4420 | }; |
| 4597 | 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 | 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 | 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 | 4432 | new_decl.analysis = .complete; |
| 4605 | 4433 | } else |err| switch (err) { |
| 4606 | 4434 | error.OutOfMemory => return error.OutOfMemory, |
| ... | ... | @@ -4632,8 +4460,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4632 | 4460 | } else { |
| 4633 | 4461 | new_decl.analysis = .file_failure; |
| 4634 | 4462 | } |
| 4635 | ||
| 4636 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 4637 | 4463 | } |
| 4638 | 4464 | |
| 4639 | 4465 | /// Returns `true` if the Decl type changed. |
| ... | ... | @@ -4645,68 +4471,52 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4645 | 4471 | |
| 4646 | 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 | 4475 | return error.AnalysisFail; |
| 4650 | 4476 | } |
| 4651 | 4477 | |
| 4652 | 4478 | const gpa = mod.gpa; |
| 4653 | const zir = decl.getFileScope().zir; | |
| 4479 | const zir = decl.getFileScope(mod).zir; | |
| 4654 | 4480 | const zir_datas = zir.instructions.items(.data); |
| 4655 | 4481 | |
| 4656 | 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 | 4484 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 4678 | 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 | 4490 | var sema: Sema = .{ |
| 4682 | 4491 | .mod = mod, |
| 4683 | 4492 | .gpa = gpa, |
| 4684 | .arena = analysis_arena_allocator, | |
| 4685 | .perm_arena = decl_arena_allocator, | |
| 4493 | .arena = analysis_arena.allocator(), | |
| 4686 | 4494 | .code = zir, |
| 4687 | 4495 | .owner_decl = decl, |
| 4688 | 4496 | .owner_decl_index = decl_index, |
| 4689 | 4497 | .func = null, |
| 4498 | .func_index = .none, | |
| 4690 | 4499 | .fn_ret_ty = Type.void, |
| 4691 | 4500 | .owner_func = null, |
| 4501 | .owner_func_index = .none, | |
| 4502 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 4692 | 4503 | }; |
| 4693 | 4504 | defer sema.deinit(); |
| 4694 | 4505 | |
| 4695 | 4506 | if (mod.declIsRoot(decl_index)) { |
| 4696 | log.debug("semaDecl root {*} ({s})", .{ decl, decl.name }); | |
| 4697 | 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 | 4510 | // This might not have gotten set in `semaFile` if the first time had |
| 4700 | 4511 | // a ZIR failure, so we set it here in case. |
| 4701 | 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 | 4514 | decl.analysis = .complete; |
| 4704 | 4515 | decl.generation = mod.generation; |
| 4705 | 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 | 4520 | defer wip_captures.deinit(); |
| 4711 | 4521 | |
| 4712 | 4522 | var block_scope: Sema.Block = .{ |
| ... | ... | @@ -4724,12 +4534,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4724 | 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 | 4538 | const inst_data = zir_datas[zir_block_index].pl_node; |
| 4729 | 4539 | const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 4730 | 4540 | const body = zir.extra[extra.end..][0..extra.data.body_len]; |
| 4731 | 4541 | const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand; |
| 4732 | 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 | 4547 | const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 }; |
| 4734 | 4548 | const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 }; |
| 4735 | 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 | 4562 | decl_tv.ty.fmt(mod), |
| 4749 | 4563 | }); |
| 4750 | 4564 | } |
| 4751 | var buffer: Value.ToTypeBuffer = undefined; | |
| 4752 | const ty = try decl_tv.val.toType(&buffer).copy(decl_arena_allocator); | |
| 4753 | if (ty.getNamespace() == null) { | |
| 4565 | const ty = decl_tv.val.toType(); | |
| 4566 | if (ty.getNamespace(mod) == null) { | |
| 4754 | 4567 | return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)}); |
| 4755 | 4568 | } |
| 4756 | 4569 | |
| 4757 | decl.ty = Type.type; | |
| 4758 | decl.val = try Value.Tag.ty.create(decl_arena_allocator, ty); | |
| 4570 | decl.ty = InternPool.Index.type_type.toType(); | |
| 4571 | decl.val = ty.toValue(); | |
| 4759 | 4572 | decl.@"align" = 0; |
| 4760 | decl.@"linksection" = null; | |
| 4573 | decl.@"linksection" = .none; | |
| 4761 | 4574 | decl.has_tv = true; |
| 4762 | 4575 | decl.owns_tv = false; |
| 4763 | 4576 | decl.analysis = .complete; |
| ... | ... | @@ -4766,8 +4579,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4766 | 4579 | return true; |
| 4767 | 4580 | } |
| 4768 | 4581 | |
| 4769 | if (decl_tv.val.castTag(.function)) |fn_payload| { | |
| 4770 | const func = fn_payload.data; | |
| 4582 | if (mod.intern_pool.indexToFunc(decl_tv.val.toIntern()).unwrap()) |func_index| { | |
| 4583 | const func = mod.funcPtr(func_index); | |
| 4771 | 4584 | const owns_tv = func.owner_decl == decl_index; |
| 4772 | 4585 | if (owns_tv) { |
| 4773 | 4586 | var prev_type_has_bits = false; |
| ... | ... | @@ -4775,31 +4588,30 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4775 | 4588 | var type_changed = true; |
| 4776 | 4589 | |
| 4777 | 4590 | if (decl.has_tv) { |
| 4778 | prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(); | |
| 4591 | prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod); | |
| 4779 | 4592 | type_changed = !decl.ty.eql(decl_tv.ty, mod); |
| 4780 | if (decl.getFunction()) |prev_func| { | |
| 4593 | if (decl.getOwnedFunction(mod)) |prev_func| { | |
| 4781 | 4594 | prev_is_inline = prev_func.state == .inline_only; |
| 4782 | 4595 | } |
| 4783 | 4596 | } |
| 4784 | 4597 | decl.clearValues(mod); |
| 4785 | 4598 | |
| 4786 | decl.ty = try decl_tv.ty.copy(decl_arena_allocator); | |
| 4787 | decl.val = try decl_tv.val.copy(decl_arena_allocator); | |
| 4599 | decl.ty = decl_tv.ty; | |
| 4600 | decl.val = (try decl_tv.val.intern(decl_tv.ty, mod)).toValue(); | |
| 4788 | 4601 | // linksection, align, and addrspace were already set by Sema |
| 4789 | 4602 | decl.has_tv = true; |
| 4790 | 4603 | decl.owns_tv = owns_tv; |
| 4791 | 4604 | decl.analysis = .complete; |
| 4792 | 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 | 4608 | if (decl.is_exported) { |
| 4796 | 4609 | const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; |
| 4797 | 4610 | if (is_inline) { |
| 4798 | 4611 | return sema.fail(&block_scope, export_src, "export of inline function", .{}); |
| 4799 | 4612 | } |
| 4800 | 4613 | // The scope needs to have the decl in it. |
| 4801 | const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; | |
| 4802 | try sema.analyzeExport(&block_scope, export_src, options, decl_index); | |
| 4614 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); | |
| 4803 | 4615 | } |
| 4804 | 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 | 4625 | decl.owns_tv = false; |
| 4814 | 4626 | var queue_linker_work = false; |
| 4815 | 4627 | var is_extern = false; |
| 4816 | switch (decl_tv.val.tag()) { | |
| 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 | ||
| 4628 | switch (decl_tv.val.toIntern()) { | |
| 4836 | 4629 | .generic_poison => unreachable, |
| 4837 | 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 => { | |
| 4842 | log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name }); | |
| 4843 | queue_linker_work = true; | |
| 4643 | .func => {}, | |
| 4644 | ||
| 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); | |
| 4848 | decl.val = try decl_tv.val.copy(decl_arena_allocator); | |
| 4651 | decl.ty = decl_tv.ty; | |
| 4652 | decl.val = (try decl_tv.val.intern(decl_tv.ty, mod)).toValue(); | |
| 4849 | 4653 | decl.@"align" = blk: { |
| 4850 | const align_ref = decl.zirAlignRef(); | |
| 4654 | const align_ref = decl.zirAlignRef(mod); | |
| 4851 | 4655 | if (align_ref == .none) break :blk 0; |
| 4852 | 4656 | break :blk try sema.resolveAlign(&block_scope, align_src, align_ref); |
| 4853 | 4657 | }; |
| 4854 | 4658 | decl.@"linksection" = blk: { |
| 4855 | const linksection_ref = decl.zirLinksectionRef(); | |
| 4856 | if (linksection_ref == .none) break :blk null; | |
| 4659 | const linksection_ref = decl.zirLinksectionRef(mod); | |
| 4660 | if (linksection_ref == .none) break :blk .none; | |
| 4857 | 4661 | const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known"); |
| 4858 | 4662 | if (mem.indexOfScalar(u8, bytes, 0) != null) { |
| 4859 | 4663 | return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); |
| 4860 | 4664 | } else if (bytes.len == 0) { |
| 4861 | 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 | 4670 | decl.@"addrspace" = blk: { |
| 4866 | const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) { | |
| 4867 | .function, .extern_fn => .function, | |
| 4671 | const addrspace_ctx: Sema.AddressSpaceContext = switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { | |
| 4868 | 4672 | .variable => .variable, |
| 4673 | .extern_func, .func => .function, | |
| 4869 | 4674 | else => .constant, |
| 4870 | 4675 | }; |
| 4871 | 4676 | |
| 4872 | 4677 | const target = sema.mod.getTarget(); |
| 4873 | break :blk switch (decl.zirAddrspaceRef()) { | |
| 4678 | break :blk switch (decl.zirAddrspaceRef(mod)) { | |
| 4874 | 4679 | .none => switch (addrspace_ctx) { |
| 4875 | 4680 | .function => target_util.defaultAddressSpace(target, .function), |
| 4876 | 4681 | .variable => target_util.defaultAddressSpace(target, .global_mutable), |
| ... | ... | @@ -4888,7 +4693,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4888 | 4693 | (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); |
| 4889 | 4694 | |
| 4890 | 4695 | if (has_runtime_bits) { |
| 4891 | log.debug("queue linker work for {*} ({s})", .{ decl, decl.name }); | |
| 4892 | 4696 | |
| 4893 | 4697 | // Needed for codegen_decl which will call updateDecl and then the |
| 4894 | 4698 | // codegen backend wants full access to the Decl Type. |
| ... | ... | @@ -4904,8 +4708,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4904 | 4708 | if (decl.is_exported) { |
| 4905 | 4709 | const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; |
| 4906 | 4710 | // The scope needs to have the decl in it. |
| 4907 | const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; | |
| 4908 | try sema.analyzeExport(&block_scope, export_src, options, decl_index); | |
| 4711 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); | |
| 4909 | 4712 | } |
| 4910 | 4713 | |
| 4911 | 4714 | return type_changed; |
| ... | ... | @@ -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 | 4736 | if (dependee.deletion_flag) { |
| 4938 | 4737 | dependee.deletion_flag = false; |
| 4939 | 4738 | assert(mod.deletion_set.swapRemove(dependee_index)); |
| ... | ... | @@ -5222,7 +5021,7 @@ pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void { |
| 5222 | 5021 | |
| 5223 | 5022 | pub fn scanNamespace( |
| 5224 | 5023 | mod: *Module, |
| 5225 | namespace: *Namespace, | |
| 5024 | namespace_index: Namespace.Index, | |
| 5226 | 5025 | extra_start: usize, |
| 5227 | 5026 | decls_len: u32, |
| 5228 | 5027 | parent_decl: *Decl, |
| ... | ... | @@ -5231,6 +5030,7 @@ pub fn scanNamespace( |
| 5231 | 5030 | defer tracy.end(); |
| 5232 | 5031 | |
| 5233 | 5032 | const gpa = mod.gpa; |
| 5033 | const namespace = mod.namespacePtr(namespace_index); | |
| 5234 | 5034 | const zir = namespace.file_scope.zir; |
| 5235 | 5035 | |
| 5236 | 5036 | try mod.comp.work_queue.ensureUnusedCapacity(decls_len); |
| ... | ... | @@ -5243,7 +5043,7 @@ pub fn scanNamespace( |
| 5243 | 5043 | var decl_i: u32 = 0; |
| 5244 | 5044 | var scan_decl_iter: ScanDeclIter = .{ |
| 5245 | 5045 | .module = mod, |
| 5246 | .namespace = namespace, | |
| 5046 | .namespace_index = namespace_index, | |
| 5247 | 5047 | .parent_decl = parent_decl, |
| 5248 | 5048 | }; |
| 5249 | 5049 | while (decl_i < decls_len) : (decl_i += 1) { |
| ... | ... | @@ -5266,7 +5066,7 @@ pub fn scanNamespace( |
| 5266 | 5066 | |
| 5267 | 5067 | const ScanDeclIter = struct { |
| 5268 | 5068 | module: *Module, |
| 5269 | namespace: *Namespace, | |
| 5069 | namespace_index: Namespace.Index, | |
| 5270 | 5070 | parent_decl: *Decl, |
| 5271 | 5071 | usingnamespace_index: usize = 0, |
| 5272 | 5072 | comptime_index: usize = 0, |
| ... | ... | @@ -5278,9 +5078,11 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5278 | 5078 | defer tracy.end(); |
| 5279 | 5079 | |
| 5280 | 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 | 5083 | const gpa = mod.gpa; |
| 5283 | 5084 | const zir = namespace.file_scope.zir; |
| 5085 | const ip = &mod.intern_pool; | |
| 5284 | 5086 | |
| 5285 | 5087 | // zig fmt: off |
| 5286 | 5088 | const is_pub = (flags & 0b0001) != 0; |
| ... | ... | @@ -5300,31 +5102,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5300 | 5102 | // Every Decl needs a name. |
| 5301 | 5103 | var is_named_test = false; |
| 5302 | 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 | 5106 | 0 => name: { |
| 5305 | 5107 | if (export_bit) { |
| 5306 | 5108 | const i = iter.usingnamespace_index; |
| 5307 | 5109 | iter.usingnamespace_index += 1; |
| 5308 | 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 | 5112 | } else { |
| 5311 | 5113 | const i = iter.comptime_index; |
| 5312 | 5114 | iter.comptime_index += 1; |
| 5313 | 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 | 5119 | 1 => name: { |
| 5318 | 5120 | const i = iter.unnamed_test_index; |
| 5319 | 5121 | iter.unnamed_test_index += 1; |
| 5320 | 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 | 5125 | 2 => name: { |
| 5324 | 5126 | is_named_test = true; |
| 5325 | 5127 | const test_name = zir.nullTerminatedString(decl_doccomment_index); |
| 5326 | 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 | 5131 | else => name: { |
| 5330 | 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 | 5134 | is_named_test = true; |
| 5333 | 5135 | const test_name = zir.nullTerminatedString(decl_name_index + 1); |
| 5334 | 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 | 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 | 5144 | const is_exported = export_bit and decl_name_index != 0; |
| 5345 | 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 | 5147 | // We create a Decl for it regardless of analysis status. |
| 5348 | 5148 | const gop = try namespace.decls.getOrPutContextAdapted( |
| 5349 | 5149 | gpa, |
| 5350 | @as([]const u8, mem.sliceTo(decl_name, 0)), | |
| 5150 | decl_name, | |
| 5351 | 5151 | DeclAdapter{ .mod = mod }, |
| 5352 | 5152 | Namespace.DeclContext{ .module = mod }, |
| 5353 | 5153 | ); |
| 5354 | 5154 | const comp = mod.comp; |
| 5355 | 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 | 5157 | const new_decl = mod.declPtr(new_decl_index); |
| 5358 | 5158 | new_decl.kind = kind; |
| 5359 | 5159 | new_decl.name = decl_name; |
| 5360 | must_free_decl_name = false; | |
| 5361 | 5160 | if (kind == .@"usingnamespace") { |
| 5362 | 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 | 5163 | new_decl.src_line = line; |
| 5366 | 5164 | gop.key_ptr.* = new_decl_index; |
| 5367 | 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 | 5180 | if (!comp.bin_file.options.is_test) break :blk false; |
| 5383 | 5181 | if (decl_pkg != mod.main_pkg) break :blk false; |
| 5384 | 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 | 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 | 5203 | const decl = mod.declPtr(decl_index); |
| 5406 | 5204 | if (kind == .@"test") { |
| 5407 | 5205 | const src_loc = SrcLoc{ |
| 5408 | .file_scope = decl.getFileScope(), | |
| 5206 | .file_scope = decl.getFileScope(mod), | |
| 5409 | 5207 | .parent_decl_node = decl.src_node, |
| 5410 | 5208 | .lazy = .{ .token_offset = 1 }, |
| 5411 | 5209 | }; |
| 5412 | const msg = try ErrorMsg.create( | |
| 5413 | gpa, | |
| 5414 | src_loc, | |
| 5415 | "duplicate test name: {s}", | |
| 5416 | .{decl_name}, | |
| 5417 | ); | |
| 5210 | const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{ | |
| 5211 | decl_name.fmt(&mod.intern_pool), | |
| 5212 | }); | |
| 5418 | 5213 | errdefer msg.destroy(gpa); |
| 5419 | 5214 | try mod.failed_decls.putNoClobber(gpa, decl_index, msg); |
| 5420 | 5215 | const other_src_loc = SrcLoc{ |
| ... | ... | @@ -5424,7 +5219,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5424 | 5219 | }; |
| 5425 | 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 | 5222 | // Update the AST node of the decl; even if its contents are unchanged, it may |
| 5429 | 5223 | // have been re-ordered. |
| 5430 | 5224 | decl.src_node = decl_node; |
| ... | ... | @@ -5436,7 +5230,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5436 | 5230 | decl.has_align = has_align; |
| 5437 | 5231 | decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5438 | 5232 | decl.zir_decl_index = @intCast(u32, decl_sub_index); |
| 5439 | if (decl.getFunction()) |_| { | |
| 5233 | if (decl.getOwnedFunctionIndex(mod) != .none) { | |
| 5440 | 5234 | switch (comp.bin_file.tag) { |
| 5441 | 5235 | .coff, .elf, .macho, .plan9 => { |
| 5442 | 5236 | // TODO Look into detecting when this would be unnecessary by storing enough state |
| ... | ... | @@ -5458,7 +5252,6 @@ pub fn clearDecl( |
| 5458 | 5252 | defer tracy.end(); |
| 5459 | 5253 | |
| 5460 | 5254 | const decl = mod.declPtr(decl_index); |
| 5461 | log.debug("clearing {*} ({s})", .{ decl, decl.name }); | |
| 5462 | 5255 | |
| 5463 | 5256 | const gpa = mod.gpa; |
| 5464 | 5257 | try mod.deletion_set.ensureUnusedCapacity(gpa, decl.dependencies.count()); |
| ... | ... | @@ -5473,9 +5266,6 @@ pub fn clearDecl( |
| 5473 | 5266 | const dep = mod.declPtr(dep_index); |
| 5474 | 5267 | dep.removeDependant(decl_index); |
| 5475 | 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 | 5269 | // We don't recursively perform a deletion here, because during the update, |
| 5480 | 5270 | // another reference to it may turn up. |
| 5481 | 5271 | dep.deletion_flag = true; |
| ... | ... | @@ -5510,10 +5300,10 @@ pub fn clearDecl( |
| 5510 | 5300 | try mod.deleteDeclExports(decl_index); |
| 5511 | 5301 | |
| 5512 | 5302 | if (decl.has_tv) { |
| 5513 | if (decl.ty.isFnOrHasRuntimeBits()) { | |
| 5303 | if (decl.ty.isFnOrHasRuntimeBits(mod)) { | |
| 5514 | 5304 | mod.comp.bin_file.freeDecl(decl_index); |
| 5515 | 5305 | } |
| 5516 | if (decl.getInnerNamespace()) |namespace| { | |
| 5306 | if (decl.getOwnedInnerNamespace(mod)) |namespace| { | |
| 5517 | 5307 | try namespace.deleteAllDecls(mod, outdated_decls); |
| 5518 | 5308 | } |
| 5519 | 5309 | } |
| ... | ... | @@ -5530,10 +5320,9 @@ pub fn clearDecl( |
| 5530 | 5320 | /// This function is exclusively called for anonymous decls. |
| 5531 | 5321 | pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { |
| 5532 | 5322 | const decl = mod.declPtr(decl_index); |
| 5533 | log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name }); | |
| 5534 | 5323 | |
| 5535 | 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 | 5327 | const dependants = decl.dependants.keys(); |
| 5539 | 5328 | for (dependants) |dep| { |
| ... | ... | @@ -5558,10 +5347,9 @@ fn markDeclForDeletion(mod: *Module, decl_index: Decl.Index) !void { |
| 5558 | 5347 | /// If other decls depend on this decl, they must be aborted first. |
| 5559 | 5348 | pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { |
| 5560 | 5349 | const decl = mod.declPtr(decl_index); |
| 5561 | log.debug("abortAnonDecl {*} ({s})", .{ decl, decl.name }); | |
| 5562 | 5350 | |
| 5563 | 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 | 5354 | // An aborted decl must not have dependants -- they must have |
| 5567 | 5355 | // been aborted first and removed from this list. |
| ... | ... | @@ -5575,6 +5363,17 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { |
| 5575 | 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 | 5377 | /// Delete all the Export objects that are caused by this Decl. Re-analysis of |
| 5579 | 5378 | /// this Decl will cause them to be re-created (or not). |
| 5580 | 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 | 5399 | } |
| 5601 | 5400 | } |
| 5602 | 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 | 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 | 5407 | if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| { |
| 5609 | 5408 | wasm.deleteDeclExport(decl_index); |
| 5610 | 5409 | } |
| 5611 | 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 | 5413 | if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { |
| 5615 | 5414 | failed_kv.value.destroy(mod.gpa); |
| 5616 | 5415 | } |
| 5617 | mod.gpa.free(exp.options.name); | |
| 5618 | 5416 | mod.gpa.destroy(exp); |
| 5619 | 5417 | } |
| 5620 | 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 | 5422 | const tracy = trace(@src()); |
| 5625 | 5423 | defer tracy.end(); |
| 5626 | 5424 | |
| 5627 | 5425 | const gpa = mod.gpa; |
| 5426 | const func = mod.funcPtr(func_index); | |
| 5628 | 5427 | const decl_index = func.owner_decl; |
| 5629 | 5428 | const decl = mod.declPtr(decl_index); |
| 5630 | 5429 | |
| 5631 | // Use the Decl's arena for captured values. | |
| 5632 | var decl_arena: std.heap.ArenaAllocator = undefined; | |
| 5633 | const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); | |
| 5634 | defer decl.value_arena.?.release(&decl_arena); | |
| 5430 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | |
| 5431 | defer comptime_mutable_decls.deinit(); | |
| 5432 | ||
| 5433 | const fn_ty = decl.ty; | |
| 5635 | 5434 | |
| 5636 | 5435 | var sema: Sema = .{ |
| 5637 | 5436 | .mod = mod, |
| 5638 | 5437 | .gpa = gpa, |
| 5639 | 5438 | .arena = arena, |
| 5640 | .perm_arena = decl_arena_allocator, | |
| 5641 | .code = decl.getFileScope().zir, | |
| 5439 | .code = decl.getFileScope(mod).zir, | |
| 5642 | 5440 | .owner_decl = decl, |
| 5643 | 5441 | .owner_decl_index = decl_index, |
| 5644 | 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 | 5445 | .owner_func = func, |
| 5446 | .owner_func_index = func_index.toOptional(), | |
| 5647 | 5447 | .branch_quota = @max(func.branch_quota, Sema.default_branch_quota), |
| 5448 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 5648 | 5449 | }; |
| 5649 | 5450 | defer sema.deinit(); |
| 5650 | 5451 | |
| ... | ... | @@ -5656,7 +5457,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5656 | 5457 | try sema.air_extra.ensureTotalCapacity(gpa, reserved_count); |
| 5657 | 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 | 5461 | defer wip_captures.deinit(); |
| 5661 | 5462 | |
| 5662 | 5463 | var inner_block: Sema.Block = .{ |
| ... | ... | @@ -5680,9 +5481,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5680 | 5481 | // This could be a generic function instantiation, however, in which case we need to |
| 5681 | 5482 | // map the comptime parameters to constant values and only emit arg AIR instructions |
| 5682 | 5483 | // for the runtime ones. |
| 5683 | const fn_ty = decl.ty; | |
| 5684 | const fn_ty_info = fn_ty.fnInfo(); | |
| 5685 | const runtime_params_len = @intCast(u32, fn_ty_info.param_types.len); | |
| 5484 | const runtime_params_len = @intCast(u32, mod.typeToFunc(fn_ty).?.param_types.len); | |
| 5686 | 5485 | try inner_block.instructions.ensureTotalCapacityPrecise(gpa, runtime_params_len); |
| 5687 | 5486 | try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType` |
| 5688 | 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 | 5496 | const param_ty = if (func.comptime_args) |comptime_args| t: { |
| 5698 | 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 | 5500 | arg_tv.val |
| 5702 | else if (arg_tv.ty.onePossibleValue()) |opv| | |
| 5501 | else if (try arg_tv.ty.onePossibleValue(mod)) |opv| | |
| 5703 | 5502 | opv |
| 5704 | 5503 | else |
| 5705 | 5504 | break :t arg_tv.ty; |
| ... | ... | @@ -5708,7 +5507,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5708 | 5507 | sema.inst_map.putAssumeCapacityNoClobber(inst, arg); |
| 5709 | 5508 | total_param_index += 1; |
| 5710 | 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 | 5512 | const opt_opv = sema.typeHasOnePossibleValue(param_ty) catch |err| switch (err) { |
| 5714 | 5513 | error.NeededSourceLocation => unreachable, |
| ... | ... | @@ -5740,7 +5539,6 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5740 | 5539 | } |
| 5741 | 5540 | |
| 5742 | 5541 | func.state = .in_progress; |
| 5743 | log.debug("set {s} to in_progress", .{decl.name}); | |
| 5744 | 5542 | |
| 5745 | 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 | 5563 | // is unused so it just has to be a no-op. |
| 5766 | 5564 | sema.air_instructions.set(ptr_inst.*, .{ |
| 5767 | 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 | 5571 | // If we don't get an error return trace from a caller, create our own. |
| 5774 | 5572 | if (func.calls_or_awaits_errorable_fn and |
| 5775 | 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 | 5576 | sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { |
| 5779 | 5577 | // TODO make these unreachable instead of @panic |
| ... | ... | @@ -5786,6 +5584,10 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5786 | 5584 | } |
| 5787 | 5585 | |
| 5788 | 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 | 5592 | // Copy the block into place and mark that as the main block. |
| 5791 | 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 | 5599 | sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = main_block_index; |
| 5798 | 5600 | |
| 5799 | 5601 | func.state = .success; |
| 5800 | log.debug("set {s} to success", .{decl.name}); | |
| 5801 | 5602 | |
| 5802 | 5603 | // Finally we must resolve the return type and parameter types so that backends |
| 5803 | 5604 | // have full access to type information. |
| 5804 | 5605 | // Crucially, this happens *after* we set the function state to success above, |
| 5805 | 5606 | // so that dependencies on the function body will now be satisfied rather than |
| 5806 | 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 | 5609 | error.NeededSourceLocation => unreachable, |
| 5809 | 5610 | error.GenericPoison => unreachable, |
| 5810 | 5611 | error.ComptimeReturn => unreachable, |
| ... | ... | @@ -5820,9 +5621,8 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5820 | 5621 | |
| 5821 | 5622 | // Similarly, resolve any queued up types that were requested to be resolved for |
| 5822 | 5623 | // the backends. |
| 5823 | for (sema.types_to_resolve.items) |inst_ref| { | |
| 5824 | const ty = sema.getTmpAir().getRefType(inst_ref); | |
| 5825 | sema.resolveTypeFully(ty) catch |err| switch (err) { | |
| 5624 | for (sema.types_to_resolve.keys()) |ty| { | |
| 5625 | sema.resolveTypeFully(ty.toType()) catch |err| switch (err) { | |
| 5826 | 5626 | error.NeededSourceLocation => unreachable, |
| 5827 | 5627 | error.GenericPoison => unreachable, |
| 5828 | 5628 | error.ComptimeReturn => unreachable, |
| ... | ... | @@ -5840,13 +5640,11 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5840 | 5640 | return Air{ |
| 5841 | 5641 | .instructions = sema.air_instructions.toOwnedSlice(), |
| 5842 | 5642 | .extra = try sema.air_extra.toOwnedSlice(gpa), |
| 5843 | .values = try sema.air_values.toOwnedSlice(gpa), | |
| 5844 | 5643 | }; |
| 5845 | 5644 | } |
| 5846 | 5645 | |
| 5847 | 5646 | fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 5848 | 5647 | const decl = mod.declPtr(decl_index); |
| 5849 | log.debug("mark outdated {*} ({s})", .{ decl, decl.name }); | |
| 5850 | 5648 | try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl_index }); |
| 5851 | 5649 | if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { |
| 5852 | 5650 | kv.value.destroy(mod.gpa); |
| ... | ... | @@ -5854,11 +5652,8 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 5854 | 5652 | if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { |
| 5855 | 5653 | for (kv.value) |err| err.deinit(mod.gpa); |
| 5856 | 5654 | } |
| 5857 | if (decl.has_tv and decl.owns_tv) { | |
| 5858 | if (decl.val.castTag(.function)) |payload| { | |
| 5859 | const func = payload.data; | |
| 5860 | _ = mod.align_stack_fns.remove(func); | |
| 5861 | } | |
| 5655 | if (decl.getOwnedFunctionIndex(mod).unwrap()) |func| { | |
| 5656 | _ = mod.align_stack_fns.remove(func); | |
| 5862 | 5657 | } |
| 5863 | 5658 | if (mod.emit_h) |emit_h| { |
| 5864 | 5659 | if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { |
| ... | ... | @@ -5869,9 +5664,51 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 5869 | 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 | 5709 | pub fn allocateNewDecl( |
| 5873 | 5710 | mod: *Module, |
| 5874 | namespace: *Namespace, | |
| 5711 | namespace: Namespace.Index, | |
| 5875 | 5712 | src_node: Ast.Node.Index, |
| 5876 | 5713 | src_scope: ?*CaptureScope, |
| 5877 | 5714 | ) !Decl.Index { |
| ... | ... | @@ -5896,6 +5733,7 @@ pub fn allocateNewDecl( |
| 5896 | 5733 | }; |
| 5897 | 5734 | }; |
| 5898 | 5735 | |
| 5736 | if (src_scope) |scope| scope.incRef(); | |
| 5899 | 5737 | decl_and_index.new_decl.* = .{ |
| 5900 | 5738 | .name = undefined, |
| 5901 | 5739 | .src_namespace = namespace, |
| ... | ... | @@ -5906,7 +5744,7 @@ pub fn allocateNewDecl( |
| 5906 | 5744 | .ty = undefined, |
| 5907 | 5745 | .val = undefined, |
| 5908 | 5746 | .@"align" = undefined, |
| 5909 | .@"linksection" = undefined, | |
| 5747 | .@"linksection" = .none, | |
| 5910 | 5748 | .@"addrspace" = .generic, |
| 5911 | 5749 | .analysis = .unreferenced, |
| 5912 | 5750 | .deletion_flag = false, |
| ... | ... | @@ -5924,25 +5762,20 @@ pub fn allocateNewDecl( |
| 5924 | 5762 | return decl_and_index.decl_index; |
| 5925 | 5763 | } |
| 5926 | 5764 | |
| 5927 | /// Get error value for error tag `name`. | |
| 5928 | pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(ErrorInt).KV { | |
| 5765 | pub fn getErrorValue( | |
| 5766 | mod: *Module, | |
| 5767 | name: InternPool.NullTerminatedString, | |
| 5768 | ) Allocator.Error!ErrorInt { | |
| 5929 | 5769 | const gop = try mod.global_error_set.getOrPut(mod.gpa, name); |
| 5930 | if (gop.found_existing) { | |
| 5931 | return std.StringHashMapUnmanaged(ErrorInt).KV{ | |
| 5932 | .key = gop.key_ptr.*, | |
| 5933 | .value = gop.value_ptr.*, | |
| 5934 | }; | |
| 5935 | } | |
| 5770 | return @intCast(ErrorInt, gop.index); | |
| 5771 | } | |
| 5936 | 5772 | |
| 5937 | errdefer assert(mod.global_error_set.remove(name)); | |
| 5938 | try mod.error_name_list.ensureUnusedCapacity(mod.gpa, 1); | |
| 5939 | gop.key_ptr.* = try mod.gpa.dupe(u8, name); | |
| 5940 | gop.value_ptr.* = @intCast(ErrorInt, mod.error_name_list.items.len); | |
| 5941 | mod.error_name_list.appendAssumeCapacity(gop.key_ptr.*); | |
| 5942 | return std.StringHashMapUnmanaged(ErrorInt).KV{ | |
| 5943 | .key = gop.key_ptr.*, | |
| 5944 | .value = gop.value_ptr.*, | |
| 5945 | }; | |
| 5773 | pub fn getErrorValueFromSlice( | |
| 5774 | mod: *Module, | |
| 5775 | name: []const u8, | |
| 5776 | ) Allocator.Error!ErrorInt { | |
| 5777 | const interned_name = try mod.intern_pool.getOrPutString(mod.gpa, name); | |
| 5778 | return getErrorValue(mod, interned_name); | |
| 5946 | 5779 | } |
| 5947 | 5780 | |
| 5948 | 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 | 5786 | pub fn createAnonymousDeclFromDecl( |
| 5954 | 5787 | mod: *Module, |
| 5955 | 5788 | src_decl: *Decl, |
| 5956 | namespace: *Namespace, | |
| 5789 | namespace: Namespace.Index, | |
| 5957 | 5790 | src_scope: ?*CaptureScope, |
| 5958 | 5791 | tv: TypedValue, |
| 5959 | 5792 | ) !Decl.Index { |
| 5960 | 5793 | const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope); |
| 5961 | 5794 | errdefer mod.destroyDecl(new_decl_index); |
| 5962 | const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ | |
| 5963 | src_decl.name, @enumToInt(new_decl_index), | |
| 5795 | const name = try mod.intern_pool.getOrPutStringFmt(mod.gpa, "{}__anon_{d}", .{ | |
| 5796 | src_decl.name.fmt(&mod.intern_pool), @enumToInt(new_decl_index), | |
| 5964 | 5797 | }); |
| 5965 | 5798 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, tv, name); |
| 5966 | 5799 | return new_decl_index; |
| 5967 | 5800 | } |
| 5968 | 5801 | |
| 5969 | /// Takes ownership of `name` even if it returns an error. | |
| 5970 | 5802 | pub fn initNewAnonDecl( |
| 5971 | 5803 | mod: *Module, |
| 5972 | 5804 | new_decl_index: Decl.Index, |
| 5973 | 5805 | src_line: u32, |
| 5974 | namespace: *Namespace, | |
| 5806 | namespace: Namespace.Index, | |
| 5975 | 5807 | typed_value: TypedValue, |
| 5976 | name: [:0]u8, | |
| 5977 | ) !void { | |
| 5978 | errdefer mod.gpa.free(name); | |
| 5808 | name: InternPool.NullTerminatedString, | |
| 5809 | ) Allocator.Error!void { | |
| 5810 | assert(typed_value.ty.toIntern() == mod.intern_pool.typeOf(typed_value.val.toIntern())); | |
| 5979 | 5811 | |
| 5980 | 5812 | const new_decl = mod.declPtr(new_decl_index); |
| 5981 | 5813 | |
| ... | ... | @@ -5984,34 +5816,12 @@ pub fn initNewAnonDecl( |
| 5984 | 5816 | new_decl.ty = typed_value.ty; |
| 5985 | 5817 | new_decl.val = typed_value.val; |
| 5986 | 5818 | new_decl.@"align" = 0; |
| 5987 | new_decl.@"linksection" = null; | |
| 5819 | new_decl.@"linksection" = .none; | |
| 5988 | 5820 | new_decl.has_tv = true; |
| 5989 | 5821 | new_decl.analysis = .complete; |
| 5990 | 5822 | new_decl.generation = mod.generation; |
| 5991 | 5823 | |
| 5992 | try 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); | |
| 5824 | try mod.namespacePtr(namespace).anon_decls.putNoClobber(mod.gpa, new_decl_index, {}); | |
| 6015 | 5825 | } |
| 6016 | 5826 | |
| 6017 | 5827 | pub fn errNoteNonLazy( |
| ... | ... | @@ -6073,16 +5883,17 @@ pub const SwitchProngSrc = union(enum) { |
| 6073 | 5883 | /// the LazySrcLoc in order to emit a compile error. |
| 6074 | 5884 | pub fn resolve( |
| 6075 | 5885 | prong_src: SwitchProngSrc, |
| 6076 | gpa: Allocator, | |
| 5886 | mod: *Module, | |
| 6077 | 5887 | decl: *Decl, |
| 6078 | 5888 | switch_node_offset: i32, |
| 6079 | 5889 | range_expand: RangeExpand, |
| 6080 | 5890 | ) LazySrcLoc { |
| 6081 | 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 | 5894 | // In this case we emit a warning + a less precise source location. |
| 6084 | 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 | 5898 | return LazySrcLoc.nodeOffset(0); |
| 6088 | 5899 | }; |
| ... | ... | @@ -6166,11 +5977,12 @@ pub const PeerTypeCandidateSrc = union(enum) { |
| 6166 | 5977 | |
| 6167 | 5978 | pub fn resolve( |
| 6168 | 5979 | self: PeerTypeCandidateSrc, |
| 6169 | gpa: Allocator, | |
| 5980 | mod: *Module, | |
| 6170 | 5981 | decl: *Decl, |
| 6171 | 5982 | candidate_i: usize, |
| 6172 | 5983 | ) ?LazySrcLoc { |
| 6173 | 5984 | @setCold(true); |
| 5985 | const gpa = mod.gpa; | |
| 6174 | 5986 | |
| 6175 | 5987 | switch (self) { |
| 6176 | 5988 | .none => { |
| ... | ... | @@ -6192,10 +6004,10 @@ pub const PeerTypeCandidateSrc = union(enum) { |
| 6192 | 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 | 6008 | // In this case we emit a warning + a less precise source location. |
| 6197 | 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 | 6012 | return LazySrcLoc.nodeOffset(0); |
| 6201 | 6013 | }; |
| ... | ... | @@ -6254,15 +6066,16 @@ fn queryFieldSrc( |
| 6254 | 6066 | |
| 6255 | 6067 | pub fn paramSrc( |
| 6256 | 6068 | func_node_offset: i32, |
| 6257 | gpa: Allocator, | |
| 6069 | mod: *Module, | |
| 6258 | 6070 | decl: *Decl, |
| 6259 | 6071 | param_i: usize, |
| 6260 | 6072 | ) LazySrcLoc { |
| 6261 | 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 | 6076 | // In this case we emit a warning + a less precise source location. |
| 6264 | 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 | 6080 | return LazySrcLoc.nodeOffset(0); |
| 6268 | 6081 | }; |
| ... | ... | @@ -6284,19 +6097,20 @@ pub fn paramSrc( |
| 6284 | 6097 | } |
| 6285 | 6098 | |
| 6286 | 6099 | pub fn argSrc( |
| 6100 | mod: *Module, | |
| 6287 | 6101 | call_node_offset: i32, |
| 6288 | gpa: Allocator, | |
| 6289 | 6102 | decl: *Decl, |
| 6290 | 6103 | start_arg_i: usize, |
| 6291 | 6104 | bound_arg_src: ?LazySrcLoc, |
| 6292 | 6105 | ) LazySrcLoc { |
| 6106 | @setCold(true); | |
| 6107 | const gpa = mod.gpa; | |
| 6293 | 6108 | if (start_arg_i == 0 and bound_arg_src != null) return bound_arg_src.?; |
| 6294 | 6109 | const arg_i = start_arg_i - @boolToInt(bound_arg_src != null); |
| 6295 | @setCold(true); | |
| 6296 | const tree = decl.getFileScope().getTree(gpa) catch |err| { | |
| 6110 | const tree = decl.getFileScope(mod).getTree(gpa) catch |err| { | |
| 6297 | 6111 | // In this case we emit a warning + a less precise source location. |
| 6298 | 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 | 6115 | return LazySrcLoc.nodeOffset(0); |
| 6302 | 6116 | }; |
| ... | ... | @@ -6310,7 +6124,7 @@ pub fn argSrc( |
| 6310 | 6124 | const node_datas = tree.nodes.items(.data); |
| 6311 | 6125 | const call_args_node = tree.extra_data[node_datas[node].rhs - 1]; |
| 6312 | 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 | 6129 | else => unreachable, |
| 6316 | 6130 | }; |
| ... | ... | @@ -6318,16 +6132,17 @@ pub fn argSrc( |
| 6318 | 6132 | } |
| 6319 | 6133 | |
| 6320 | 6134 | pub fn initSrc( |
| 6135 | mod: *Module, | |
| 6321 | 6136 | init_node_offset: i32, |
| 6322 | gpa: Allocator, | |
| 6323 | 6137 | decl: *Decl, |
| 6324 | 6138 | init_index: usize, |
| 6325 | 6139 | ) LazySrcLoc { |
| 6326 | 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 | 6143 | // In this case we emit a warning + a less precise source location. |
| 6329 | 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 | 6147 | return LazySrcLoc.nodeOffset(0); |
| 6333 | 6148 | }; |
| ... | ... | @@ -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 | 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 | 6185 | // In this case we emit a warning + a less precise source location. |
| 6370 | 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 | 6189 | return LazySrcLoc.nodeOffset(0); |
| 6374 | 6190 | }; |
| ... | ... | @@ -6430,11 +6246,13 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { |
| 6430 | 6246 | // deletion set at this time. |
| 6431 | 6247 | for (file.deleted_decls.items) |decl_index| { |
| 6432 | 6248 | const decl = mod.declPtr(decl_index); |
| 6433 | log.debug("deleted from source: {*} ({s})", .{ decl, decl.name }); | |
| 6434 | 6249 | |
| 6435 | 6250 | // Remove from the namespace it resides in, preserving declaration order. |
| 6436 | 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 | 6257 | try mod.clearDecl(decl_index, &outdated_decls); |
| 6440 | 6258 | mod.destroyDecl(decl_index); |
| ... | ... | @@ -6454,7 +6272,7 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { |
| 6454 | 6272 | pub fn processExports(mod: *Module) !void { |
| 6455 | 6273 | const gpa = mod.gpa; |
| 6456 | 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 | 6276 | defer symbol_exports.deinit(gpa); |
| 6459 | 6277 | |
| 6460 | 6278 | var it = mod.decl_exports.iterator(); |
| ... | ... | @@ -6462,13 +6280,13 @@ pub fn processExports(mod: *Module) !void { |
| 6462 | 6280 | const exported_decl = entry.key_ptr.*; |
| 6463 | 6281 | const exports = entry.value_ptr.items; |
| 6464 | 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 | 6284 | if (gop.found_existing) { |
| 6467 | 6285 | new_export.status = .failed_retryable; |
| 6468 | 6286 | try mod.failed_exports.ensureUnusedCapacity(gpa, 1); |
| 6469 | 6287 | const src_loc = new_export.getSrcLoc(mod); |
| 6470 | const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {s}", .{ | |
| 6471 | new_export.options.name, | |
| 6288 | const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{ | |
| 6289 | new_export.opts.name.fmt(&mod.intern_pool), | |
| 6472 | 6290 | }); |
| 6473 | 6291 | errdefer msg.destroy(gpa); |
| 6474 | 6292 | const other_export = gop.value_ptr.*; |
| ... | ... | @@ -6501,11 +6319,16 @@ pub fn populateTestFunctions( |
| 6501 | 6319 | main_progress_node: *std.Progress.Node, |
| 6502 | 6320 | ) !void { |
| 6503 | 6321 | const gpa = mod.gpa; |
| 6322 | const ip = &mod.intern_pool; | |
| 6504 | 6323 | const builtin_pkg = mod.main_pkg.table.get("builtin").?; |
| 6505 | 6324 | const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file; |
| 6506 | 6325 | const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); |
| 6507 | const builtin_namespace = root_decl.src_namespace; | |
| 6508 | const decl_index = builtin_namespace.decls.getKeyAdapted(@as([]const u8, "test_functions"), DeclAdapter{ .mod = mod }).?; | |
| 6326 | const builtin_namespace = mod.namespacePtr(root_decl.src_namespace); | |
| 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 | 6333 | // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` |
| 6511 | 6334 | // was not referenced by start code. |
| ... | ... | @@ -6518,90 +6341,117 @@ pub fn populateTestFunctions( |
| 6518 | 6341 | try mod.ensureDeclAnalyzed(decl_index); |
| 6519 | 6342 | } |
| 6520 | 6343 | const decl = mod.declPtr(decl_index); |
| 6521 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 6522 | const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType(); | |
| 6344 | const test_fn_ty = decl.ty.slicePtrFieldType(mod).childType(mod); | |
| 6345 | const null_usize = try mod.intern(.{ .opt = .{ | |
| 6346 | .ty = try mod.intern(.{ .opt_type = .usize_type }), | |
| 6347 | .val = .none, | |
| 6348 | } }); | |
| 6523 | 6349 | |
| 6524 | 6350 | const array_decl_index = d: { |
| 6525 | 6351 | // Add mod.test_functions to an array decl then make the test_functions |
| 6526 | 6352 | // decl reference it as a slice. |
| 6527 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | |
| 6528 | errdefer new_decl_arena.deinit(); | |
| 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); | |
| 6353 | const test_fn_vals = try gpa.alloc(InternPool.Index, mod.test_functions.count()); | |
| 6354 | defer gpa.free(test_fn_vals); | |
| 6540 | 6355 | |
| 6541 | 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 | 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 | 6366 | const test_name_decl_index = n: { |
| 6548 | var name_decl_arena = std.heap.ArenaAllocator.init(gpa); | |
| 6549 | errdefer name_decl_arena.deinit(); | |
| 6550 | const bytes = try name_decl_arena.allocator().dupe(u8, test_name_slice); | |
| 6551 | const test_name_decl_index = try mod.createAnonymousDeclFromDecl(array_decl, array_decl.src_namespace, null, .{ | |
| 6552 | .ty = try Type.Tag.array_u8.create(name_decl_arena.allocator(), bytes.len), | |
| 6553 | .val = try Value.Tag.bytes.create(name_decl_arena.allocator(), bytes), | |
| 6367 | const test_name_decl_ty = try mod.arrayType(.{ | |
| 6368 | .len = test_decl_name.len, | |
| 6369 | .child = .u8_type, | |
| 6370 | }); | |
| 6371 | const test_name_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{ | |
| 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 | 6378 | break :n test_name_decl_index; |
| 6557 | 6379 | }; |
| 6558 | array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, .normal); | |
| 6559 | array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, .normal); | |
| 6380 | array_decl_dependencies.appendAssumeCapacity(test_decl_index); | |
| 6381 | array_decl_dependencies.appendAssumeCapacity(test_name_decl_index); | |
| 6560 | 6382 | try mod.linkerUpdateDecl(test_name_decl_index); |
| 6561 | 6383 | |
| 6562 | const field_vals = try arena.create([3]Value); | |
| 6563 | field_vals.* = .{ | |
| 6564 | try Value.Tag.slice.create(arena, .{ | |
| 6565 | .ptr = try Value.Tag.decl_ref.create(arena, test_name_decl_index), | |
| 6566 | .len = try Value.Tag.int_u64.create(arena, test_name_slice.len), | |
| 6567 | }), // name | |
| 6568 | try Value.Tag.decl_ref.create(arena, test_decl_index), // func | |
| 6569 | Value.initTag(.null_value), // async_frame_size | |
| 6384 | const test_fn_fields = .{ | |
| 6385 | // name | |
| 6386 | try mod.intern(.{ .ptr = .{ | |
| 6387 | .ty = .slice_const_u8_type, | |
| 6388 | .addr = .{ .decl = test_name_decl_index }, | |
| 6389 | .len = try mod.intern(.{ .int = .{ | |
| 6390 | .ty = .usize_type, | |
| 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 | 6429 | break :d array_decl_index; |
| 6576 | 6430 | }; |
| 6577 | 6431 | try mod.linkerUpdateDecl(array_decl_index); |
| 6578 | 6432 | |
| 6579 | 6433 | { |
| 6580 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | |
| 6581 | errdefer new_decl_arena.deinit(); | |
| 6582 | const arena = new_decl_arena.allocator(); | |
| 6583 | ||
| 6584 | { | |
| 6585 | // This copy accesses the old Decl Type/Value so it must be done before `clearValues`. | |
| 6586 | const new_ty = try Type.Tag.const_slice.create(arena, try tmp_test_fn_ty.copy(arena)); | |
| 6587 | const new_var = try gpa.create(Var); | |
| 6588 | errdefer gpa.destroy(new_var); | |
| 6589 | new_var.* = decl.val.castTag(.variable).?.data.*; | |
| 6590 | new_var.init = try Value.Tag.slice.create(arena, .{ | |
| 6591 | .ptr = try Value.Tag.decl_ref.create(arena, array_decl_index), | |
| 6592 | .len = try Value.Tag.int_u64.create(arena, mod.test_functions.count()), | |
| 6593 | }); | |
| 6594 | const new_val = try Value.Tag.variable.create(arena, new_var); | |
| 6595 | ||
| 6596 | // Since we are replacing the Decl's value we must perform cleanup on the | |
| 6597 | // previous value. | |
| 6598 | decl.clearValues(mod); | |
| 6599 | decl.ty = new_ty; | |
| 6600 | decl.val = new_val; | |
| 6601 | decl.has_tv = true; | |
| 6602 | } | |
| 6603 | ||
| 6604 | try decl.finalizeNewArena(&new_decl_arena); | |
| 6434 | const new_ty = try mod.ptrType(.{ | |
| 6435 | .child = test_fn_ty.toIntern(), | |
| 6436 | .flags = .{ | |
| 6437 | .is_const = true, | |
| 6438 | .size = .Slice, | |
| 6439 | }, | |
| 6440 | }); | |
| 6441 | const new_val = decl.val; | |
| 6442 | const new_init = try mod.intern(.{ .ptr = .{ | |
| 6443 | .ty = new_ty.toIntern(), | |
| 6444 | .addr = .{ .decl = array_decl_index }, | |
| 6445 | .len = (try mod.intValue(Type.usize, mod.test_functions.count())).toIntern(), | |
| 6446 | } }); | |
| 6447 | ip.mutateVarInit(decl.val.toIntern(), new_init); | |
| 6448 | ||
| 6449 | // Since we are replacing the Decl's value we must perform cleanup on the | |
| 6450 | // previous value. | |
| 6451 | decl.clearValues(mod); | |
| 6452 | decl.ty = new_ty; | |
| 6453 | decl.val = new_val; | |
| 6454 | decl.has_tv = true; | |
| 6605 | 6455 | } |
| 6606 | 6456 | try mod.linkerUpdateDecl(decl_index); |
| 6607 | 6457 | } |
| ... | ... | @@ -6631,7 +6481,7 @@ pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 6631 | 6481 | try mod.failed_decls.ensureUnusedCapacity(gpa, 1); |
| 6632 | 6482 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 6633 | 6483 | gpa, |
| 6634 | decl.srcLoc(), | |
| 6484 | decl.srcLoc(mod), | |
| 6635 | 6485 | "unable to codegen: {s}", |
| 6636 | 6486 | .{@errorName(err)}, |
| 6637 | 6487 | )); |
| ... | ... | @@ -6673,64 +6523,49 @@ fn reportRetryableFileError( |
| 6673 | 6523 | gop.value_ptr.* = err_msg; |
| 6674 | 6524 | } |
| 6675 | 6525 | |
| 6676 | pub fn markReferencedDeclsAlive(mod: *Module, val: Value) void { | |
| 6677 | switch (val.tag()) { | |
| 6678 | .decl_ref_mut => return mod.markDeclIndexAlive(val.castTag(.decl_ref_mut).?.data.decl_index), | |
| 6679 | .extern_fn => return mod.markDeclIndexAlive(val.castTag(.extern_fn).?.data.owner_decl), | |
| 6680 | .function => return mod.markDeclIndexAlive(val.castTag(.function).?.data.owner_decl), | |
| 6681 | .variable => return mod.markDeclIndexAlive(val.castTag(.variable).?.data.owner_decl), | |
| 6682 | .decl_ref => return mod.markDeclIndexAlive(val.cast(Value.Payload.Decl).?.data), | |
| 6683 | ||
| 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); | |
| 6526 | pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void { | |
| 6527 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 6528 | .variable => |variable| try mod.markDeclIndexAlive(variable.decl), | |
| 6529 | .extern_func => |extern_func| try mod.markDeclIndexAlive(extern_func.decl), | |
| 6530 | .func => |func| try mod.markDeclIndexAlive(mod.funcPtr(func.index).owner_decl), | |
| 6531 | .error_union => |error_union| switch (error_union.val) { | |
| 6532 | .err_name => {}, | |
| 6533 | .payload => |payload| try mod.markReferencedDeclsAlive(payload.toValue()), | |
| 6707 | 6534 | }, |
| 6708 | .aggregate => { | |
| 6709 | for (val.castTag(.aggregate).?.data) |field_val| { | |
| 6710 | mod.markReferencedDeclsAlive(field_val); | |
| 6535 | .ptr => |ptr| { | |
| 6536 | switch (ptr.addr) { | |
| 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" => { | |
| 6714 | const data = val.cast(Value.Payload.Union).?.data; | |
| 6715 | mod.markReferencedDeclsAlive(data.tag); | |
| 6716 | mod.markReferencedDeclsAlive(data.val); | |
| 6545 | .opt => |opt| if (opt.val != .none) try mod.markReferencedDeclsAlive(opt.val.toValue()), | |
| 6546 | .aggregate => |aggregate| for (aggregate.storage.values()) |elem| | |
| 6547 | try mod.markReferencedDeclsAlive(elem.toValue()), | |
| 6548 | .un => |un| { | |
| 6549 | try mod.markReferencedDeclsAlive(un.tag.toValue()); | |
| 6550 | try mod.markReferencedDeclsAlive(un.val.toValue()); | |
| 6717 | 6551 | }, |
| 6718 | ||
| 6719 | 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 | 6557 | if (decl.alive) return; |
| 6725 | 6558 | decl.alive = true; |
| 6726 | 6559 | |
| 6560 | try decl.intern(mod); | |
| 6561 | ||
| 6727 | 6562 | // This is the first time we are marking this Decl alive. We must |
| 6728 | 6563 | // therefore recurse into its value and mark any Decl it references |
| 6729 | 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 | 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 | 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 | 1 | const std = @import("std"); |
| 2 | const assert = std.debug.assert; | |
| 2 | 3 | const Order = std.math.Order; |
| 3 | 4 | |
| 4 | const RangeSet = @This(); | |
| 5 | const InternPool = @import("InternPool.zig"); | |
| 5 | 6 | const Module = @import("Module.zig"); |
| 7 | const RangeSet = @This(); | |
| 6 | 8 | const SwitchProngSrc = @import("Module.zig").SwitchProngSrc; |
| 7 | const Type = @import("type.zig").Type; | |
| 8 | const Value = @import("value.zig").Value; | |
| 9 | 9 | |
| 10 | 10 | ranges: std.ArrayList(Range), |
| 11 | 11 | module: *Module, |
| 12 | 12 | |
| 13 | 13 | pub const Range = struct { |
| 14 | first: Value, | |
| 15 | last: Value, | |
| 14 | first: InternPool.Index, | |
| 15 | last: InternPool.Index, | |
| 16 | 16 | src: SwitchProngSrc, |
| 17 | 17 | }; |
| 18 | 18 | |
| ... | ... | @@ -29,18 +29,27 @@ pub fn deinit(self: *RangeSet) void { |
| 29 | 29 | |
| 30 | 30 | pub fn add( |
| 31 | 31 | self: *RangeSet, |
| 32 | first: Value, | |
| 33 | last: Value, | |
| 34 | ty: Type, | |
| 32 | first: InternPool.Index, | |
| 33 | last: InternPool.Index, | |
| 35 | 34 | src: SwitchProngSrc, |
| 36 | 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 | 42 | for (self.ranges.items) |range| { |
| 38 | if (last.compareAll(.gte, range.first, ty, self.module) and | |
| 39 | first.compareAll(.lte, range.last, ty, self.module)) | |
| 43 | assert(ty == ip.typeOf(range.first)); | |
| 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 | 49 | return range.src; // They overlap. |
| 42 | 50 | } |
| 43 | 51 | } |
| 52 | ||
| 44 | 53 | try self.ranges.append(.{ |
| 45 | 54 | .first = first, |
| 46 | 55 | .last = last, |
| ... | ... | @@ -49,45 +58,43 @@ pub fn add( |
| 49 | 58 | return null; |
| 50 | 59 | } |
| 51 | 60 | |
| 52 | const LessThanContext = struct { ty: Type, module: *Module }; | |
| 53 | ||
| 54 | 61 | /// Assumes a and b do not overlap |
| 55 | fn lessThan(ctx: LessThanContext, a: Range, b: Range) bool { | |
| 56 | return a.first.compareAll(.lt, b.first, ctx.ty, ctx.module); | |
| 62 | fn lessThan(mod: *Module, a: Range, b: Range) bool { | |
| 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 | 72 | if (self.ranges.items.len == 0) |
| 61 | 73 | return false; |
| 62 | 74 | |
| 63 | std.mem.sort(Range, self.ranges.items, LessThanContext{ | |
| 64 | .ty = ty, | |
| 65 | .module = self.module, | |
| 66 | }, lessThan); | |
| 75 | std.mem.sort(Range, self.ranges.items, mod, lessThan); | |
| 67 | 76 | |
| 68 | if (!self.ranges.items[0].first.eql(first, ty, self.module) or | |
| 69 | !self.ranges.items[self.ranges.items.len - 1].last.eql(last, ty, self.module)) | |
| 77 | if (self.ranges.items[0].first != first or | |
| 78 | self.ranges.items[self.ranges.items.len - 1].last != last) | |
| 70 | 79 | { |
| 71 | 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 | 85 | var counter = try std.math.big.int.Managed.init(self.ranges.allocator); |
| 77 | 86 | defer counter.deinit(); |
| 78 | 87 | |
| 79 | const target = self.module.getTarget(); | |
| 80 | ||
| 81 | 88 | // look for gaps |
| 82 | 89 | for (self.ranges.items[1..], 0..) |cur, i| { |
| 83 | 90 | // i starts counting from the second item. |
| 84 | 91 | const prev = self.ranges.items[i]; |
| 85 | 92 | |
| 86 | 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 | 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 | 98 | if (!cur_start_int.eq(counter.toConst())) { |
| 92 | 99 | return false; |
| 93 | 100 | } |
src/Sema.zig+8816-8097| ... | ... | @@ -11,13 +11,9 @@ gpa: Allocator, |
| 11 | 11 | /// Points to the temporary arena allocator of the Sema. |
| 12 | 12 | /// This arena will be cleared when the sema is destroyed. |
| 13 | 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 | 14 | code: Zir, |
| 18 | 15 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, |
| 19 | 16 | air_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 20 | air_values: std.ArrayListUnmanaged(Value) = .{}, | |
| 21 | 17 | /// Maps ZIR to AIR. |
| 22 | 18 | inst_map: InstMap = .{}, |
| 23 | 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 | 24 | /// For an inline or comptime function call, this will be the root parent function |
| 29 | 25 | /// which contains the callsite. Corresponds to `owner_decl`. |
| 30 | 26 | owner_func: ?*Module.Fn, |
| 27 | owner_func_index: Module.Fn.OptionalIndex, | |
| 31 | 28 | /// The function this ZIR code is the body of, according to the source code. |
| 32 | 29 | /// This starts out the same as `owner_func` and then diverges in the case of |
| 33 | 30 | /// an inline or comptime function call. |
| 34 | 31 | func: ?*Module.Fn, |
| 32 | func_index: Module.Fn.OptionalIndex, | |
| 35 | 33 | /// Used to restore the error return trace when returning a non-error from a function. |
| 36 | 34 | error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none, |
| 37 | 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 | 63 | /// to use this instead of allocating a fresh one. This avoids an unnecessary |
| 66 | 64 | /// extra hash table lookup in the `monomorphed_funcs` set. |
| 67 | 65 | /// Sema will set this to null when it takes ownership. |
| 68 | preallocated_new_func: ?*Module.Fn = null, | |
| 69 | /// The key is `constant` AIR instructions to types that must be fully resolved | |
| 70 | /// after the current function body analysis is done. | |
| 71 | /// TODO: after upgrading to use InternPool change the key here to be an | |
| 72 | /// InternPool value index. | |
| 73 | types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{}, | |
| 66 | preallocated_new_func: Module.Fn.OptionalIndex = .none, | |
| 67 | /// The key is types that must be fully resolved prior to machine code | |
| 68 | /// generation pass. Types are added to this set when resolving them | |
| 69 | /// immediately could cause a dependency loop, but they do need to be resolved | |
| 70 | /// before machine code generation passes process the AIR. | |
| 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 | 75 | /// These are lazily created runtime blocks from block_inline instructions. |
| 75 | 76 | /// They are created when an break_inline passes through a runtime condition, because |
| 76 | 77 | /// Sema must convert comptime control flow to runtime control flow, which means |
| ... | ... | @@ -84,12 +85,22 @@ is_generic_instantiation: bool = false, |
| 84 | 85 | /// function types will emit generic poison instead of a partial type. |
| 85 | 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 | 100 | const std = @import("std"); |
| 90 | 101 | const math = std.math; |
| 91 | 102 | const mem = std.mem; |
| 92 | const Allocator = std.mem.Allocator; | |
| 103 | const Allocator = mem.Allocator; | |
| 93 | 104 | const assert = std.debug.assert; |
| 94 | 105 | const log = std.log.scoped(.sema); |
| 95 | 106 | |
| ... | ... | @@ -114,6 +125,7 @@ const Package = @import("Package.zig"); |
| 114 | 125 | const crash_report = @import("crash_report.zig"); |
| 115 | 126 | const build_options = @import("build_options"); |
| 116 | 127 | const Compilation = @import("Compilation.zig"); |
| 128 | const InternPool = @import("InternPool.zig"); | |
| 117 | 129 | |
| 118 | 130 | pub const default_branch_quota = 1000; |
| 119 | 131 | pub const default_reference_trace_len = 2; |
| ... | ... | @@ -226,7 +238,7 @@ pub const Block = struct { |
| 226 | 238 | sema: *Sema, |
| 227 | 239 | /// The namespace to use for lookups from this source block |
| 228 | 240 | /// When analyzing fields, this is different from src_decl.src_namespace. |
| 229 | namespace: *Namespace, | |
| 241 | namespace: Namespace.Index, | |
| 230 | 242 | /// The AIR instructions generated for this block. |
| 231 | 243 | instructions: std.ArrayListUnmanaged(Air.Inst.Index), |
| 232 | 244 | // `param` instructions are collected here to be used by the `func` instruction. |
| ... | ... | @@ -285,6 +297,7 @@ pub const Block = struct { |
| 285 | 297 | |
| 286 | 298 | fn explain(cr: ComptimeReason, sema: *Sema, msg: ?*Module.ErrorMsg) !void { |
| 287 | 299 | const parent = msg orelse return; |
| 300 | const mod = sema.mod; | |
| 288 | 301 | const prefix = "expression is evaluated at comptime because "; |
| 289 | 302 | switch (cr) { |
| 290 | 303 | .c_import => |ci| { |
| ... | ... | @@ -292,21 +305,21 @@ pub const Block = struct { |
| 292 | 305 | }, |
| 293 | 306 | .comptime_ret_ty => |rt| { |
| 294 | 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 | 309 | src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 297 | 310 | break :blk src_loc; |
| 298 | 311 | } else blk: { |
| 299 | const src_decl = sema.mod.declPtr(rt.block.src_decl); | |
| 300 | break :blk rt.func_src.toSrcLoc(src_decl); | |
| 312 | const src_decl = mod.declPtr(rt.block.src_decl); | |
| 313 | break :blk rt.func_src.toSrcLoc(src_decl, mod); | |
| 301 | 314 | }; |
| 302 | if (rt.return_ty.tag() == .generic_poison) { | |
| 303 | return sema.mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{}); | |
| 315 | if (rt.return_ty.isGenericPoison()) { | |
| 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 | 319 | src_loc, |
| 307 | 320 | parent, |
| 308 | 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 | 324 | try sema.explainWhyTypeIsComptime(parent, src_loc, rt.return_ty); |
| 312 | 325 | }, |
| ... | ... | @@ -398,8 +411,8 @@ pub const Block = struct { |
| 398 | 411 | }; |
| 399 | 412 | } |
| 400 | 413 | |
| 401 | pub fn getFileScope(block: *Block) *Module.File { | |
| 402 | return block.namespace.file_scope; | |
| 414 | pub fn getFileScope(block: *Block, mod: *Module) *Module.File { | |
| 415 | return mod.namespacePtr(block.namespace).file_scope; | |
| 403 | 416 | } |
| 404 | 417 | |
| 405 | 418 | fn addTy( |
| ... | ... | @@ -584,13 +597,18 @@ pub const Block = struct { |
| 584 | 597 | } |
| 585 | 598 | |
| 586 | 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 | 602 | return block.addInst(.{ |
| 588 | 603 | .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector, |
| 589 | 604 | .data = .{ .ty_pl = .{ |
| 590 | .ty = try block.sema.addType( | |
| 591 | try Type.vector(block.sema.arena, block.sema.typeOf(lhs).vectorLen(), Type.bool), | |
| 605 | .ty = try sema.addType( | |
| 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 | 612 | .lhs = lhs, |
| 595 | 613 | .rhs = rhs, |
| 596 | 614 | .op = Air.VectorCmp.encodeOp(cmp_op), |
| ... | ... | @@ -684,29 +702,20 @@ pub const Block = struct { |
| 684 | 702 | pub fn startAnonDecl(block: *Block) !WipAnonDecl { |
| 685 | 703 | return WipAnonDecl{ |
| 686 | 704 | .block = block, |
| 687 | .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa), | |
| 688 | 705 | .finished = false, |
| 689 | 706 | }; |
| 690 | 707 | } |
| 691 | 708 | |
| 692 | 709 | pub const WipAnonDecl = struct { |
| 693 | 710 | block: *Block, |
| 694 | new_decl_arena: std.heap.ArenaAllocator, | |
| 695 | 711 | finished: bool, |
| 696 | 712 | |
| 697 | pub fn arena(wad: *WipAnonDecl) Allocator { | |
| 698 | return wad.new_decl_arena.allocator(); | |
| 699 | } | |
| 700 | ||
| 701 | 713 | pub fn deinit(wad: *WipAnonDecl) void { |
| 702 | if (!wad.finished) { | |
| 703 | wad.new_decl_arena.deinit(); | |
| 704 | } | |
| 705 | 714 | wad.* = undefined; |
| 706 | 715 | } |
| 707 | 716 | |
| 708 | 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 | 719 | const sema = wad.block.sema; |
| 711 | 720 | // Do this ahead of time because `createAnonymousDecl` depends on calling |
| 712 | 721 | // `type.hasRuntimeBits()`. |
| ... | ... | @@ -716,10 +725,11 @@ pub const Block = struct { |
| 716 | 725 | .val = val, |
| 717 | 726 | }); |
| 718 | 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 | 730 | errdefer sema.mod.abortAnonDecl(new_decl_index); |
| 721 | try new_decl.finalizeNewArena(&wad.new_decl_arena); | |
| 722 | 731 | wad.finished = true; |
| 732 | try sema.mod.finalizeAnonDecl(new_decl_index); | |
| 723 | 733 | return new_decl_index; |
| 724 | 734 | } |
| 725 | 735 | }; |
| ... | ... | @@ -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 | 766 | pub fn deinit(sema: *Sema) void { |
| 740 | 767 | const gpa = sema.gpa; |
| 741 | 768 | sema.air_instructions.deinit(gpa); |
| 742 | 769 | sema.air_extra.deinit(gpa); |
| 743 | sema.air_values.deinit(gpa); | |
| 744 | 770 | sema.inst_map.deinit(gpa); |
| 745 | 771 | sema.decl_val_table.deinit(gpa); |
| 746 | 772 | sema.types_to_resolve.deinit(gpa); |
| ... | ... | @@ -823,7 +849,7 @@ pub fn analyzeBodyBreak( |
| 823 | 849 | else => |e| return e, |
| 824 | 850 | }; |
| 825 | 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 | 853 | return null; |
| 828 | 854 | const break_data = sema.code.instructions.items(.data)[break_inst].@"break"; |
| 829 | 855 | const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; |
| ... | ... | @@ -858,18 +884,20 @@ fn analyzeBodyInner( |
| 858 | 884 | |
| 859 | 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 | 891 | const parent_capture_scope = block.wip_capture_scope; |
| 862 | ||
| 863 | var wip_captures = WipCaptureScope{ | |
| 864 | .finalized = true, | |
| 892 | parent_capture_scope.incRef(); | |
| 893 | var wip_captures: WipCaptureScope = .{ | |
| 865 | 894 | .scope = parent_capture_scope, |
| 866 | .perm_arena = sema.perm_arena, | |
| 867 | 895 | .gpa = sema.gpa, |
| 896 | .finalized = true, // don't finalize the parent scope | |
| 868 | 897 | }; |
| 869 | defer if (wip_captures.scope != parent_capture_scope) { | |
| 870 | wip_captures.deinit(); | |
| 871 | }; | |
| 898 | defer wip_captures.deinit(); | |
| 872 | 899 | |
| 900 | const mod = sema.mod; | |
| 873 | 901 | const map = &sema.inst_map; |
| 874 | 902 | const tags = sema.code.instructions.items(.tag); |
| 875 | 903 | const datas = sema.code.instructions.items(.data); |
| ... | ... | @@ -890,15 +918,15 @@ fn analyzeBodyInner( |
| 890 | 918 | crash_info.setBodyIndex(i); |
| 891 | 919 | const inst = body[i]; |
| 892 | 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 | 923 | const air_inst: Air.Inst.Ref = switch (tags[inst]) { |
| 896 | 924 | // zig fmt: off |
| 897 | 925 | .alloc => try sema.zirAlloc(block, inst), |
| 898 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), | |
| 899 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), | |
| 900 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_const)), | |
| 901 | .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_mut)), | |
| 926 | .alloc_inferred => try sema.zirAllocInferred(block, inst, true), | |
| 927 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, false), | |
| 928 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, true), | |
| 929 | .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, false), | |
| 902 | 930 | .alloc_mut => try sema.zirAllocMut(block, inst), |
| 903 | 931 | .alloc_comptime_mut => try sema.zirAllocComptime(block, inst), |
| 904 | 932 | .make_ptr_const => try sema.zirMakePtrConst(block, inst), |
| ... | ... | @@ -962,7 +990,7 @@ fn analyzeBodyInner( |
| 962 | 990 | .int_big => try sema.zirIntBig(block, inst), |
| 963 | 991 | .float => try sema.zirFloat(block, inst), |
| 964 | 992 | .float128 => try sema.zirFloat128(block, inst), |
| 965 | .int_type => try sema.zirIntType(block, inst), | |
| 993 | .int_type => try sema.zirIntType(inst), | |
| 966 | 994 | .is_non_err => try sema.zirIsNonErr(block, inst), |
| 967 | 995 | .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), |
| 968 | 996 | .ret_is_non_err => try sema.zirRetIsNonErr(block, inst), |
| ... | ... | @@ -1420,6 +1448,11 @@ fn analyzeBodyInner( |
| 1420 | 1448 | const src = LazySrcLoc.nodeOffset(datas[inst].node); |
| 1421 | 1449 | try sema.emitBackwardBranch(block, src); |
| 1422 | 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 | 1456 | try wip_captures.reset(parent_capture_scope); |
| 1424 | 1457 | block.wip_capture_scope = wip_captures.scope; |
| 1425 | 1458 | orig_captures = 0; |
| ... | ... | @@ -1435,6 +1468,11 @@ fn analyzeBodyInner( |
| 1435 | 1468 | const src = LazySrcLoc.nodeOffset(datas[inst].node); |
| 1436 | 1469 | try sema.emitBackwardBranch(block, src); |
| 1437 | 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 | 1476 | try wip_captures.reset(parent_capture_scope); |
| 1439 | 1477 | block.wip_capture_scope = wip_captures.scope; |
| 1440 | 1478 | orig_captures = 0; |
| ... | ... | @@ -1621,18 +1659,18 @@ fn analyzeBodyInner( |
| 1621 | 1659 | const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 1622 | 1660 | const err_union = try sema.resolveInst(extra.data.operand); |
| 1623 | 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 | 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 | 1667 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); |
| 1630 | 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 | 1670 | if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); |
| 1633 | 1671 | return err; |
| 1634 | 1672 | }; |
| 1635 | if (is_non_err_tv.val.toBool()) { | |
| 1673 | if (is_non_err_val.toBool()) { | |
| 1636 | 1674 | break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false); |
| 1637 | 1675 | } |
| 1638 | 1676 | const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse |
| ... | ... | @@ -1654,11 +1692,11 @@ fn analyzeBodyInner( |
| 1654 | 1692 | const err_union = try sema.analyzeLoad(block, src, operand, operand_src); |
| 1655 | 1693 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); |
| 1656 | 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 | 1696 | if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); |
| 1659 | 1697 | return err; |
| 1660 | 1698 | }; |
| 1661 | if (is_non_err_tv.val.toBool()) { | |
| 1699 | if (is_non_err_val.toBool()) { | |
| 1662 | 1700 | break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); |
| 1663 | 1701 | } |
| 1664 | 1702 | const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse |
| ... | ... | @@ -1684,7 +1722,7 @@ fn analyzeBodyInner( |
| 1684 | 1722 | const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data; |
| 1685 | 1723 | const defer_body = sema.code.extra[extra.index..][0..extra.len]; |
| 1686 | 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 | 1726 | const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { |
| 1689 | 1727 | error.ComptimeBreak => sema.comptime_break_inst, |
| 1690 | 1728 | else => |e| return e, |
| ... | ... | @@ -1693,8 +1731,12 @@ fn analyzeBodyInner( |
| 1693 | 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 | 1738 | break always_noreturn; |
| 1739 | } | |
| 1698 | 1740 | map.putAssumeCapacity(inst, air_inst); |
| 1699 | 1741 | i += 1; |
| 1700 | 1742 | }; |
| ... | ... | @@ -1703,7 +1745,7 @@ fn analyzeBodyInner( |
| 1703 | 1745 | const noreturn_inst = block.instructions.popOrNull(); |
| 1704 | 1746 | while (dbg_block_begins > 0) { |
| 1705 | 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 | 1750 | _ = try block.addInst(.{ |
| 1709 | 1751 | .tag = .dbg_block_end, |
| ... | ... | @@ -1713,6 +1755,8 @@ fn analyzeBodyInner( |
| 1713 | 1755 | if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); |
| 1714 | 1756 | |
| 1715 | 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 | 1760 | try wip_captures.finalize(); |
| 1717 | 1761 | block.wip_capture_scope = parent_capture_scope; |
| 1718 | 1762 | } |
| ... | ... | @@ -1720,20 +1764,23 @@ fn analyzeBodyInner( |
| 1720 | 1764 | return result; |
| 1721 | 1765 | } |
| 1722 | 1766 | |
| 1723 | pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { | |
| 1724 | var i: usize = @enumToInt(zir_ref); | |
| 1725 | ||
| 1726 | // First section of indexes correspond to a set number of constant values. | |
| 1727 | if (i < Zir.Inst.Ref.typed_value_map.len) { | |
| 1728 | // We intentionally map the same indexes to the same values between ZIR and AIR. | |
| 1729 | return zir_ref; | |
| 1767 | pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { | |
| 1768 | if (zir_ref == .none) { | |
| 1769 | return .none; | |
| 1770 | } else { | |
| 1771 | return resolveInst(sema, 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. | |
| 1734 | const inst = sema.inst_map.get(@intCast(u32, i)).?; | |
| 1735 | const ty = sema.typeOf(inst); | |
| 1736 | if (ty.tag() == .generic_poison) return error.GenericPoison; | |
| 1775 | pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { | |
| 1776 | assert(zir_ref != .none); | |
| 1777 | const i = @enumToInt(zir_ref); | |
| 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 | 1784 | return inst; |
| 1738 | 1785 | } |
| 1739 | 1786 | |
| ... | ... | @@ -1759,18 +1806,31 @@ pub fn resolveConstString( |
| 1759 | 1806 | reason: []const u8, |
| 1760 | 1807 | ) ![]u8 { |
| 1761 | 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 | 1810 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 1764 | 1811 | const val = try sema.resolveConstValue(block, src, coerced_inst, reason); |
| 1765 | 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 | 1829 | pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { |
| 1769 | assert(zir_ref != .var_args_param); | |
| 1770 | 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 | 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 | 1834 | return ty; |
| 1775 | 1835 | } |
| 1776 | 1836 | |
| ... | ... | @@ -1780,45 +1840,48 @@ fn analyzeAsType( |
| 1780 | 1840 | src: LazySrcLoc, |
| 1781 | 1841 | air_inst: Air.Inst.Ref, |
| 1782 | 1842 | ) !Type { |
| 1783 | const wanted_type = Type.initTag(.type); | |
| 1843 | const wanted_type = Type.type; | |
| 1784 | 1844 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 1785 | 1845 | const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime-known"); |
| 1786 | var buffer: Value.ToTypeBuffer = undefined; | |
| 1787 | const ty = val.toType(&buffer); | |
| 1788 | return ty.copy(sema.arena); | |
| 1846 | return val.toType(); | |
| 1789 | 1847 | } |
| 1790 | 1848 | |
| 1791 | 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 | 1855 | assert(!block.is_comptime); |
| 1795 | 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 | 1859 | const src: LazySrcLoc = .unneeded; |
| 1799 | 1860 | |
| 1800 | 1861 | // var addrs: [err_return_trace_addr_count]usize = undefined; |
| 1801 | 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); | |
| 1803 | const addrs_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, addr_arr_ty)); | |
| 1863 | const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, mod); | |
| 1864 | const addrs_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(addr_arr_ty)); | |
| 1804 | 1865 | |
| 1805 | 1866 | // var st: StackTrace = undefined; |
| 1806 | 1867 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 1807 | 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 | 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 | 1874 | try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store); |
| 1813 | 1875 | |
| 1814 | 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 | 1879 | try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store); |
| 1817 | 1880 | |
| 1818 | 1881 | // @errorReturnTrace() = &st; |
| 1819 | 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 | 1887 | /// May return Value Tags: `variable`, `undef`. |
| ... | ... | @@ -1832,7 +1895,7 @@ fn resolveValue( |
| 1832 | 1895 | reason: []const u8, |
| 1833 | 1896 | ) CompileError!Value { |
| 1834 | 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 | 1899 | return val; |
| 1837 | 1900 | } |
| 1838 | 1901 | return sema.failWithNeededComptime(block, src, reason); |
| ... | ... | @@ -1848,10 +1911,12 @@ fn resolveConstMaybeUndefVal( |
| 1848 | 1911 | reason: []const u8, |
| 1849 | 1912 | ) CompileError!Value { |
| 1850 | 1913 | if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| { |
| 1851 | switch (val.tag()) { | |
| 1852 | .variable => return sema.failWithNeededComptime(block, src, reason), | |
| 1914 | switch (val.toIntern()) { | |
| 1853 | 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 | 1922 | return sema.failWithNeededComptime(block, src, reason); |
| ... | ... | @@ -1867,16 +1932,31 @@ fn resolveConstValue( |
| 1867 | 1932 | reason: []const u8, |
| 1868 | 1933 | ) CompileError!Value { |
| 1869 | 1934 | if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| { |
| 1870 | switch (val.tag()) { | |
| 1871 | .undef => return sema.failWithUseOfUndef(block, src), | |
| 1872 | .variable => return sema.failWithNeededComptime(block, src, reason), | |
| 1935 | switch (val.toIntern()) { | |
| 1873 | 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 | 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 | 1960 | /// Value Tag `variable` causes this function to return `null`. |
| 1881 | 1961 | /// Value Tag `undef` causes this function to return a compile error. |
| 1882 | 1962 | fn resolveDefinedValue( |
| ... | ... | @@ -1885,8 +1965,9 @@ fn resolveDefinedValue( |
| 1885 | 1965 | src: LazySrcLoc, |
| 1886 | 1966 | air_ref: Air.Inst.Ref, |
| 1887 | 1967 | ) CompileError!?Value { |
| 1968 | const mod = sema.mod; | |
| 1888 | 1969 | if (try sema.resolveMaybeUndefVal(air_ref)) |val| { |
| 1889 | if (val.isUndef()) { | |
| 1970 | if (val.isUndef(mod)) { | |
| 1890 | 1971 | if (block.is_typeof) return null; |
| 1891 | 1972 | return sema.failWithUseOfUndef(block, src); |
| 1892 | 1973 | } |
| ... | ... | @@ -1903,34 +1984,53 @@ fn resolveMaybeUndefVal( |
| 1903 | 1984 | inst: Air.Inst.Ref, |
| 1904 | 1985 | ) CompileError!?Value { |
| 1905 | 1986 | const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; |
| 1906 | switch (val.tag()) { | |
| 1907 | .variable => return null, | |
| 1987 | switch (val.ip_index) { | |
| 1908 | 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 | 2008 | /// Value Tag `variable` results in `null`. |
| 1914 | 2009 | /// Value Tag `undef` results in the Value. |
| 1915 | 2010 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. |
| 1916 | 2011 | /// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`. |
| 2012 | /// Lazy values are recursively resolved. | |
| 1917 | 2013 | fn resolveMaybeUndefValIntable( |
| 1918 | 2014 | sema: *Sema, |
| 1919 | 2015 | inst: Air.Inst.Ref, |
| 1920 | 2016 | ) CompileError!?Value { |
| 1921 | 2017 | const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; |
| 1922 | 2018 | var check = val; |
| 1923 | while (true) switch (check.tag()) { | |
| 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, | |
| 2019 | while (true) switch (check.ip_index) { | |
| 1928 | 2020 | .generic_poison => return error.GenericPoison, |
| 1929 | else => { | |
| 1930 | try sema.resolveLazyValue(val); | |
| 1931 | return val; | |
| 2021 | .none => break, | |
| 2022 | else => switch (sema.mod.intern_pool.indexToKey(check.toIntern())) { | |
| 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 | 2036 | /// Returns all Value tags including `variable` and `undef`. |
| ... | ... | @@ -1949,35 +2049,33 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( |
| 1949 | 2049 | inst: Air.Inst.Ref, |
| 1950 | 2050 | make_runtime: *bool, |
| 1951 | 2051 | ) CompileError!?Value { |
| 2052 | assert(inst != .none); | |
| 1952 | 2053 | // First section of indexes correspond to a set number of constant values. |
| 1953 | var i: usize = @enumToInt(inst); | |
| 1954 | if (i < Air.Inst.Ref.typed_value_map.len) { | |
| 1955 | return Air.Inst.Ref.typed_value_map[i].val; | |
| 2054 | const int = @enumToInt(inst); | |
| 2055 | if (int < InternPool.static_len) { | |
| 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 | 2060 | const air_tags = sema.air_instructions.items(.tag); |
| 1960 | 2061 | if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| { |
| 1961 | if (air_tags[i] == .constant) { | |
| 1962 | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; | |
| 1963 | const val = sema.air_values.items[ty_pl.payload]; | |
| 1964 | if (val.tag() == .variable) return val; | |
| 2062 | if (air_tags[i] == .interned) { | |
| 2063 | const interned = sema.air_instructions.items(.data)[i].interned; | |
| 2064 | const val = interned.toValue(); | |
| 2065 | if (val.getVariable(sema.mod) != null) return val; | |
| 1965 | 2066 | } |
| 1966 | 2067 | return opv; |
| 1967 | 2068 | } |
| 1968 | switch (air_tags[i]) { | |
| 1969 | .constant => { | |
| 1970 | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; | |
| 1971 | const val = sema.air_values.items[ty_pl.payload]; | |
| 1972 | if (val.tag() == .runtime_value) make_runtime.* = true; | |
| 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 | }, | |
| 2069 | const air_datas = sema.air_instructions.items(.data); | |
| 2070 | const val = switch (air_tags[i]) { | |
| 2071 | .inferred_alloc => unreachable, | |
| 2072 | .inferred_alloc_comptime => unreachable, | |
| 2073 | .interned => air_datas[i].interned.toValue(), | |
| 1979 | 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 | 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 | 2108 | } |
| 2011 | 2109 | |
| 2012 | 2110 | fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { |
| 2111 | const mod = sema.mod; | |
| 2013 | 2112 | const msg = msg: { |
| 2014 | 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 | 2116 | errdefer msg.destroy(sema.gpa); |
| 2018 | if (ty.isSlice()) { | |
| 2019 | try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2().fmt(sema.mod)}); | |
| 2117 | if (ty.isSlice(mod)) { | |
| 2118 | try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(mod).fmt(mod)}); | |
| 2020 | 2119 | } |
| 2021 | 2120 | break :msg msg; |
| 2022 | 2121 | }; |
| ... | ... | @@ -2042,7 +2141,8 @@ fn failWithErrorSetCodeMissing( |
| 2042 | 2141 | } |
| 2043 | 2142 | |
| 2044 | 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 | 2146 | const msg = msg: { |
| 2047 | 2147 | const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{ |
| 2048 | 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 | 2159 | } |
| 2060 | 2160 | |
| 2061 | 2161 | fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError { |
| 2162 | const mod = sema.mod; | |
| 2062 | 2163 | const msg = msg: { |
| 2063 | 2164 | const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); |
| 2064 | 2165 | errdefer msg.destroy(sema.gpa); |
| 2065 | 2166 | |
| 2066 | const struct_ty = container_ty.castTag(.@"struct") orelse break :msg msg; | |
| 2067 | const default_value_src = struct_ty.data.fieldSrcLoc(sema.mod, .{ | |
| 2167 | const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg; | |
| 2168 | const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{ | |
| 2068 | 2169 | .index = field_index, |
| 2069 | 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 | 2173 | break :msg msg; |
| 2073 | 2174 | }; |
| 2074 | 2175 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -2083,13 +2184,19 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError |
| 2083 | 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 { | |
| 2087 | const inner_ty = if (object_ty.isSinglePointer()) object_ty.childType() else object_ty; | |
| 2187 | fn failWithInvalidFieldAccess( | |
| 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: { | |
| 2090 | var buf: Type.Payload.ElemType = undefined; | |
| 2091 | const child_ty = inner_ty.optionalChild(&buf); | |
| 2092 | if (!typeSupportsFieldAccess(child_ty, field_name)) break :opt; | |
| 2197 | if (inner_ty.zigTypeTag(mod) == .Optional) opt: { | |
| 2198 | const child_ty = inner_ty.optionalChild(mod); | |
| 2199 | if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :opt; | |
| 2093 | 2200 | const msg = msg: { |
| 2094 | 2201 | const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 2095 | 2202 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -2097,9 +2204,9 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec |
| 2097 | 2204 | break :msg msg; |
| 2098 | 2205 | }; |
| 2099 | 2206 | return sema.failWithOwnedErrorMsg(msg); |
| 2100 | } else if (inner_ty.zigTypeTag() == .ErrorUnion) err: { | |
| 2101 | const child_ty = inner_ty.errorUnionPayload(); | |
| 2102 | if (!typeSupportsFieldAccess(child_ty, field_name)) break :err; | |
| 2207 | } else if (inner_ty.zigTypeTag(mod) == .ErrorUnion) err: { | |
| 2208 | const child_ty = inner_ty.errorUnionPayload(mod); | |
| 2209 | if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :err; | |
| 2103 | 2210 | const msg = msg: { |
| 2104 | 2211 | const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 2105 | 2212 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -2111,15 +2218,16 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec |
| 2111 | 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 { | |
| 2115 | switch (ty.zigTypeTag()) { | |
| 2116 | .Array => return mem.eql(u8, field_name, "len"), | |
| 2221 | fn typeSupportsFieldAccess(mod: *const Module, ty: Type, field_name: InternPool.NullTerminatedString) bool { | |
| 2222 | const ip = &mod.intern_pool; | |
| 2223 | switch (ty.zigTypeTag(mod)) { | |
| 2224 | .Array => return ip.stringEqlSlice(field_name, "len"), | |
| 2117 | 2225 | .Pointer => { |
| 2118 | const ptr_info = ty.ptrInfo().data; | |
| 2226 | const ptr_info = ty.ptrInfo(mod); | |
| 2119 | 2227 | if (ptr_info.size == .Slice) { |
| 2120 | return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len"); | |
| 2121 | } else if (ptr_info.pointee_type.zigTypeTag() == .Array) { | |
| 2122 | return mem.eql(u8, field_name, "len"); | |
| 2228 | return ip.stringEqlSlice(field_name, "ptr") or ip.stringEqlSlice(field_name, "len"); | |
| 2229 | } else if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) { | |
| 2230 | return ip.stringEqlSlice(field_name, "len"); | |
| 2123 | 2231 | } else return false; |
| 2124 | 2232 | }, |
| 2125 | 2233 | .Type, .Struct, .Union => return true, |
| ... | ... | @@ -2139,7 +2247,7 @@ fn errNote( |
| 2139 | 2247 | ) error{OutOfMemory}!void { |
| 2140 | 2248 | const mod = sema.mod; |
| 2141 | 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 | 2253 | fn addFieldErrNote( |
| ... | ... | @@ -2152,19 +2260,19 @@ fn addFieldErrNote( |
| 2152 | 2260 | ) !void { |
| 2153 | 2261 | @setCold(true); |
| 2154 | 2262 | const mod = sema.mod; |
| 2155 | const decl_index = container_ty.getOwnerDecl(); | |
| 2263 | const decl_index = container_ty.getOwnerDecl(mod); | |
| 2156 | 2264 | const decl = mod.declPtr(decl_index); |
| 2157 | 2265 | |
| 2158 | 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 | 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 | 2272 | const container_node = decl.relativeToNodeIndex(0); |
| 2165 | 2273 | const node_tags = tree.nodes.items(.tag); |
| 2166 | 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 | 2277 | var it_index: usize = 0; |
| 2170 | 2278 | for (container_decl.ast.members) |member_node| { |
| ... | ... | @@ -2174,7 +2282,7 @@ fn addFieldErrNote( |
| 2174 | 2282 | .container_field, |
| 2175 | 2283 | => { |
| 2176 | 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 | 2287 | it_index += 1; |
| 2180 | 2288 | }, |
| ... | ... | @@ -2195,7 +2303,7 @@ fn errMsg( |
| 2195 | 2303 | ) error{OutOfMemory}!*Module.ErrorMsg { |
| 2196 | 2304 | const mod = sema.mod; |
| 2197 | 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 | 2309 | pub fn fail( |
| ... | ... | @@ -2212,19 +2320,19 @@ pub fn fail( |
| 2212 | 2320 | fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2213 | 2321 | @setCold(true); |
| 2214 | 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 | 2326 | if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation; |
| 2218 | 2327 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 2219 | 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 | 2330 | std.debug.print("compile error during Sema:\n", .{}); |
| 2222 | 2331 | var error_bundle = wip_errors.toOwnedBundle("") catch unreachable; |
| 2223 | 2332 | error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); |
| 2224 | 2333 | crash_report.compilerPanic("unexpected compile error occurred", null, null); |
| 2225 | 2334 | } |
| 2226 | 2335 | |
| 2227 | const mod = sema.mod; | |
| 2228 | 2336 | ref: { |
| 2229 | 2337 | errdefer err_msg.destroy(gpa); |
| 2230 | 2338 | if (err_msg.src_loc.lazy == .unneeded) { |
| ... | ... | @@ -2234,9 +2342,9 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2234 | 2342 | try mod.failed_files.ensureUnusedCapacity(gpa, 1); |
| 2235 | 2343 | |
| 2236 | 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 | 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 | 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 | 2353 | defer reference_stack.deinit(); |
| 2246 | 2354 | |
| 2247 | 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 | 2357 | defer seen.deinit(); |
| 2250 | 2358 | |
| 2251 | 2359 | var cur_reference_trace: u32 = 0; |
| ... | ... | @@ -2254,13 +2362,16 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2254 | 2362 | if (gop.found_existing) break; |
| 2255 | 2363 | if (cur_reference_trace < max_references) { |
| 2256 | 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 | 2370 | referenced_by = ref.referencer; |
| 2260 | 2371 | } |
| 2261 | 2372 | if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) { |
| 2262 | 2373 | try reference_stack.append(.{ |
| 2263 | .decl = null, | |
| 2374 | .decl = .none, | |
| 2264 | 2375 | .src_loc = undefined, |
| 2265 | 2376 | .hidden = 0, |
| 2266 | 2377 | }); |
| ... | ... | @@ -2352,10 +2463,10 @@ fn analyzeAsInt( |
| 2352 | 2463 | dest_ty: Type, |
| 2353 | 2464 | reason: []const u8, |
| 2354 | 2465 | ) !u64 { |
| 2466 | const mod = sema.mod; | |
| 2355 | 2467 | const coerced = try sema.coerce(block, dest_ty, air_ref, src); |
| 2356 | 2468 | const val = try sema.resolveConstValue(block, src, coerced, reason); |
| 2357 | const target = sema.mod.getTarget(); | |
| 2358 | return (try val.getUnsignedIntAdvanced(target, sema)).?; | |
| 2469 | return (try val.getUnsignedIntAdvanced(mod, sema)).?; | |
| 2359 | 2470 | } |
| 2360 | 2471 | |
| 2361 | 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 | 2507 | const tracy = trace(@src()); |
| 2397 | 2508 | defer tracy.end(); |
| 2398 | 2509 | |
| 2510 | const mod = sema.mod; | |
| 2399 | 2511 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2400 | 2512 | const src = inst_data.src(); |
| 2401 | 2513 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 2402 | 2514 | const pointee_ty = try sema.resolveType(block, src, extra.lhs); |
| 2403 | 2515 | const ptr = try sema.resolveInst(extra.rhs); |
| 2404 | const target = sema.mod.getTarget(); | |
| 2516 | const target = mod.getTarget(); | |
| 2405 | 2517 | const addr_space = target_util.defaultAddressSpace(target, .local); |
| 2406 | 2518 | |
| 2407 | 2519 | if (Air.refToIndex(ptr)) |ptr_inst| { |
| 2408 | if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { | |
| 2409 | const air_datas = sema.air_instructions.items(.data); | |
| 2410 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; | |
| 2411 | switch (ptr_val.tag()) { | |
| 2412 | .inferred_alloc => { | |
| 2413 | const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data; | |
| 2414 | // Add the stored instruction to the set we will use to resolve peer types | |
| 2415 | // for the inferred allocation. | |
| 2416 | // This instruction will not make it to codegen; it is only to participate | |
| 2417 | // in the `stored_inst_list` of the `inferred_alloc`. | |
| 2418 | var trash_block = block.makeSubBlock(); | |
| 2419 | defer trash_block.instructions.deinit(sema.gpa); | |
| 2420 | const operand = try trash_block.addBitCast(pointee_ty, .void_value); | |
| 2421 | ||
| 2422 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 2423 | .pointee_type = pointee_ty, | |
| 2424 | .@"align" = inferred_alloc.alignment, | |
| 2425 | .@"addrspace" = addr_space, | |
| 2426 | }); | |
| 2427 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); | |
| 2520 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { | |
| 2521 | .inferred_alloc => { | |
| 2522 | const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc; | |
| 2523 | const ia2 = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; | |
| 2524 | // Add the stored instruction to the set we will use to resolve peer types | |
| 2525 | // for the inferred allocation. | |
| 2526 | // This instruction will not make it to codegen; it is only to participate | |
| 2527 | // in the `stored_inst_list` of the `inferred_alloc`. | |
| 2528 | var trash_block = block.makeSubBlock(); | |
| 2529 | defer trash_block.instructions.deinit(sema.gpa); | |
| 2530 | const operand = try trash_block.addBitCast(pointee_ty, .void_value); | |
| 2531 | ||
| 2532 | const ptr_ty = try mod.ptrType(.{ | |
| 2533 | .child = pointee_ty.toIntern(), | |
| 2534 | .flags = .{ | |
| 2535 | .alignment = ia1.alignment, | |
| 2536 | .address_space = addr_space, | |
| 2537 | }, | |
| 2538 | }); | |
| 2539 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); | |
| 2428 | 2540 | |
| 2429 | try inferred_alloc.prongs.append(sema.arena, .{ | |
| 2430 | .stored_inst = operand, | |
| 2431 | .placeholder = Air.refToIndex(bitcasted_ptr).?, | |
| 2432 | }); | |
| 2541 | try ia2.prongs.append(sema.arena, .{ | |
| 2542 | .stored_inst = operand, | |
| 2543 | .placeholder = Air.refToIndex(bitcasted_ptr).?, | |
| 2544 | }); | |
| 2433 | 2545 | |
| 2434 | return bitcasted_ptr; | |
| 2435 | }, | |
| 2436 | .inferred_alloc_comptime => { | |
| 2437 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; | |
| 2438 | // There will be only one coerce_result_ptr because we are running at comptime. | |
| 2439 | // The alloc will turn into a Decl. | |
| 2440 | var anon_decl = try block.startAnonDecl(); | |
| 2441 | defer anon_decl.deinit(); | |
| 2442 | iac.data.decl_index = try anon_decl.finish( | |
| 2443 | try pointee_ty.copy(anon_decl.arena()), | |
| 2444 | Value.undef, | |
| 2445 | iac.data.alignment, | |
| 2446 | ); | |
| 2447 | if (iac.data.alignment != 0) { | |
| 2448 | try sema.resolveTypeLayout(pointee_ty); | |
| 2449 | } | |
| 2450 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 2451 | .pointee_type = pointee_ty, | |
| 2452 | .@"align" = iac.data.alignment, | |
| 2453 | .@"addrspace" = addr_space, | |
| 2454 | }); | |
| 2455 | try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index); | |
| 2456 | return sema.addConstant( | |
| 2457 | ptr_ty, | |
| 2458 | try Value.Tag.decl_ref_mut.create(sema.arena, .{ | |
| 2459 | .decl_index = iac.data.decl_index, | |
| 2460 | .runtime_index = block.runtime_index, | |
| 2461 | }), | |
| 2462 | ); | |
| 2463 | }, | |
| 2464 | else => {}, | |
| 2465 | } | |
| 2546 | return bitcasted_ptr; | |
| 2547 | }, | |
| 2548 | .inferred_alloc_comptime => { | |
| 2549 | const alignment = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.alignment; | |
| 2550 | // There will be only one coerce_result_ptr because we are running at comptime. | |
| 2551 | // The alloc will turn into a Decl. | |
| 2552 | var anon_decl = try block.startAnonDecl(); | |
| 2553 | defer anon_decl.deinit(); | |
| 2554 | const decl_index = try anon_decl.finish( | |
| 2555 | pointee_ty, | |
| 2556 | (try mod.intern(.{ .undef = pointee_ty.toIntern() })).toValue(), | |
| 2557 | alignment.toByteUnits(0), | |
| 2558 | ); | |
| 2559 | sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.decl_index = decl_index; | |
| 2560 | if (alignment != .none) { | |
| 2561 | try sema.resolveTypeLayout(pointee_ty); | |
| 2562 | } | |
| 2563 | const ptr_ty = try mod.ptrType(.{ | |
| 2564 | .child = pointee_ty.toIntern(), | |
| 2565 | .flags = .{ | |
| 2566 | .alignment = alignment, | |
| 2567 | .address_space = addr_space, | |
| 2568 | }, | |
| 2569 | }); | |
| 2570 | try sema.maybeQueueFuncBodyAnalysis(decl_index); | |
| 2571 | try sema.comptime_mutable_decls.append(decl_index); | |
| 2572 | return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{ | |
| 2573 | .ty = ptr_ty.toIntern(), | |
| 2574 | .addr = .{ .mut_decl = .{ | |
| 2575 | .decl = decl_index, | |
| 2576 | .runtime_index = block.runtime_index, | |
| 2577 | } }, | |
| 2578 | } })).toValue()); | |
| 2579 | }, | |
| 2580 | else => {}, | |
| 2466 | 2581 | } |
| 2467 | 2582 | } |
| 2468 | 2583 | |
| ... | ... | @@ -2487,6 +2602,7 @@ fn coerceResultPtr( |
| 2487 | 2602 | dummy_operand: Air.Inst.Ref, |
| 2488 | 2603 | trash_block: *Block, |
| 2489 | 2604 | ) CompileError!Air.Inst.Ref { |
| 2605 | const mod = sema.mod; | |
| 2490 | 2606 | const target = sema.mod.getTarget(); |
| 2491 | 2607 | const addr_space = target_util.defaultAddressSpace(target, .local); |
| 2492 | 2608 | const pointee_ty = sema.typeOf(dummy_operand); |
| ... | ... | @@ -2530,7 +2646,7 @@ fn coerceResultPtr( |
| 2530 | 2646 | return sema.addConstant(ptr_ty, ptr_val); |
| 2531 | 2647 | } |
| 2532 | 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 | 2650 | const null_inst = try sema.addConstant(opt_ty, Value.null); |
| 2535 | 2651 | _ = try block.addBinOp(.store, new_ptr, null_inst); |
| 2536 | 2652 | return Air.Inst.Ref.void_value; |
| ... | ... | @@ -2563,7 +2679,7 @@ fn coerceResultPtr( |
| 2563 | 2679 | .@"addrspace" = addr_space, |
| 2564 | 2680 | }); |
| 2565 | 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 | 2683 | } else { |
| 2568 | 2684 | new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null); |
| 2569 | 2685 | } |
| ... | ... | @@ -2600,8 +2716,10 @@ pub fn analyzeStructDecl( |
| 2600 | 2716 | sema: *Sema, |
| 2601 | 2717 | new_decl: *Decl, |
| 2602 | 2718 | inst: Zir.Inst.Index, |
| 2603 | struct_obj: *Module.Struct, | |
| 2719 | struct_index: Module.Struct.Index, | |
| 2604 | 2720 | ) SemaError!void { |
| 2721 | const mod = sema.mod; | |
| 2722 | const struct_obj = mod.structPtr(struct_index); | |
| 2605 | 2723 | const extended = sema.code.instructions.items(.data)[inst].extended; |
| 2606 | 2724 | assert(extended.opcode == .struct_decl); |
| 2607 | 2725 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| ... | ... | @@ -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 | 2754 | fn zirStructDecl( |
| ... | ... | @@ -2639,28 +2757,35 @@ fn zirStructDecl( |
| 2639 | 2757 | extended: Zir.Inst.Extended.InstData, |
| 2640 | 2758 | inst: Zir.Inst.Index, |
| 2641 | 2759 | ) CompileError!Air.Inst.Ref { |
| 2760 | const mod = sema.mod; | |
| 2761 | const gpa = sema.gpa; | |
| 2642 | 2762 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| 2643 | 2763 | const src: LazySrcLoc = if (small.has_src_node) blk: { |
| 2644 | 2764 | const node_offset = @bitCast(i32, sema.code.extra[extended.operand]); |
| 2645 | 2765 | break :blk LazySrcLoc.nodeOffset(node_offset); |
| 2646 | 2766 | } else sema.src; |
| 2647 | 2767 | |
| 2648 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | |
| 2649 | errdefer new_decl_arena.deinit(); | |
| 2650 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 2768 | // Because these three things each reference each other, `undefined` | |
| 2769 | // placeholders are used before being set after the struct type gains an | |
| 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 | 2772 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2657 | .ty = Type.type, | |
| 2658 | .val = struct_val, | |
| 2773 | .ty = Type.noreturn, | |
| 2774 | .val = Value.@"unreachable", | |
| 2659 | 2775 | }, small.name_strategy, "struct", inst); |
| 2660 | 2776 | const new_decl = mod.declPtr(new_decl_index); |
| 2661 | 2777 | new_decl.owns_tv = true; |
| 2662 | 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 | 2789 | .owner_decl = new_decl_index, |
| 2665 | 2790 | .fields = .{}, |
| 2666 | 2791 | .zir_index = inst, |
| ... | ... | @@ -2668,18 +2793,25 @@ fn zirStructDecl( |
| 2668 | 2793 | .status = .none, |
| 2669 | 2794 | .known_non_opv = undefined, |
| 2670 | 2795 | .is_tuple = small.is_tuple, |
| 2671 | .namespace = .{ | |
| 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, | |
| 2796 | .namespace = new_namespace_index, | |
| 2679 | 2797 | }); |
| 2680 | try sema.analyzeStructDecl(new_decl, inst, struct_obj); | |
| 2681 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 2682 | return sema.analyzeDeclVal(block, src, new_decl_index); | |
| 2798 | errdefer mod.destroyStruct(struct_index); | |
| 2799 | ||
| 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 | 2817 | fn createAnonymousDeclTypeNamed( |
| ... | ... | @@ -2692,6 +2824,7 @@ fn createAnonymousDeclTypeNamed( |
| 2692 | 2824 | inst: ?Zir.Inst.Index, |
| 2693 | 2825 | ) !Decl.Index { |
| 2694 | 2826 | const mod = sema.mod; |
| 2827 | const gpa = sema.gpa; | |
| 2695 | 2828 | const namespace = block.namespace; |
| 2696 | 2829 | const src_scope = block.wip_capture_scope; |
| 2697 | 2830 | const src_decl = mod.declPtr(block.src_decl); |
| ... | ... | @@ -2707,16 +2840,15 @@ fn createAnonymousDeclTypeNamed( |
| 2707 | 2840 | // semantically analyzed. |
| 2708 | 2841 | // This name is also used as the key in the parent namespace so it cannot be |
| 2709 | 2842 | // renamed. |
| 2710 | const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{ | |
| 2711 | src_decl.name, anon_prefix, @enumToInt(new_decl_index), | |
| 2712 | }); | |
| 2713 | errdefer sema.gpa.free(name); | |
| 2843 | ||
| 2844 | const name = mod.intern_pool.getOrPutStringFmt(gpa, "{}__{s}_{d}", .{ | |
| 2845 | src_decl.name.fmt(&mod.intern_pool), anon_prefix, @enumToInt(new_decl_index), | |
| 2846 | }) catch unreachable; | |
| 2714 | 2847 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); |
| 2715 | 2848 | return new_decl_index; |
| 2716 | 2849 | }, |
| 2717 | 2850 | .parent => { |
| 2718 | const name = try sema.gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); | |
| 2719 | errdefer sema.gpa.free(name); | |
| 2851 | const name = mod.declPtr(block.src_decl).name; | |
| 2720 | 2852 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); |
| 2721 | 2853 | return new_decl_index; |
| 2722 | 2854 | }, |
| ... | ... | @@ -2724,10 +2856,11 @@ fn createAnonymousDeclTypeNamed( |
| 2724 | 2856 | const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst); |
| 2725 | 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 | 2860 | defer buf.deinit(); |
| 2729 | try buf.appendSlice(mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); | |
| 2730 | try buf.appendSlice("("); | |
| 2861 | ||
| 2862 | const writer = buf.writer(); | |
| 2863 | try writer.print("{}(", .{mod.declPtr(block.src_decl).name.fmt(&mod.intern_pool)}); | |
| 2731 | 2864 | |
| 2732 | 2865 | var arg_i: usize = 0; |
| 2733 | 2866 | for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) { |
| ... | ... | @@ -2741,8 +2874,8 @@ fn createAnonymousDeclTypeNamed( |
| 2741 | 2874 | const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, "") catch |
| 2742 | 2875 | return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); |
| 2743 | 2876 | |
| 2744 | if (arg_i != 0) try buf.appendSlice(","); | |
| 2745 | try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)}); | |
| 2877 | if (arg_i != 0) try writer.writeByte(','); | |
| 2878 | try writer.print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)}); | |
| 2746 | 2879 | |
| 2747 | 2880 | arg_i += 1; |
| 2748 | 2881 | continue; |
| ... | ... | @@ -2750,9 +2883,8 @@ fn createAnonymousDeclTypeNamed( |
| 2750 | 2883 | else => continue, |
| 2751 | 2884 | }; |
| 2752 | 2885 | |
| 2753 | try buf.appendSlice(")"); | |
| 2754 | const name = try buf.toOwnedSliceSentinel(0); | |
| 2755 | errdefer sema.gpa.free(name); | |
| 2886 | try writer.writeByte(')'); | |
| 2887 | const name = try mod.intern_pool.getOrPutString(gpa, buf.items); | |
| 2756 | 2888 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); |
| 2757 | 2889 | return new_decl_index; |
| 2758 | 2890 | }, |
| ... | ... | @@ -2765,10 +2897,9 @@ fn createAnonymousDeclTypeNamed( |
| 2765 | 2897 | .dbg_var_ptr, .dbg_var_val => { |
| 2766 | 2898 | if (zir_data[i].str_op.operand != ref) continue; |
| 2767 | 2899 | |
| 2768 | const name = try std.fmt.allocPrintZ(sema.gpa, "{s}.{s}", .{ | |
| 2769 | src_decl.name, zir_data[i].str_op.getStr(sema.code), | |
| 2900 | const name = try mod.intern_pool.getOrPutStringFmt(gpa, "{}.{s}", .{ | |
| 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 | 2904 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); |
| 2774 | 2905 | return new_decl_index; |
| ... | ... | @@ -2825,53 +2956,28 @@ fn zirEnumDecl( |
| 2825 | 2956 | break :blk decls_len; |
| 2826 | 2957 | } else 0; |
| 2827 | 2958 | |
| 2828 | var done = false; | |
| 2829 | ||
| 2830 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | |
| 2831 | errdefer if (!done) new_decl_arena.deinit(); | |
| 2832 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 2959 | // Because these three things each reference each other, `undefined` | |
| 2960 | // placeholders are used before being set after the enum type gains an | |
| 2961 | // InternPool index. | |
| 2833 | 2962 | |
| 2834 | const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull); | |
| 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); | |
| 2963 | var done = false; | |
| 2842 | 2964 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2843 | .ty = Type.type, | |
| 2844 | .val = enum_val, | |
| 2965 | .ty = Type.noreturn, | |
| 2966 | .val = Value.@"unreachable", | |
| 2845 | 2967 | }, small.name_strategy, "enum", inst); |
| 2846 | 2968 | const new_decl = mod.declPtr(new_decl_index); |
| 2847 | 2969 | new_decl.owns_tv = true; |
| 2848 | 2970 | errdefer if (!done) mod.abortAnonDecl(new_decl_index); |
| 2849 | 2971 | |
| 2850 | enum_obj.* = .{ | |
| 2851 | .owner_decl = new_decl_index, | |
| 2852 | .tag_ty = Type.null, | |
| 2853 | .tag_ty_inferred = true, | |
| 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, | |
| 2972 | const new_namespace_index = try mod.createNamespace(.{ | |
| 2973 | .parent = block.namespace.toOptional(), | |
| 2974 | .ty = undefined, | |
| 2975 | .file_scope = block.getFileScope(mod), | |
| 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); | |
| 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); | |
| 2980 | extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); | |
| 2875 | 2981 | |
| 2876 | 2982 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 2877 | 2983 | extra_index += body.len; |
| ... | ... | @@ -2880,7 +2986,34 @@ fn zirEnumDecl( |
| 2880 | 2986 | const body_end = extra_index; |
| 2881 | 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 | 3017 | // We create a block for the field type instructions because they |
| 2885 | 3018 | // may need to reference Decls from inside the enum namespace. |
| 2886 | 3019 | // Within the field type, default value, and alignment expressions, the "owner decl" |
| ... | ... | @@ -2896,21 +3029,27 @@ fn zirEnumDecl( |
| 2896 | 3029 | } |
| 2897 | 3030 | |
| 2898 | 3031 | const prev_owner_func = sema.owner_func; |
| 3032 | const prev_owner_func_index = sema.owner_func_index; | |
| 2899 | 3033 | sema.owner_func = null; |
| 3034 | sema.owner_func_index = .none; | |
| 2900 | 3035 | defer sema.owner_func = prev_owner_func; |
| 3036 | defer sema.owner_func_index = prev_owner_func_index; | |
| 2901 | 3037 | |
| 2902 | 3038 | const prev_func = sema.func; |
| 3039 | const prev_func_index = sema.func_index; | |
| 2903 | 3040 | sema.func = null; |
| 3041 | sema.func_index = .none; | |
| 2904 | 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 | 3046 | defer wip_captures.deinit(); |
| 2908 | 3047 | |
| 2909 | 3048 | var enum_block: Block = .{ |
| 2910 | 3049 | .parent = null, |
| 2911 | 3050 | .sema = sema, |
| 2912 | 3051 | .src_decl = new_decl_index, |
| 2913 | .namespace = &enum_obj.namespace, | |
| 3052 | .namespace = new_namespace_index, | |
| 2914 | 3053 | .wip_capture_scope = wip_captures.scope, |
| 2915 | 3054 | .instructions = .{}, |
| 2916 | 3055 | .inlining = null, |
| ... | ... | @@ -2926,43 +3065,29 @@ fn zirEnumDecl( |
| 2926 | 3065 | |
| 2927 | 3066 | if (tag_type_ref != .none) { |
| 2928 | 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 | 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); | |
| 2933 | enum_obj.tag_ty_inferred = false; | |
| 3071 | incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern()); | |
| 3072 | break :ty ty; | |
| 2934 | 3073 | } else if (fields_len == 0) { |
| 2935 | enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, 0); | |
| 2936 | enum_obj.tag_ty_inferred = true; | |
| 3074 | break :ty try mod.intType(.unsigned, 0); | |
| 2937 | 3075 | } else { |
| 2938 | 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); | |
| 2940 | enum_obj.tag_ty_inferred = true; | |
| 3077 | break :ty try mod.intType(.unsigned, bits); | |
| 2941 | 3078 | } |
| 2942 | } | |
| 3079 | }; | |
| 2943 | 3080 | |
| 2944 | if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) { | |
| 2945 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) { | |
| 3081 | if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { | |
| 3082 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) { | |
| 2946 | 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 | 3087 | var bit_bag_index: usize = body_end; |
| 2962 | 3088 | var cur_bit_bag: u32 = undefined; |
| 2963 | 3089 | var field_i: u32 = 0; |
| 2964 | 3090 | var last_tag_val: ?Value = null; |
| 2965 | var tag_val_buf: Value.Payload.U64 = undefined; | |
| 2966 | 3091 | while (field_i < fields_len) : (field_i += 1) { |
| 2967 | 3092 | if (field_i % 32 == 0) { |
| 2968 | 3093 | cur_bit_bag = sema.code.extra[bit_bag_index]; |
| ... | ... | @@ -2977,15 +3102,12 @@ fn zirEnumDecl( |
| 2977 | 3102 | // doc comment |
| 2978 | 3103 | extra_index += 1; |
| 2979 | 3104 | |
| 2980 | // This string needs to outlive the ZIR code. | |
| 2981 | const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); | |
| 2982 | ||
| 2983 | const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name); | |
| 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; | |
| 3105 | const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir); | |
| 3106 | if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name)) |other_index| { | |
| 3107 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; | |
| 3108 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; | |
| 2987 | 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 | 3111 | errdefer msg.destroy(gpa); |
| 2990 | 3112 | try sema.errNote(block, other_field_src, msg, "other field here", .{}); |
| 2991 | 3113 | break :msg msg; |
| ... | ... | @@ -2993,13 +3115,13 @@ fn zirEnumDecl( |
| 2993 | 3115 | return sema.failWithOwnedErrorMsg(msg); |
| 2994 | 3116 | } |
| 2995 | 3117 | |
| 2996 | if (has_tag_value) { | |
| 3118 | const tag_overflow = if (has_tag_value) overflow: { | |
| 2997 | 3119 | const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 2998 | 3120 | extra_index += 1; |
| 2999 | 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 | 3123 | error.NeededSourceLocation => { |
| 3002 | const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ | |
| 3124 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ | |
| 3003 | 3125 | .index = field_i, |
| 3004 | 3126 | .range = .value, |
| 3005 | 3127 | }).lazy; |
| ... | ... | @@ -3008,63 +3130,56 @@ fn zirEnumDecl( |
| 3008 | 3130 | }, |
| 3009 | 3131 | else => |e| return e, |
| 3010 | 3132 | }; |
| 3011 | last_tag_val = tag_val; | |
| 3012 | const copied_tag_val = try tag_val.copy(decl_arena_allocator); | |
| 3013 | const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ | |
| 3014 | .ty = enum_obj.tag_ty, | |
| 3015 | .mod = mod, | |
| 3016 | }); | |
| 3017 | if (gop_val.found_existing) { | |
| 3018 | const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ | |
| 3133 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; | |
| 3134 | last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty); | |
| 3135 | if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| { | |
| 3136 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ | |
| 3019 | 3137 | .index = field_i, |
| 3020 | 3138 | .range = .value, |
| 3021 | 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 | 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 | 3143 | errdefer msg.destroy(gpa); |
| 3026 | 3144 | try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); |
| 3027 | 3145 | break :msg msg; |
| 3028 | 3146 | }; |
| 3029 | 3147 | return sema.failWithOwnedErrorMsg(msg); |
| 3030 | 3148 | } |
| 3031 | } else if (any_values) { | |
| 3032 | const tag_val = if (last_tag_val) |val| | |
| 3033 | try sema.intAdd(val, Value.one, enum_obj.tag_ty) | |
| 3149 | break :overflow false; | |
| 3150 | } else if (any_values) overflow: { | |
| 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 | 3154 | else |
| 3035 | Value.zero; | |
| 3036 | last_tag_val = tag_val; | |
| 3037 | const copied_tag_val = try tag_val.copy(decl_arena_allocator); | |
| 3038 | const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ | |
| 3039 | .ty = enum_obj.tag_ty, | |
| 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; | |
| 3155 | try mod.intValue(int_tag_ty, 0); | |
| 3156 | if (overflow != null) break :overflow true; | |
| 3157 | if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| { | |
| 3158 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; | |
| 3159 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; | |
| 3045 | 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 | 3162 | errdefer msg.destroy(gpa); |
| 3048 | 3163 | try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); |
| 3049 | 3164 | break :msg msg; |
| 3050 | 3165 | }; |
| 3051 | 3166 | return sema.failWithOwnedErrorMsg(msg); |
| 3052 | 3167 | } |
| 3053 | } else { | |
| 3054 | tag_val_buf = .{ | |
| 3055 | .base = .{ .tag = .int_u64 }, | |
| 3056 | .data = field_i, | |
| 3057 | }; | |
| 3058 | last_tag_val = Value.initPayload(&tag_val_buf.base); | |
| 3059 | } | |
| 3168 | break :overflow false; | |
| 3169 | } else overflow: { | |
| 3170 | last_tag_val = try mod.intValue(Type.comptime_int, field_i); | |
| 3171 | if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true; | |
| 3172 | last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty); | |
| 3173 | break :overflow false; | |
| 3174 | }; | |
| 3060 | 3175 | |
| 3061 | if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) { | |
| 3062 | const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ | |
| 3176 | if (tag_overflow) { | |
| 3177 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ | |
| 3063 | 3178 | .index = field_i, |
| 3064 | 3179 | .range = if (has_tag_value) .value else .name, |
| 3065 | 3180 | }).lazy; |
| 3066 | 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 | 3184 | return sema.failWithOwnedErrorMsg(msg); |
| 3070 | 3185 | } |
| ... | ... | @@ -3081,6 +3196,8 @@ fn zirUnionDecl( |
| 3081 | 3196 | const tracy = trace(@src()); |
| 3082 | 3197 | defer tracy.end(); |
| 3083 | 3198 | |
| 3199 | const mod = sema.mod; | |
| 3200 | const gpa = sema.gpa; | |
| 3084 | 3201 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); |
| 3085 | 3202 | var extra_index: usize = extended.operand; |
| 3086 | 3203 | |
| ... | ... | @@ -3100,55 +3217,60 @@ fn zirUnionDecl( |
| 3100 | 3217 | break :blk decls_len; |
| 3101 | 3218 | } else 0; |
| 3102 | 3219 | |
| 3103 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | |
| 3104 | errdefer new_decl_arena.deinit(); | |
| 3105 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 3106 | ||
| 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; | |
| 3220 | // Because these three things each reference each other, `undefined` | |
| 3221 | // placeholders are used before being set after the union type gains an | |
| 3222 | // InternPool index. | |
| 3223 | ||
| 3124 | 3224 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 3125 | .ty = Type.type, | |
| 3126 | .val = union_val, | |
| 3225 | .ty = Type.noreturn, | |
| 3226 | .val = Value.@"unreachable", | |
| 3127 | 3227 | }, small.name_strategy, "union", inst); |
| 3128 | 3228 | const new_decl = mod.declPtr(new_decl_index); |
| 3129 | 3229 | new_decl.owns_tv = true; |
| 3130 | 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 | 3241 | .owner_decl = new_decl_index, |
| 3133 | .tag_ty = Type.initTag(.null), | |
| 3242 | .tag_ty = Type.null, | |
| 3134 | 3243 | .fields = .{}, |
| 3135 | 3244 | .zir_index = inst, |
| 3136 | 3245 | .layout = small.layout, |
| 3137 | 3246 | .status = .none, |
| 3138 | .namespace = .{ | |
| 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, | |
| 3247 | .namespace = new_namespace_index, | |
| 3146 | 3248 | }); |
| 3147 | ||
| 3148 | _ = try mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl); | |
| 3149 | ||
| 3150 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 3151 | return sema.analyzeDeclVal(block, src, new_decl_index); | |
| 3249 | errdefer mod.destroyUnion(union_index); | |
| 3250 | ||
| 3251 | const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ | |
| 3252 | .index = union_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 | 3276 | fn zirOpaqueDecl( |
| ... | ... | @@ -3161,7 +3283,6 @@ fn zirOpaqueDecl( |
| 3161 | 3283 | defer tracy.end(); |
| 3162 | 3284 | |
| 3163 | 3285 | const mod = sema.mod; |
| 3164 | const gpa = sema.gpa; | |
| 3165 | 3286 | const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small); |
| 3166 | 3287 | var extra_index: usize = extended.operand; |
| 3167 | 3288 | |
| ... | ... | @@ -3177,42 +3298,42 @@ fn zirOpaqueDecl( |
| 3177 | 3298 | break :blk decls_len; |
| 3178 | 3299 | } else 0; |
| 3179 | 3300 | |
| 3180 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | |
| 3181 | errdefer new_decl_arena.deinit(); | |
| 3182 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 3301 | // Because these three things each reference each other, `undefined` | |
| 3302 | // placeholders are used in two places before being set after the opaque | |
| 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 | 3305 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 3193 | .ty = Type.type, | |
| 3194 | .val = opaque_val, | |
| 3306 | .ty = Type.noreturn, | |
| 3307 | .val = Value.@"unreachable", | |
| 3195 | 3308 | }, small.name_strategy, "opaque", inst); |
| 3196 | 3309 | const new_decl = mod.declPtr(new_decl_index); |
| 3197 | 3310 | new_decl.owns_tv = true; |
| 3198 | 3311 | errdefer mod.abortAnonDecl(new_decl_index); |
| 3199 | 3312 | |
| 3200 | opaque_obj.* = .{ | |
| 3201 | .owner_decl = new_decl_index, | |
| 3202 | .namespace = .{ | |
| 3203 | .parent = block.namespace, | |
| 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, | |
| 3313 | const new_namespace_index = try mod.createNamespace(.{ | |
| 3314 | .parent = block.namespace.toOptional(), | |
| 3315 | .ty = undefined, | |
| 3316 | .file_scope = block.getFileScope(mod), | |
| 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); | |
| 3215 | return sema.analyzeDeclVal(block, src, new_decl_index); | |
| 3332 | extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); | |
| 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 | 3339 | fn zirErrorSetDecl( |
| ... | ... | @@ -3224,48 +3345,39 @@ fn zirErrorSetDecl( |
| 3224 | 3345 | const tracy = trace(@src()); |
| 3225 | 3346 | defer tracy.end(); |
| 3226 | 3347 | |
| 3348 | const mod = sema.mod; | |
| 3227 | 3349 | const gpa = sema.gpa; |
| 3228 | 3350 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3229 | 3351 | const src = inst_data.src(); |
| 3230 | 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); | |
| 3233 | errdefer new_decl_arena.deinit(); | |
| 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); | |
| 3354 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; | |
| 3355 | try names.ensureUnusedCapacity(sema.arena, extra.data.fields_len); | |
| 3250 | 3356 | |
| 3251 | 3357 | var extra_index = @intCast(u32, extra.end); |
| 3252 | 3358 | const extra_index_end = extra_index + (extra.data.fields_len * 2); |
| 3253 | 3359 | while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string |
| 3254 | 3360 | const str_index = sema.code.extra[extra_index]; |
| 3255 | const kv = try mod.getErrorValue(sema.code.nullTerminatedString(str_index)); | |
| 3256 | const result = names.getOrPutAssumeCapacity(kv.key); | |
| 3361 | const name = sema.code.nullTerminatedString(str_index); | |
| 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 | 3365 | assert(!result.found_existing); // verified in AstGen |
| 3258 | 3366 | } |
| 3259 | 3367 | |
| 3260 | // names must be sorted. | |
| 3261 | Module.ErrorSet.sortNames(&names); | |
| 3368 | const error_set_ty = try mod.errorSetFromUnsortedNames(names.keys()); | |
| 3262 | 3369 | |
| 3263 | error_set.* = .{ | |
| 3264 | .owner_decl = new_decl_index, | |
| 3265 | .names = names, | |
| 3266 | }; | |
| 3267 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 3268 | return sema.analyzeDeclVal(block, src, new_decl_index); | |
| 3370 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | |
| 3371 | .ty = Type.type, | |
| 3372 | .val = error_set_ty.toValue(), | |
| 3373 | }, name_strategy, "error", inst); | |
| 3374 | const new_decl = mod.declPtr(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 | 3383 | fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -3319,7 +3431,8 @@ fn ensureResultUsed( |
| 3319 | 3431 | ty: Type, |
| 3320 | 3432 | src: LazySrcLoc, |
| 3321 | 3433 | ) CompileError!void { |
| 3322 | switch (ty.zigTypeTag()) { | |
| 3434 | const mod = sema.mod; | |
| 3435 | switch (ty.zigTypeTag(mod)) { | |
| 3323 | 3436 | .Void, .NoReturn => return, |
| 3324 | 3437 | .ErrorSet, .ErrorUnion => { |
| 3325 | 3438 | const msg = msg: { |
| ... | ... | @@ -3347,11 +3460,12 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3347 | 3460 | const tracy = trace(@src()); |
| 3348 | 3461 | defer tracy.end(); |
| 3349 | 3462 | |
| 3463 | const mod = sema.mod; | |
| 3350 | 3464 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3351 | 3465 | const operand = try sema.resolveInst(inst_data.operand); |
| 3352 | 3466 | const src = inst_data.src(); |
| 3353 | 3467 | const operand_ty = sema.typeOf(operand); |
| 3354 | switch (operand_ty.zigTypeTag()) { | |
| 3468 | switch (operand_ty.zigTypeTag(mod)) { | |
| 3355 | 3469 | .ErrorSet, .ErrorUnion => { |
| 3356 | 3470 | const msg = msg: { |
| 3357 | 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 | 3483 | const tracy = trace(@src()); |
| 3370 | 3484 | defer tracy.end(); |
| 3371 | 3485 | |
| 3486 | const mod = sema.mod; | |
| 3372 | 3487 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3373 | 3488 | const src = inst_data.src(); |
| 3374 | 3489 | const operand = try sema.resolveInst(inst_data.operand); |
| 3375 | 3490 | const operand_ty = sema.typeOf(operand); |
| 3376 | const err_union_ty = if (operand_ty.zigTypeTag() == .Pointer) | |
| 3377 | operand_ty.childType() | |
| 3491 | const err_union_ty = if (operand_ty.zigTypeTag(mod) == .Pointer) | |
| 3492 | operand_ty.childType(mod) | |
| 3378 | 3493 | else |
| 3379 | 3494 | operand_ty; |
| 3380 | if (err_union_ty.zigTypeTag() != .ErrorUnion) return; | |
| 3381 | const payload_ty = err_union_ty.errorUnionPayload().zigTypeTag(); | |
| 3495 | if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) return; | |
| 3496 | const payload_ty = err_union_ty.errorUnionPayload(mod).zigTypeTag(mod); | |
| 3382 | 3497 | if (payload_ty != .Void and payload_ty != .NoReturn) { |
| 3383 | 3498 | const msg = msg: { |
| 3384 | 3499 | const msg = try sema.errMsg(block, src, "error union payload is ignored", .{}); |
| ... | ... | @@ -3407,11 +3522,13 @@ fn indexablePtrLen( |
| 3407 | 3522 | src: LazySrcLoc, |
| 3408 | 3523 | object: Air.Inst.Ref, |
| 3409 | 3524 | ) CompileError!Air.Inst.Ref { |
| 3525 | const mod = sema.mod; | |
| 3410 | 3526 | const object_ty = sema.typeOf(object); |
| 3411 | const is_pointer_to = object_ty.isSinglePointer(); | |
| 3412 | const indexable_ty = if (is_pointer_to) object_ty.childType() else object_ty; | |
| 3527 | const is_pointer_to = object_ty.isSinglePointer(mod); | |
| 3528 | const indexable_ty = if (is_pointer_to) object_ty.childType(mod) else object_ty; | |
| 3413 | 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 | 3534 | fn indexablePtrLenOrNone( |
| ... | ... | @@ -3420,10 +3537,12 @@ fn indexablePtrLenOrNone( |
| 3420 | 3537 | src: LazySrcLoc, |
| 3421 | 3538 | operand: Air.Inst.Ref, |
| 3422 | 3539 | ) CompileError!Air.Inst.Ref { |
| 3540 | const mod = sema.mod; | |
| 3423 | 3541 | const operand_ty = sema.typeOf(operand); |
| 3424 | 3542 | try checkMemOperand(sema, block, src, operand_ty); |
| 3425 | if (operand_ty.ptrSize() == .Many) return .none; | |
| 3426 | return sema.fieldVal(block, src, operand, "len", src); | |
| 3543 | if (operand_ty.ptrSize(mod) == .Many) return .none; | |
| 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 | 3548 | fn zirAllocExtended( |
| ... | ... | @@ -3431,6 +3550,7 @@ fn zirAllocExtended( |
| 3431 | 3550 | block: *Block, |
| 3432 | 3551 | extended: Zir.Inst.Extended.InstData, |
| 3433 | 3552 | ) CompileError!Air.Inst.Ref { |
| 3553 | const gpa = sema.gpa; | |
| 3434 | 3554 | const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); |
| 3435 | 3555 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node }; |
| 3436 | 3556 | const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node }; |
| ... | ... | @@ -3451,22 +3571,19 @@ fn zirAllocExtended( |
| 3451 | 3571 | break :blk alignment; |
| 3452 | 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 | 3574 | if (block.is_comptime or small.is_comptime) { |
| 3460 | 3575 | if (small.has_type) { |
| 3461 | 3576 | return sema.analyzeComptimeAlloc(block, var_ty, alignment); |
| 3462 | 3577 | } else { |
| 3463 | return sema.addConstant( | |
| 3464 | inferred_alloc_ty, | |
| 3465 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ | |
| 3578 | try sema.air_instructions.append(gpa, .{ | |
| 3579 | .tag = .inferred_alloc_comptime, | |
| 3580 | .data = .{ .inferred_alloc_comptime = .{ | |
| 3466 | 3581 | .decl_index = undefined, |
| 3467 | .alignment = alignment, | |
| 3468 | }), | |
| 3469 | ); | |
| 3582 | .alignment = InternPool.Alignment.fromByteUnits(alignment), | |
| 3583 | .is_const = small.is_const, | |
| 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 | 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 | |
| 3488 | // not needed in the case of constant values. However here, we plan to "downgrade" | |
| 3489 | // to a normal instruction when we hit `resolve_inferred_alloc`. So we append | |
| 3490 | // to the block even though it is currently a `.constant`. | |
| 3491 | const result = try sema.addConstant( | |
| 3492 | inferred_alloc_ty, | |
| 3493 | try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }), | |
| 3494 | ); | |
| 3495 | try block.instructions.append(sema.gpa, Air.refToIndex(result).?); | |
| 3496 | try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {}); | |
| 3497 | return result; | |
| 3604 | const result_index = try block.addInstAsIndex(.{ | |
| 3605 | .tag = .inferred_alloc, | |
| 3606 | .data = .{ .inferred_alloc = .{ | |
| 3607 | .alignment = InternPool.Alignment.fromByteUnits(alignment), | |
| 3608 | .is_const = small.is_const, | |
| 3609 | } }, | |
| 3610 | }); | |
| 3611 | try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); | |
| 3612 | return Air.indexToRef(result_index); | |
| 3498 | 3613 | } |
| 3499 | 3614 | |
| 3500 | 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 | 3623 | } |
| 3509 | 3624 | |
| 3510 | 3625 | fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 3626 | const mod = sema.mod; | |
| 3511 | 3627 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3512 | 3628 | const alloc = try sema.resolveInst(inst_data.operand); |
| 3513 | 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 | 3632 | const elem_ty = ptr_info.pointee_type; |
| 3517 | 3633 | |
| 3518 | 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 | 3674 | var anon_decl = try block.startAnonDecl(); |
| 3559 | 3675 | defer anon_decl.deinit(); |
| 3560 | 3676 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 3561 | try elem_ty.copy(anon_decl.arena()), | |
| 3562 | try store_val.copy(anon_decl.arena()), | |
| 3677 | elem_ty, | |
| 3678 | store_val, | |
| 3563 | 3679 | ptr_info.@"align", |
| 3564 | 3680 | )); |
| 3565 | 3681 | } |
| ... | ... | @@ -3568,15 +3684,16 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 3568 | 3684 | } |
| 3569 | 3685 | |
| 3570 | 3686 | fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref { |
| 3687 | const mod = sema.mod; | |
| 3571 | 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 | 3691 | ptr_info.mutable = false; |
| 3575 | 3692 | const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); |
| 3576 | 3693 | |
| 3577 | 3694 | // Detect if a comptime value simply needs to have its type changed. |
| 3578 | 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 | 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 | 3702 | fn zirAllocInferredComptime( |
| 3586 | 3703 | sema: *Sema, |
| 3587 | 3704 | inst: Zir.Inst.Index, |
| 3588 | inferred_alloc_ty: Type, | |
| 3705 | is_const: bool, | |
| 3589 | 3706 | ) CompileError!Air.Inst.Ref { |
| 3707 | const gpa = sema.gpa; | |
| 3590 | 3708 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 3591 | 3709 | const src = LazySrcLoc.nodeOffset(src_node); |
| 3592 | 3710 | sema.src = src; |
| 3593 | return sema.addConstant( | |
| 3594 | inferred_alloc_ty, | |
| 3595 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ | |
| 3711 | ||
| 3712 | try sema.air_instructions.append(gpa, .{ | |
| 3713 | .tag = .inferred_alloc_comptime, | |
| 3714 | .data = .{ .inferred_alloc_comptime = .{ | |
| 3596 | 3715 | .decl_index = undefined, |
| 3597 | .alignment = 0, | |
| 3598 | }), | |
| 3599 | ); | |
| 3716 | .alignment = .none, | |
| 3717 | .is_const = is_const, | |
| 3718 | } }, | |
| 3719 | }); | |
| 3720 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); | |
| 3600 | 3721 | } |
| 3601 | 3722 | |
| 3602 | 3723 | fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -3642,104 +3763,103 @@ fn zirAllocInferred( |
| 3642 | 3763 | sema: *Sema, |
| 3643 | 3764 | block: *Block, |
| 3644 | 3765 | inst: Zir.Inst.Index, |
| 3645 | inferred_alloc_ty: Type, | |
| 3766 | is_const: bool, | |
| 3646 | 3767 | ) CompileError!Air.Inst.Ref { |
| 3647 | 3768 | const tracy = trace(@src()); |
| 3648 | 3769 | defer tracy.end(); |
| 3649 | 3770 | |
| 3771 | const gpa = sema.gpa; | |
| 3650 | 3772 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 3651 | 3773 | const src = LazySrcLoc.nodeOffset(src_node); |
| 3652 | 3774 | sema.src = src; |
| 3653 | 3775 | |
| 3654 | 3776 | if (block.is_comptime) { |
| 3655 | return sema.addConstant( | |
| 3656 | inferred_alloc_ty, | |
| 3657 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ | |
| 3777 | try sema.air_instructions.append(gpa, .{ | |
| 3778 | .tag = .inferred_alloc_comptime, | |
| 3779 | .data = .{ .inferred_alloc_comptime = .{ | |
| 3658 | 3780 | .decl_index = undefined, |
| 3659 | .alignment = 0, | |
| 3660 | }), | |
| 3661 | ); | |
| 3781 | .alignment = .none, | |
| 3782 | .is_const = is_const, | |
| 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 | |
| 3665 | // not needed in the case of constant values. However here, we plan to "downgrade" | |
| 3666 | // to a normal instruction when we hit `resolve_inferred_alloc`. So we append | |
| 3667 | // to the block even though it is currently a `.constant`. | |
| 3668 | const result = try sema.addConstant( | |
| 3669 | inferred_alloc_ty, | |
| 3670 | try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }), | |
| 3671 | ); | |
| 3672 | try block.instructions.append(sema.gpa, Air.refToIndex(result).?); | |
| 3673 | try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {}); | |
| 3674 | return result; | |
| 3788 | const result_index = try block.addInstAsIndex(.{ | |
| 3789 | .tag = .inferred_alloc, | |
| 3790 | .data = .{ .inferred_alloc = .{ | |
| 3791 | .alignment = .none, | |
| 3792 | .is_const = is_const, | |
| 3793 | } }, | |
| 3794 | }); | |
| 3795 | try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); | |
| 3796 | return Air.indexToRef(result_index); | |
| 3675 | 3797 | } |
| 3676 | 3798 | |
| 3677 | 3799 | fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 3678 | 3800 | const tracy = trace(@src()); |
| 3679 | 3801 | defer tracy.end(); |
| 3680 | 3802 | |
| 3803 | const mod = sema.mod; | |
| 3681 | 3804 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3682 | 3805 | const src = inst_data.src(); |
| 3683 | 3806 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; |
| 3684 | 3807 | const ptr = try sema.resolveInst(inst_data.operand); |
| 3685 | 3808 | const ptr_inst = Air.refToIndex(ptr).?; |
| 3686 | assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); | |
| 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(); | |
| 3809 | const target = mod.getTarget(); | |
| 3695 | 3810 | |
| 3696 | switch (ptr_val.tag()) { | |
| 3811 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { | |
| 3697 | 3812 | .inferred_alloc_comptime => { |
| 3698 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; | |
| 3699 | const decl_index = iac.data.decl_index; | |
| 3700 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); | |
| 3701 | ||
| 3702 | const decl = sema.mod.declPtr(decl_index); | |
| 3703 | const final_elem_ty = try decl.ty.copy(sema.arena); | |
| 3704 | const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 3705 | .pointee_type = final_elem_ty, | |
| 3706 | .mutable = true, | |
| 3707 | .@"align" = iac.data.alignment, | |
| 3708 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | |
| 3813 | const iac = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime; | |
| 3814 | const decl_index = iac.decl_index; | |
| 3815 | try mod.declareDeclDependency(sema.owner_decl_index, decl_index); | |
| 3816 | ||
| 3817 | const decl = mod.declPtr(decl_index); | |
| 3818 | if (iac.is_const) try decl.intern(mod); | |
| 3819 | const final_elem_ty = decl.ty; | |
| 3820 | const final_ptr_ty = try mod.ptrType(.{ | |
| 3821 | .child = final_elem_ty.toIntern(), | |
| 3822 | .flags = .{ | |
| 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 | 3829 | try sema.maybeQueueFuncBodyAnalysis(decl_index); |
| 3714 | if (var_is_mut) { | |
| 3715 | sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{ | |
| 3716 | .decl_index = decl_index, | |
| 3717 | .runtime_index = block.runtime_index, | |
| 3718 | }); | |
| 3719 | } else { | |
| 3720 | sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl_index); | |
| 3721 | } | |
| 3830 | // Change it to an interned. | |
| 3831 | sema.air_instructions.set(ptr_inst, .{ | |
| 3832 | .tag = .interned, | |
| 3833 | .data = .{ .interned = try mod.intern(.{ .ptr = .{ | |
| 3834 | .ty = final_ptr_ty.toIntern(), | |
| 3835 | .addr = if (!iac.is_const) .{ .mut_decl = .{ | |
| 3836 | .decl = decl_index, | |
| 3837 | .runtime_index = block.runtime_index, | |
| 3838 | } } else .{ .decl = decl_index }, | |
| 3839 | } }) }, | |
| 3840 | }); | |
| 3722 | 3841 | }, |
| 3723 | 3842 | .inferred_alloc => { |
| 3724 | assert(sema.unresolved_inferred_allocs.remove(ptr_inst)); | |
| 3725 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; | |
| 3726 | const peer_inst_list = inferred_alloc.data.prongs.items(.stored_inst); | |
| 3843 | const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc; | |
| 3844 | const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value; | |
| 3845 | const peer_inst_list = ia2.prongs.items(.stored_inst); | |
| 3727 | 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, .{ | |
| 3730 | .pointee_type = final_elem_ty, | |
| 3731 | .mutable = true, | |
| 3732 | .@"align" = inferred_alloc.data.alignment, | |
| 3733 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | |
| 3848 | const final_ptr_ty = try mod.ptrType(.{ | |
| 3849 | .child = final_elem_ty.toIntern(), | |
| 3850 | .flags = .{ | |
| 3851 | .alignment = ia1.alignment, | |
| 3852 | .address_space = target_util.defaultAddressSpace(target, .local), | |
| 3853 | }, | |
| 3734 | 3854 | }); |
| 3735 | 3855 | |
| 3736 | if (var_is_mut) { | |
| 3856 | if (!ia1.is_const) { | |
| 3737 | 3857 | try sema.validateVarType(block, ty_src, final_elem_ty, false); |
| 3738 | 3858 | } else ct: { |
| 3739 | 3859 | // Detect if the value is comptime-known. In such case, the |
| 3740 | 3860 | // last 3 AIR instructions of the block will look like this: |
| 3741 | 3861 | // |
| 3742 | // %a = constant | |
| 3862 | // %a = inferred_alloc | |
| 3743 | 3863 | // %b = bitcast(%a) |
| 3744 | 3864 | // %c = store(%b, %d) |
| 3745 | 3865 | // |
| ... | ... | @@ -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 | 3903 | if (search_index == 0) break :ct; |
| 3784 | 3904 | search_index -= 1; |
| 3785 | 3905 | |
| 3786 | 3906 | const candidate = block.instructions.items[search_index]; |
| 3907 | if (candidate == ptr_inst) break; | |
| 3787 | 3908 | switch (air_tags[candidate]) { |
| 3788 | 3909 | .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, |
| 3789 | .constant => break candidate, | |
| 3790 | 3910 | else => break :ct, |
| 3791 | 3911 | } |
| 3792 | }; | |
| 3912 | } | |
| 3793 | 3913 | |
| 3794 | 3914 | const store_op = air_datas[store_inst].bin_op; |
| 3795 | 3915 | const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct; |
| 3796 | 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 | 3919 | const new_decl_index = d: { |
| 3800 | 3920 | var anon_decl = try block.startAnonDecl(); |
| 3801 | 3921 | defer anon_decl.deinit(); |
| 3802 | 3922 | const new_decl_index = try anon_decl.finish( |
| 3803 | try final_elem_ty.copy(anon_decl.arena()), | |
| 3804 | try store_val.copy(anon_decl.arena()), | |
| 3805 | inferred_alloc.data.alignment, | |
| 3923 | final_elem_ty, | |
| 3924 | store_val, | |
| 3925 | ia1.alignment.toByteUnits(0), | |
| 3806 | 3926 | ); |
| 3807 | 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 | 3931 | // Even though we reuse the constant instruction, we still remove it from the |
| 3812 | 3932 | // block so that codegen does not see it. |
| 3813 | 3933 | block.instructions.shrinkRetainingCapacity(search_index); |
| 3814 | 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); | |
| 3816 | // if bitcast ty ref needs to be made const, make_ptr_const | |
| 3817 | // ZIR handles it later, so we can just use the ty ref here. | |
| 3818 | air_datas[ptr_inst].ty_pl.ty = air_datas[bitcast_inst].ty_op.ty; | |
| 3935 | sema.air_instructions.set(ptr_inst, .{ | |
| 3936 | .tag = .interned, | |
| 3937 | .data = .{ .interned = try mod.intern(.{ .ptr = .{ | |
| 3938 | .ty = final_ptr_ty.toIntern(), | |
| 3939 | .addr = .{ .decl = new_decl_index }, | |
| 3940 | } }) }, | |
| 3941 | }); | |
| 3819 | 3942 | |
| 3820 | 3943 | // Unless the block is comptime, `alloc_inferred` always produces |
| 3821 | 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 | 3959 | // Now we need to go back over all the coerce_result_ptr instructions, which |
| 3837 | 3960 | // previously inserted a bitcast as a placeholder, and do the logic as if |
| 3838 | 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 | 3963 | const gpa = sema.gpa; |
| 3841 | 3964 | |
| 3842 | 3965 | var trash_block = block.makeSubBlock(); |
| 3843 | 3966 | trash_block.is_comptime = false; |
| 3844 | 3967 | defer trash_block.instructions.deinit(gpa); |
| 3845 | 3968 | |
| 3846 | const mut_final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 3847 | .pointee_type = final_elem_ty, | |
| 3848 | .mutable = true, | |
| 3849 | .@"align" = inferred_alloc.data.alignment, | |
| 3850 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | |
| 3969 | const mut_final_ptr_ty = try mod.ptrType(.{ | |
| 3970 | .child = final_elem_ty.toIntern(), | |
| 3971 | .flags = .{ | |
| 3972 | .alignment = ia1.alignment, | |
| 3973 | .address_space = target_util.defaultAddressSpace(target, .local), | |
| 3974 | }, | |
| 3851 | 3975 | }); |
| 3852 | 3976 | const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty); |
| 3853 | 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 | 3979 | for (peer_inst_list, placeholders) |peer_inst, placeholder_inst| { |
| 3856 | 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 | 3983 | // New result location type is the same as the old one; nothing |
| 3860 | 3984 | // to do here. |
| 3861 | 3985 | continue; |
| ... | ... | @@ -3920,27 +4044,28 @@ fn zirArrayBasePtr( |
| 3920 | 4044 | block: *Block, |
| 3921 | 4045 | inst: Zir.Inst.Index, |
| 3922 | 4046 | ) CompileError!Air.Inst.Ref { |
| 4047 | const mod = sema.mod; | |
| 3923 | 4048 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3924 | 4049 | const src = inst_data.src(); |
| 3925 | 4050 | |
| 3926 | 4051 | const start_ptr = try sema.resolveInst(inst_data.operand); |
| 3927 | 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 | 4054 | .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), |
| 3930 | 4055 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), |
| 3931 | 4056 | else => break, |
| 3932 | 4057 | }; |
| 3933 | 4058 | |
| 3934 | const elem_ty = sema.typeOf(base_ptr).childType(); | |
| 3935 | switch (elem_ty.zigTypeTag()) { | |
| 4059 | const elem_ty = sema.typeOf(base_ptr).childType(mod); | |
| 4060 | switch (elem_ty.zigTypeTag(mod)) { | |
| 3936 | 4061 | .Array, .Vector => return base_ptr, |
| 3937 | .Struct => if (elem_ty.isTuple()) { | |
| 4062 | .Struct => if (elem_ty.isTuple(mod)) { | |
| 3938 | 4063 | // TODO validate element count |
| 3939 | 4064 | return base_ptr; |
| 3940 | 4065 | }, |
| 3941 | 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 | 4071 | fn zirFieldBasePtr( |
| ... | ... | @@ -3948,27 +4073,30 @@ fn zirFieldBasePtr( |
| 3948 | 4073 | block: *Block, |
| 3949 | 4074 | inst: Zir.Inst.Index, |
| 3950 | 4075 | ) CompileError!Air.Inst.Ref { |
| 4076 | const mod = sema.mod; | |
| 3951 | 4077 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3952 | 4078 | const src = inst_data.src(); |
| 3953 | 4079 | |
| 3954 | 4080 | const start_ptr = try sema.resolveInst(inst_data.operand); |
| 3955 | 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 | 4083 | .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), |
| 3958 | 4084 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), |
| 3959 | 4085 | else => break, |
| 3960 | 4086 | }; |
| 3961 | 4087 | |
| 3962 | const elem_ty = sema.typeOf(base_ptr).childType(); | |
| 3963 | switch (elem_ty.zigTypeTag()) { | |
| 4088 | const elem_ty = sema.typeOf(base_ptr).childType(mod); | |
| 4089 | switch (elem_ty.zigTypeTag(mod)) { | |
| 3964 | 4090 | .Struct, .Union => return base_ptr, |
| 3965 | 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 | 4096 | fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 4097 | const mod = sema.mod; | |
| 3971 | 4098 | const gpa = sema.gpa; |
| 4099 | const ip = &mod.intern_pool; | |
| 3972 | 4100 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3973 | 4101 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); |
| 3974 | 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 | 4119 | const object_ty = sema.typeOf(object); |
| 3992 | 4120 | // Each arg could be an indexable, or a range, in which case the length |
| 3993 | 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 | 4123 | .Int, .ComptimeInt => true, |
| 3996 | 4124 | else => false, |
| 3997 | 4125 | }; |
| ... | ... | @@ -4000,7 +4128,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4000 | 4128 | .input_index = i, |
| 4001 | 4129 | } }; |
| 4002 | 4130 | const arg_len_uncoerced = if (is_int) object else l: { |
| 4003 | if (!object_ty.isIndexable()) { | |
| 4131 | if (!object_ty.isIndexable(mod)) { | |
| 4004 | 4132 | // Instead of using checkIndexable we customize this error. |
| 4005 | 4133 | const msg = msg: { |
| 4006 | 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 | 4138 | }; |
| 4011 | 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 | 4145 | const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src); |
| 4018 | 4146 | if (len == .none) { |
| ... | ... | @@ -4061,7 +4189,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4061 | 4189 | const object_ty = sema.typeOf(object); |
| 4062 | 4190 | // Each arg could be an indexable, or a range, in which case the length |
| 4063 | 4191 | // is passed directly as an integer. |
| 4064 | switch (object_ty.zigTypeTag()) { | |
| 4192 | switch (object_ty.zigTypeTag(mod)) { | |
| 4065 | 4193 | .Int, .ComptimeInt => continue, |
| 4066 | 4194 | else => {}, |
| 4067 | 4195 | } |
| ... | ... | @@ -4096,15 +4224,16 @@ fn validateArrayInitTy( |
| 4096 | 4224 | block: *Block, |
| 4097 | 4225 | inst: Zir.Inst.Index, |
| 4098 | 4226 | ) CompileError!void { |
| 4227 | const mod = sema.mod; | |
| 4099 | 4228 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 4100 | 4229 | const src = inst_data.src(); |
| 4101 | 4230 | const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; |
| 4102 | 4231 | const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; |
| 4103 | 4232 | const ty = try sema.resolveType(block, ty_src, extra.ty); |
| 4104 | 4233 | |
| 4105 | switch (ty.zigTypeTag()) { | |
| 4234 | switch (ty.zigTypeTag(mod)) { | |
| 4106 | 4235 | .Array => { |
| 4107 | const array_len = ty.arrayLen(); | |
| 4236 | const array_len = ty.arrayLen(mod); | |
| 4108 | 4237 | if (extra.init_count != array_len) { |
| 4109 | 4238 | return sema.fail(block, src, "expected {d} array elements; found {d}", .{ |
| 4110 | 4239 | array_len, extra.init_count, |
| ... | ... | @@ -4113,7 +4242,7 @@ fn validateArrayInitTy( |
| 4113 | 4242 | return; |
| 4114 | 4243 | }, |
| 4115 | 4244 | .Vector => { |
| 4116 | const array_len = ty.arrayLen(); | |
| 4245 | const array_len = ty.arrayLen(mod); | |
| 4117 | 4246 | if (extra.init_count != array_len) { |
| 4118 | 4247 | return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ |
| 4119 | 4248 | array_len, extra.init_count, |
| ... | ... | @@ -4121,9 +4250,9 @@ fn validateArrayInitTy( |
| 4121 | 4250 | } |
| 4122 | 4251 | return; |
| 4123 | 4252 | }, |
| 4124 | .Struct => if (ty.isTuple()) { | |
| 4253 | .Struct => if (ty.isTuple(mod)) { | |
| 4125 | 4254 | _ = try sema.resolveTypeFields(ty); |
| 4126 | const array_len = ty.arrayLen(); | |
| 4255 | const array_len = ty.arrayLen(mod); | |
| 4127 | 4256 | if (extra.init_count > array_len) { |
| 4128 | 4257 | return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ |
| 4129 | 4258 | array_len, extra.init_count, |
| ... | ... | @@ -4141,11 +4270,12 @@ fn validateStructInitTy( |
| 4141 | 4270 | block: *Block, |
| 4142 | 4271 | inst: Zir.Inst.Index, |
| 4143 | 4272 | ) CompileError!void { |
| 4273 | const mod = sema.mod; | |
| 4144 | 4274 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4145 | 4275 | const src = inst_data.src(); |
| 4146 | 4276 | const ty = try sema.resolveType(block, src, inst_data.operand); |
| 4147 | 4277 | |
| 4148 | switch (ty.zigTypeTag()) { | |
| 4278 | switch (ty.zigTypeTag(mod)) { | |
| 4149 | 4279 | .Struct, .Union => return, |
| 4150 | 4280 | else => {}, |
| 4151 | 4281 | } |
| ... | ... | @@ -4160,6 +4290,7 @@ fn zirValidateStructInit( |
| 4160 | 4290 | const tracy = trace(@src()); |
| 4161 | 4291 | defer tracy.end(); |
| 4162 | 4292 | |
| 4293 | const mod = sema.mod; | |
| 4163 | 4294 | const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; |
| 4164 | 4295 | const init_src = validate_inst.src(); |
| 4165 | 4296 | const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); |
| ... | ... | @@ -4167,8 +4298,8 @@ fn zirValidateStructInit( |
| 4167 | 4298 | const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; |
| 4168 | 4299 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 4169 | 4300 | const object_ptr = try sema.resolveInst(field_ptr_extra.lhs); |
| 4170 | const agg_ty = sema.typeOf(object_ptr).childType(); | |
| 4171 | switch (agg_ty.zigTypeTag()) { | |
| 4301 | const agg_ty = sema.typeOf(object_ptr).childType(mod); | |
| 4302 | switch (agg_ty.zigTypeTag(mod)) { | |
| 4172 | 4303 | .Struct => return sema.validateStructInit( |
| 4173 | 4304 | block, |
| 4174 | 4305 | agg_ty, |
| ... | ... | @@ -4194,6 +4325,9 @@ fn validateUnionInit( |
| 4194 | 4325 | instrs: []const Zir.Inst.Index, |
| 4195 | 4326 | union_ptr: Air.Inst.Ref, |
| 4196 | 4327 | ) CompileError!void { |
| 4328 | const mod = sema.mod; | |
| 4329 | const gpa = sema.gpa; | |
| 4330 | ||
| 4197 | 4331 | if (instrs.len != 1) { |
| 4198 | 4332 | const msg = msg: { |
| 4199 | 4333 | const msg = try sema.errMsg( |
| ... | ... | @@ -4202,7 +4336,7 @@ fn validateUnionInit( |
| 4202 | 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 | 4341 | for (instrs[1..]) |inst| { |
| 4208 | 4342 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| ... | ... | @@ -4226,7 +4360,7 @@ fn validateUnionInit( |
| 4226 | 4360 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; |
| 4227 | 4361 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; |
| 4228 | 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 | 4364 | // Validate the field access but ignore the index since we want the tag enum field index. |
| 4231 | 4365 | _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src); |
| 4232 | 4366 | const air_tags = sema.air_instructions.items(.tag); |
| ... | ... | @@ -4291,21 +4425,25 @@ fn validateUnionInit( |
| 4291 | 4425 | break; |
| 4292 | 4426 | } |
| 4293 | 4427 | |
| 4294 | const tag_ty = union_ty.unionTagTypeHypothetical(); | |
| 4295 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); | |
| 4296 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | |
| 4428 | const tag_ty = union_ty.unionTagTypeHypothetical(mod); | |
| 4429 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); | |
| 4430 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); | |
| 4297 | 4431 | |
| 4298 | 4432 | if (init_val) |val| { |
| 4299 | 4433 | // Our task is to delete all the `field_ptr` and `store` instructions, and insert |
| 4300 | 4434 | // instead a single `store` to the result ptr with a comptime union value. |
| 4301 | 4435 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4302 | 4436 | |
| 4303 | var union_val = try Value.Tag.@"union".create(sema.arena, .{ | |
| 4304 | .tag = tag_val, | |
| 4305 | .val = val, | |
| 4306 | }); | |
| 4307 | if (make_runtime) union_val = try Value.Tag.runtime_value.create(sema.arena, union_val); | |
| 4308 | const union_init = try sema.addConstant(union_ty, union_val); | |
| 4437 | var union_val = try mod.intern(.{ .un = .{ | |
| 4438 | .ty = union_ty.toIntern(), | |
| 4439 | .tag = tag_val.toIntern(), | |
| 4440 | .val = val.toIntern(), | |
| 4441 | } }); | |
| 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 | 4447 | try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store); |
| 4310 | 4448 | return; |
| 4311 | 4449 | } else if (try sema.typeRequiresComptime(union_ty)) { |
| ... | ... | @@ -4323,10 +4461,12 @@ fn validateStructInit( |
| 4323 | 4461 | init_src: LazySrcLoc, |
| 4324 | 4462 | instrs: []const Zir.Inst.Index, |
| 4325 | 4463 | ) CompileError!void { |
| 4464 | const mod = sema.mod; | |
| 4326 | 4465 | const gpa = sema.gpa; |
| 4466 | const ip = &mod.intern_pool; | |
| 4327 | 4467 | |
| 4328 | 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 | 4470 | defer gpa.free(found_fields); |
| 4331 | 4471 | @memset(found_fields, 0); |
| 4332 | 4472 | |
| ... | ... | @@ -4337,8 +4477,11 @@ fn validateStructInit( |
| 4337 | 4477 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; |
| 4338 | 4478 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 4339 | 4479 | struct_ptr_zir_ref = field_ptr_extra.lhs; |
| 4340 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); | |
| 4341 | const field_index = if (struct_ty.isTuple()) | |
| 4480 | const field_name = try ip.getOrPutString( | |
| 4481 | gpa, | |
| 4482 | sema.code.nullTerminatedString(field_ptr_extra.field_name_start), | |
| 4483 | ); | |
| 4484 | const field_index = if (struct_ty.isTuple(mod)) | |
| 4342 | 4485 | try sema.tupleFieldIndex(block, struct_ty, field_name, field_src) |
| 4343 | 4486 | else |
| 4344 | 4487 | try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| ... | ... | @@ -4371,9 +4514,9 @@ fn validateStructInit( |
| 4371 | 4514 | for (found_fields, 0..) |field_ptr, i| { |
| 4372 | 4515 | if (field_ptr != 0) continue; |
| 4373 | 4516 | |
| 4374 | const default_val = struct_ty.structFieldDefaultValue(i); | |
| 4375 | if (default_val.tag() == .unreachable_value) { | |
| 4376 | if (struct_ty.isTuple()) { | |
| 4517 | const default_val = struct_ty.structFieldDefaultValue(i, mod); | |
| 4518 | if (default_val.toIntern() == .unreachable_value) { | |
| 4519 | if (struct_ty.isTuple(mod)) { | |
| 4377 | 4520 | const template = "missing tuple field with index {d}"; |
| 4378 | 4521 | if (root_msg) |msg| { |
| 4379 | 4522 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | ... | @@ -4382,9 +4525,9 @@ fn validateStructInit( |
| 4382 | 4525 | } |
| 4383 | 4526 | continue; |
| 4384 | 4527 | } |
| 4385 | const field_name = struct_ty.structFieldName(i); | |
| 4386 | const template = "missing struct field: {s}"; | |
| 4387 | const args = .{field_name}; | |
| 4528 | const field_name = struct_ty.structFieldName(i, mod); | |
| 4529 | const template = "missing struct field: {}"; | |
| 4530 | const args = .{field_name.fmt(ip)}; | |
| 4388 | 4531 | if (root_msg) |msg| { |
| 4389 | 4532 | try sema.errNote(block, init_src, msg, template, args); |
| 4390 | 4533 | } else { |
| ... | ... | @@ -4394,25 +4537,23 @@ fn validateStructInit( |
| 4394 | 4537 | } |
| 4395 | 4538 | |
| 4396 | 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 | 4541 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) |
| 4399 | 4542 | else |
| 4400 | 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 | 4545 | const init = try sema.addConstant(field_ty, default_val); |
| 4403 | 4546 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| 4404 | 4547 | } |
| 4405 | 4548 | |
| 4406 | 4549 | if (root_msg) |msg| { |
| 4407 | if (struct_ty.castTag(.@"struct")) |struct_obj| { | |
| 4408 | const mod = sema.mod; | |
| 4409 | const fqn = try struct_obj.data.getFullyQualifiedName(mod); | |
| 4410 | defer gpa.free(fqn); | |
| 4550 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | |
| 4551 | const fqn = try struct_obj.getFullyQualifiedName(mod); | |
| 4411 | 4552 | try mod.errNoteNonLazy( |
| 4412 | struct_obj.data.srcLoc(mod), | |
| 4553 | struct_obj.srcLoc(mod), | |
| 4413 | 4554 | msg, |
| 4414 | "struct '{s}' declared here", | |
| 4415 | .{fqn}, | |
| 4555 | "struct '{}' declared here", | |
| 4556 | .{fqn.fmt(ip)}, | |
| 4416 | 4557 | ); |
| 4417 | 4558 | } |
| 4418 | 4559 | root_msg = null; |
| ... | ... | @@ -4432,14 +4573,14 @@ fn validateStructInit( |
| 4432 | 4573 | |
| 4433 | 4574 | // We collect the comptime field values in case the struct initialization |
| 4434 | 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 | 4578 | field: for (found_fields, 0..) |field_ptr, i| { |
| 4438 | 4579 | if (field_ptr != 0) { |
| 4439 | 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 | 4582 | if (try sema.typeHasOnePossibleValue(field_ty)) |opv| { |
| 4442 | field_values[i] = opv; | |
| 4583 | field_values[i] = opv.toIntern(); | |
| 4443 | 4584 | continue; |
| 4444 | 4585 | } |
| 4445 | 4586 | |
| ... | ... | @@ -4504,7 +4645,7 @@ fn validateStructInit( |
| 4504 | 4645 | first_block_index = @min(first_block_index, block_index); |
| 4505 | 4646 | } |
| 4506 | 4647 | if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { |
| 4507 | field_values[i] = val; | |
| 4648 | field_values[i] = val.toIntern(); | |
| 4508 | 4649 | } else if (require_comptime) { |
| 4509 | 4650 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; |
| 4510 | 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 | 4658 | continue :field; |
| 4518 | 4659 | } |
| 4519 | 4660 | |
| 4520 | const default_val = struct_ty.structFieldDefaultValue(i); | |
| 4521 | if (default_val.tag() == .unreachable_value) { | |
| 4522 | if (struct_ty.isTuple()) { | |
| 4661 | const default_val = struct_ty.structFieldDefaultValue(i, mod); | |
| 4662 | if (default_val.toIntern() == .unreachable_value) { | |
| 4663 | if (struct_ty.isTuple(mod)) { | |
| 4523 | 4664 | const template = "missing tuple field with index {d}"; |
| 4524 | 4665 | if (root_msg) |msg| { |
| 4525 | 4666 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | ... | @@ -4528,9 +4669,9 @@ fn validateStructInit( |
| 4528 | 4669 | } |
| 4529 | 4670 | continue; |
| 4530 | 4671 | } |
| 4531 | const field_name = struct_ty.structFieldName(i); | |
| 4532 | const template = "missing struct field: {s}"; | |
| 4533 | const args = .{field_name}; | |
| 4672 | const field_name = struct_ty.structFieldName(i, mod); | |
| 4673 | const template = "missing struct field: {}"; | |
| 4674 | const args = .{field_name.fmt(ip)}; | |
| 4534 | 4675 | if (root_msg) |msg| { |
| 4535 | 4676 | try sema.errNote(block, init_src, msg, template, args); |
| 4536 | 4677 | } else { |
| ... | ... | @@ -4538,18 +4679,17 @@ fn validateStructInit( |
| 4538 | 4679 | } |
| 4539 | 4680 | continue; |
| 4540 | 4681 | } |
| 4541 | field_values[i] = default_val; | |
| 4682 | field_values[i] = default_val.toIntern(); | |
| 4542 | 4683 | } |
| 4543 | 4684 | |
| 4544 | 4685 | if (root_msg) |msg| { |
| 4545 | if (struct_ty.castTag(.@"struct")) |struct_obj| { | |
| 4546 | const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); | |
| 4547 | defer gpa.free(fqn); | |
| 4548 | try sema.mod.errNoteNonLazy( | |
| 4549 | struct_obj.data.srcLoc(sema.mod), | |
| 4686 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | |
| 4687 | const fqn = try struct_obj.getFullyQualifiedName(mod); | |
| 4688 | try mod.errNoteNonLazy( | |
| 4689 | struct_obj.srcLoc(mod), | |
| 4550 | 4690 | msg, |
| 4551 | "struct '{s}' declared here", | |
| 4552 | .{fqn}, | |
| 4691 | "struct '{}' declared here", | |
| 4692 | .{fqn.fmt(ip)}, | |
| 4553 | 4693 | ); |
| 4554 | 4694 | } |
| 4555 | 4695 | root_msg = null; |
| ... | ... | @@ -4561,9 +4701,15 @@ fn validateStructInit( |
| 4561 | 4701 | // instead a single `store` to the struct_ptr with a comptime struct value. |
| 4562 | 4702 | |
| 4563 | 4703 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4564 | var struct_val = try Value.Tag.aggregate.create(sema.arena, field_values); | |
| 4565 | if (make_runtime) struct_val = try Value.Tag.runtime_value.create(sema.arena, struct_val); | |
| 4566 | const struct_init = try sema.addConstant(struct_ty, struct_val); | |
| 4704 | var struct_val = try mod.intern(.{ .aggregate = .{ | |
| 4705 | .ty = struct_ty.toIntern(), | |
| 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 | 4713 | try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); |
| 4568 | 4714 | return; |
| 4569 | 4715 | } |
| ... | ... | @@ -4574,12 +4720,12 @@ fn validateStructInit( |
| 4574 | 4720 | if (field_ptr != 0) continue; |
| 4575 | 4721 | |
| 4576 | 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 | 4724 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) |
| 4579 | 4725 | else |
| 4580 | 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(); | |
| 4582 | const init = try sema.addConstant(field_ty, field_values[i]); | |
| 4727 | const field_ty = sema.typeOf(default_field_ptr).childType(mod); | |
| 4728 | const init = try sema.addConstant(field_ty, field_values[i].toValue()); | |
| 4583 | 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 | 4735 | block: *Block, |
| 4590 | 4736 | inst: Zir.Inst.Index, |
| 4591 | 4737 | ) CompileError!void { |
| 4738 | const mod = sema.mod; | |
| 4592 | 4739 | const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; |
| 4593 | 4740 | const init_src = validate_inst.src(); |
| 4594 | 4741 | const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); |
| ... | ... | @@ -4596,18 +4743,18 @@ fn zirValidateArrayInit( |
| 4596 | 4743 | const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; |
| 4597 | 4744 | const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data; |
| 4598 | 4745 | const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr); |
| 4599 | const array_ty = sema.typeOf(array_ptr).childType(); | |
| 4600 | const array_len = array_ty.arrayLen(); | |
| 4746 | const array_ty = sema.typeOf(array_ptr).childType(mod); | |
| 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 | 4750 | .Struct => { |
| 4604 | 4751 | var root_msg: ?*Module.ErrorMsg = null; |
| 4605 | 4752 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 4606 | 4753 | |
| 4607 | 4754 | var i = instrs.len; |
| 4608 | 4755 | while (i < array_len) : (i += 1) { |
| 4609 | const default_val = array_ty.structFieldDefaultValue(i); | |
| 4610 | if (default_val.tag() == .unreachable_value) { | |
| 4756 | const default_val = array_ty.structFieldDefaultValue(i, mod); | |
| 4757 | if (default_val.toIntern() == .unreachable_value) { | |
| 4611 | 4758 | const template = "missing tuple field with index {d}"; |
| 4612 | 4759 | if (root_msg) |msg| { |
| 4613 | 4760 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | ... | @@ -4642,39 +4789,41 @@ fn zirValidateArrayInit( |
| 4642 | 4789 | // at comptime so we have almost nothing to do here. However, in case of a |
| 4643 | 4790 | // sentinel-terminated array, the sentinel will not have been populated by |
| 4644 | 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 | 4793 | const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len); |
| 4647 | 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 | 4796 | try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store); |
| 4650 | 4797 | } |
| 4651 | 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 | 4808 | var array_is_comptime = true; |
| 4655 | 4809 | var first_block_index = block.instructions.items.len; |
| 4656 | 4810 | var make_runtime = false; |
| 4657 | 4811 | |
| 4658 | 4812 | // Collect the comptime element values in case the array literal ends up |
| 4659 | 4813 | // being comptime-known. |
| 4660 | const array_len_s = try sema.usizeCast(block, init_src, array_ty.arrayLenIncludingSentinel()); | |
| 4661 | const element_vals = try sema.arena.alloc(Value, array_len_s); | |
| 4662 | const opt_opv = try sema.typeHasOnePossibleValue(array_ty); | |
| 4814 | const element_vals = try sema.arena.alloc( | |
| 4815 | InternPool.Index, | |
| 4816 | try sema.usizeCast(block, init_src, array_len), | |
| 4817 | ); | |
| 4663 | 4818 | const air_tags = sema.air_instructions.items(.tag); |
| 4664 | 4819 | const air_datas = sema.air_instructions.items(.data); |
| 4665 | 4820 | |
| 4666 | 4821 | outer: for (instrs, 0..) |elem_ptr, i| { |
| 4667 | 4822 | // Determine whether the value stored to this pointer is comptime-known. |
| 4668 | 4823 | |
| 4669 | if (array_ty.isTuple()) { | |
| 4670 | if (array_ty.structFieldValueComptime(i)) |opv| { | |
| 4671 | element_vals[i] = opv; | |
| 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; | |
| 4824 | if (array_ty.isTuple(mod)) { | |
| 4825 | if (try array_ty.structFieldValueComptime(mod, i)) |opv| { | |
| 4826 | element_vals[i] = opv.toIntern(); | |
| 4678 | 4827 | continue; |
| 4679 | 4828 | } |
| 4680 | 4829 | } |
| ... | ... | @@ -4735,7 +4884,7 @@ fn zirValidateArrayInit( |
| 4735 | 4884 | first_block_index = @min(first_block_index, block_index); |
| 4736 | 4885 | } |
| 4737 | 4886 | if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { |
| 4738 | element_vals[i] = val; | |
| 4887 | element_vals[i] = val.toIntern(); | |
| 4739 | 4888 | } else { |
| 4740 | 4889 | array_is_comptime = false; |
| 4741 | 4890 | } |
| ... | ... | @@ -4747,50 +4896,55 @@ fn zirValidateArrayInit( |
| 4747 | 4896 | |
| 4748 | 4897 | if (array_is_comptime) { |
| 4749 | 4898 | if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| { |
| 4750 | if (ptr_val.tag() == .comptime_field_ptr) { | |
| 4751 | // This store was validated by the individual elem ptrs. | |
| 4752 | return; | |
| 4899 | switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { | |
| 4900 | .ptr => |ptr| switch (ptr.addr) { | |
| 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 | 4908 | // Our task is to delete all the `elem_ptr` and `store` instructions, and insert |
| 4757 | 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 | 4910 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4764 | 4911 | |
| 4765 | var array_val = try Value.Tag.aggregate.create(sema.arena, element_vals); | |
| 4766 | if (make_runtime) array_val = try Value.Tag.runtime_value.create(sema.arena, array_val); | |
| 4767 | const array_init = try sema.addConstant(array_ty, array_val); | |
| 4912 | var array_val = try mod.intern(.{ .aggregate = .{ | |
| 4913 | .ty = array_ty.toIntern(), | |
| 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 | 4921 | try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store); |
| 4769 | 4922 | } |
| 4770 | 4923 | } |
| 4771 | 4924 | |
| 4772 | 4925 | fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 4926 | const mod = sema.mod; | |
| 4773 | 4927 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4774 | 4928 | const src = inst_data.src(); |
| 4775 | 4929 | const operand = try sema.resolveInst(inst_data.operand); |
| 4776 | 4930 | const operand_ty = sema.typeOf(operand); |
| 4777 | 4931 | |
| 4778 | if (operand_ty.zigTypeTag() != .Pointer) { | |
| 4779 | return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)}); | |
| 4780 | } else switch (operand_ty.ptrSize()) { | |
| 4932 | if (operand_ty.zigTypeTag(mod) != .Pointer) { | |
| 4933 | return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(mod)}); | |
| 4934 | } else switch (operand_ty.ptrSize(mod)) { | |
| 4781 | 4935 | .One, .C => {}, |
| 4782 | .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}), | |
| 4783 | .Slice => return sema.fail(block, src, "index syntax required for slice 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)}), | |
| 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 | 4941 | // No need to validate the actual pointer value, we don't need it! |
| 4788 | 4942 | return; |
| 4789 | 4943 | } |
| 4790 | 4944 | |
| 4791 | const elem_ty = operand_ty.elemType2(); | |
| 4945 | const elem_ty = operand_ty.elemType2(mod); | |
| 4792 | 4946 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 4793 | if (val.isUndef()) { | |
| 4947 | if (val.isUndef(mod)) { | |
| 4794 | 4948 | return sema.fail(block, src, "cannot dereference undefined value", .{}); |
| 4795 | 4949 | } |
| 4796 | 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 | 4953 | block, |
| 4800 | 4954 | src, |
| 4801 | 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 | 4958 | errdefer msg.destroy(sema.gpa); |
| 4805 | 4959 | |
| 4806 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 4807 | try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl), elem_ty); | |
| 4960 | const src_decl = mod.declPtr(block.src_decl); | |
| 4961 | try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), elem_ty); | |
| 4808 | 4962 | break :msg msg; |
| 4809 | 4963 | }; |
| 4810 | 4964 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -4816,23 +4970,24 @@ fn failWithBadMemberAccess( |
| 4816 | 4970 | block: *Block, |
| 4817 | 4971 | agg_ty: Type, |
| 4818 | 4972 | field_src: LazySrcLoc, |
| 4819 | field_name: []const u8, | |
| 4973 | field_name: InternPool.NullTerminatedString, | |
| 4820 | 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 | 4977 | .Union => "union", |
| 4823 | 4978 | .Struct => "struct", |
| 4824 | 4979 | .Opaque => "opaque", |
| 4825 | 4980 | .Enum => "enum", |
| 4826 | 4981 | else => unreachable, |
| 4827 | 4982 | }; |
| 4828 | if (agg_ty.getOwnerDeclOrNull()) |some| if (sema.mod.declIsRoot(some)) { | |
| 4829 | return sema.fail(block, field_src, "root struct of file '{}' has no member named '{s}'", .{ | |
| 4830 | agg_ty.fmt(sema.mod), field_name, | |
| 4983 | if (agg_ty.getOwnerDeclOrNull(mod)) |some| if (mod.declIsRoot(some)) { | |
| 4984 | return sema.fail(block, field_src, "root struct of file '{}' has no member named '{}'", .{ | |
| 4985 | agg_ty.fmt(mod), field_name.fmt(&mod.intern_pool), | |
| 4831 | 4986 | }); |
| 4832 | 4987 | }; |
| 4833 | 4988 | const msg = msg: { |
| 4834 | const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{ | |
| 4835 | kw_name, agg_ty.fmt(sema.mod), field_name, | |
| 4989 | const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{}'", .{ | |
| 4990 | kw_name, agg_ty.fmt(mod), field_name.fmt(&mod.intern_pool), | |
| 4836 | 4991 | }); |
| 4837 | 4992 | errdefer msg.destroy(sema.gpa); |
| 4838 | 4993 | try sema.addDeclaredHereNote(msg, agg_ty); |
| ... | ... | @@ -4846,22 +5001,22 @@ fn failWithBadStructFieldAccess( |
| 4846 | 5001 | block: *Block, |
| 4847 | 5002 | struct_obj: *Module.Struct, |
| 4848 | 5003 | field_src: LazySrcLoc, |
| 4849 | field_name: []const u8, | |
| 5004 | field_name: InternPool.NullTerminatedString, | |
| 4850 | 5005 | ) CompileError { |
| 5006 | const mod = sema.mod; | |
| 4851 | 5007 | const gpa = sema.gpa; |
| 4852 | 5008 | |
| 4853 | const fqn = try struct_obj.getFullyQualifiedName(sema.mod); | |
| 4854 | defer gpa.free(fqn); | |
| 5009 | const fqn = try struct_obj.getFullyQualifiedName(mod); | |
| 4855 | 5010 | |
| 4856 | 5011 | const msg = msg: { |
| 4857 | 5012 | const msg = try sema.errMsg( |
| 4858 | 5013 | block, |
| 4859 | 5014 | field_src, |
| 4860 | "no field named '{s}' in struct '{s}'", | |
| 4861 | .{ field_name, fqn }, | |
| 5015 | "no field named '{}' in struct '{}'", | |
| 5016 | .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) }, | |
| 4862 | 5017 | ); |
| 4863 | 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 | 5020 | break :msg msg; |
| 4866 | 5021 | }; |
| 4867 | 5022 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -4872,30 +5027,31 @@ fn failWithBadUnionFieldAccess( |
| 4872 | 5027 | block: *Block, |
| 4873 | 5028 | union_obj: *Module.Union, |
| 4874 | 5029 | field_src: LazySrcLoc, |
| 4875 | field_name: []const u8, | |
| 5030 | field_name: InternPool.NullTerminatedString, | |
| 4876 | 5031 | ) CompileError { |
| 5032 | const mod = sema.mod; | |
| 4877 | 5033 | const gpa = sema.gpa; |
| 4878 | 5034 | |
| 4879 | const fqn = try union_obj.getFullyQualifiedName(sema.mod); | |
| 4880 | defer gpa.free(fqn); | |
| 5035 | const fqn = try union_obj.getFullyQualifiedName(mod); | |
| 4881 | 5036 | |
| 4882 | 5037 | const msg = msg: { |
| 4883 | 5038 | const msg = try sema.errMsg( |
| 4884 | 5039 | block, |
| 4885 | 5040 | field_src, |
| 4886 | "no field named '{s}' in union '{s}'", | |
| 4887 | .{ field_name, fqn }, | |
| 5041 | "no field named '{}' in union '{}'", | |
| 5042 | .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) }, | |
| 4888 | 5043 | ); |
| 4889 | 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 | 5046 | break :msg msg; |
| 4892 | 5047 | }; |
| 4893 | 5048 | return sema.failWithOwnedErrorMsg(msg); |
| 4894 | 5049 | } |
| 4895 | 5050 | |
| 4896 | 5051 | fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !void { |
| 4897 | const src_loc = decl_ty.declSrcLocOrNull(sema.mod) orelse return; | |
| 4898 | const category = switch (decl_ty.zigTypeTag()) { | |
| 5052 | const mod = sema.mod; | |
| 5053 | const src_loc = decl_ty.declSrcLocOrNull(mod) orelse return; | |
| 5054 | const category = switch (decl_ty.zigTypeTag(mod)) { | |
| 4899 | 5055 | .Union => "union", |
| 4900 | 5056 | .Struct => "struct", |
| 4901 | 5057 | .Enum => "enum", |
| ... | ... | @@ -4903,7 +5059,7 @@ fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !vo |
| 4903 | 5059 | .ErrorSet => "error set", |
| 4904 | 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 | 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 | 5075 | const src: LazySrcLoc = sema.src; |
| 4920 | 5076 | blk: { |
| 4921 | 5077 | const ptr_inst = Air.refToIndex(ptr) orelse break :blk; |
| 4922 | if (sema.air_instructions.items(.tag)[ptr_inst] != .constant) break :blk; | |
| 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()) { | |
| 5078 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { | |
| 4926 | 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 | 5081 | return sema.storeToInferredAllocComptime(block, src, operand, iac); |
| 4929 | 5082 | }, |
| 4930 | 5083 | .inferred_alloc => { |
| 4931 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; | |
| 4932 | return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc); | |
| 5084 | const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; | |
| 5085 | return sema.storeToInferredAlloc(block, ptr, operand, ia); | |
| 4933 | 5086 | }, |
| 4934 | 5087 | else => break :blk, |
| 4935 | 5088 | } |
| ... | ... | @@ -4947,18 +5100,16 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi |
| 4947 | 5100 | const ptr = try sema.resolveInst(bin_inst.lhs); |
| 4948 | 5101 | const operand = try sema.resolveInst(bin_inst.rhs); |
| 4949 | 5102 | const ptr_inst = Air.refToIndex(ptr).?; |
| 4950 | assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); | |
| 4951 | 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 | 5106 | .inferred_alloc_comptime => { |
| 4956 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; | |
| 5107 | const iac = &air_datas[ptr_inst].inferred_alloc_comptime; | |
| 4957 | 5108 | return sema.storeToInferredAllocComptime(block, src, operand, iac); |
| 4958 | 5109 | }, |
| 4959 | 5110 | .inferred_alloc => { |
| 4960 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; | |
| 4961 | return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc); | |
| 5111 | const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; | |
| 5112 | return sema.storeToInferredAlloc(block, ptr, operand, ia); | |
| 4962 | 5113 | }, |
| 4963 | 5114 | else => unreachable, |
| 4964 | 5115 | } |
| ... | ... | @@ -4969,14 +5120,14 @@ fn storeToInferredAlloc( |
| 4969 | 5120 | block: *Block, |
| 4970 | 5121 | ptr: Air.Inst.Ref, |
| 4971 | 5122 | operand: Air.Inst.Ref, |
| 4972 | inferred_alloc: *Value.Payload.InferredAlloc, | |
| 5123 | inferred_alloc: *InferredAlloc, | |
| 4973 | 5124 | ) CompileError!void { |
| 4974 | 5125 | // Create a store instruction as a placeholder. This will be replaced by a |
| 4975 | 5126 | // proper store sequence once we know the stored type. |
| 4976 | 5127 | const dummy_store = try block.addBinOp(.store, ptr, operand); |
| 4977 | 5128 | // Add the stored instruction to the set we will use to resolve peer types |
| 4978 | 5129 | // for the inferred allocation. |
| 4979 | try inferred_alloc.data.prongs.append(sema.arena, .{ | |
| 5130 | try inferred_alloc.prongs.append(sema.arena, .{ | |
| 4980 | 5131 | .stored_inst = operand, |
| 4981 | 5132 | .placeholder = Air.refToIndex(dummy_store).?, |
| 4982 | 5133 | }); |
| ... | ... | @@ -4987,20 +5138,21 @@ fn storeToInferredAllocComptime( |
| 4987 | 5138 | block: *Block, |
| 4988 | 5139 | src: LazySrcLoc, |
| 4989 | 5140 | operand: Air.Inst.Ref, |
| 4990 | iac: *Value.Payload.InferredAllocComptime, | |
| 5141 | iac: *Air.Inst.Data.InferredAllocComptime, | |
| 4991 | 5142 | ) CompileError!void { |
| 4992 | 5143 | const operand_ty = sema.typeOf(operand); |
| 4993 | 5144 | // There will be only one store_to_inferred_ptr because we are running at comptime. |
| 4994 | 5145 | // The alloc will turn into a Decl. |
| 4995 | 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 | 5148 | var anon_decl = try block.startAnonDecl(); |
| 4998 | 5149 | defer anon_decl.deinit(); |
| 4999 | iac.data.decl_index = try anon_decl.finish( | |
| 5000 | try operand_ty.copy(anon_decl.arena()), | |
| 5001 | try operand_val.copy(anon_decl.arena()), | |
| 5002 | iac.data.alignment, | |
| 5150 | iac.decl_index = try anon_decl.finish( | |
| 5151 | operand_ty, | |
| 5152 | operand_val, | |
| 5153 | iac.alignment.toByteUnits(0), | |
| 5003 | 5154 | ); |
| 5155 | try sema.comptime_mutable_decls.append(iac.decl_index); | |
| 5004 | 5156 | return; |
| 5005 | 5157 | } |
| 5006 | 5158 | |
| ... | ... | @@ -5028,6 +5180,7 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v |
| 5028 | 5180 | const tracy = trace(@src()); |
| 5029 | 5181 | defer tracy.end(); |
| 5030 | 5182 | |
| 5183 | const mod = sema.mod; | |
| 5031 | 5184 | const zir_tags = sema.code.instructions.items(.tag); |
| 5032 | 5185 | const zir_datas = sema.code.instructions.items(.data); |
| 5033 | 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 | 5199 | // %b = store(%a, %c) |
| 5047 | 5200 | // Where %c is an error union or error set. In such case we need to add |
| 5048 | 5201 | // to the current function's inferred error set, if any. |
| 5049 | if (is_ret and (sema.typeOf(operand).zigTypeTag() == .ErrorUnion or | |
| 5050 | sema.typeOf(operand).zigTypeTag() == .ErrorSet) and | |
| 5051 | sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) | |
| 5202 | if (is_ret and (sema.typeOf(operand).zigTypeTag(mod) == .ErrorUnion or | |
| 5203 | sema.typeOf(operand).zigTypeTag(mod) == .ErrorSet) and | |
| 5204 | sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion) | |
| 5052 | 5205 | { |
| 5053 | 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 | 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 { | |
| 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. | |
| 5228 | fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref { | |
| 5079 | 5229 | const mod = sema.mod; |
| 5080 | 5230 | const gpa = sema.gpa; |
| 5081 | const string_bytes = &mod.string_literal_bytes; | |
| 5082 | const StringLiteralAdapter = Module.StringLiteralAdapter; | |
| 5083 | const StringLiteralContext = Module.StringLiteralContext; | |
| 5084 | try string_bytes.ensureUnusedCapacity(gpa, zir_bytes.len); | |
| 5085 | const gop = try mod.string_literal_table.getOrPutContextAdapted(gpa, zir_bytes, StringLiteralAdapter{ | |
| 5086 | .bytes = string_bytes, | |
| 5087 | }, StringLiteralContext{ | |
| 5088 | .bytes = string_bytes, | |
| 5231 | // TODO: write something like getCoercedInts to avoid needing to dupe | |
| 5232 | const duped_bytes = try sema.arena.dupe(u8, bytes); | |
| 5233 | const ty = try mod.arrayType(.{ | |
| 5234 | .len = bytes.len, | |
| 5235 | .child = .u8_type, | |
| 5236 | .sentinel = .zero_u8, | |
| 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 | 5243 | if (!gop.found_existing) { |
| 5091 | gop.key_ptr.* = .{ | |
| 5092 | .index = @intCast(u32, string_bytes.items.len), | |
| 5093 | .len = @intCast(u32, zir_bytes.len), | |
| 5094 | }; | |
| 5095 | string_bytes.appendSliceAssumeCapacity(zir_bytes); | |
| 5096 | gop.value_ptr.* = .none; | |
| 5244 | const new_decl_index = try mod.createAnonymousDecl(block, .{ | |
| 5245 | .ty = ty, | |
| 5246 | .val = val.toValue(), | |
| 5247 | }); | |
| 5248 | gop.value_ptr.* = new_decl_index; | |
| 5249 | try mod.finalizeAnonDecl(new_decl_index); | |
| 5097 | 5250 | } |
| 5098 | const decl_index = gop.value_ptr.unwrap() orelse di: { | |
| 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); | |
| 5251 | return sema.analyzeDeclRef(gop.value_ptr.*); | |
| 5116 | 5252 | } |
| 5117 | 5253 | |
| 5118 | 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 | 5257 | defer tracy.end(); |
| 5122 | 5258 | |
| 5123 | 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 | 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 | 5265 | const tracy = trace(@src()); |
| 5130 | 5266 | defer tracy.end(); |
| 5131 | 5267 | |
| 5132 | const arena = sema.arena; | |
| 5268 | const mod = sema.mod; | |
| 5133 | 5269 | const int = sema.code.instructions.items(.data)[inst].str; |
| 5134 | 5270 | const byte_count = int.len * @sizeOf(std.math.big.Limb); |
| 5135 | 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 | 5277 | @memcpy(mem.sliceAsBytes(limbs), limb_bytes); |
| 5138 | 5278 | |
| 5139 | 5279 | return sema.addConstant( |
| 5140 | Type.initTag(.comptime_int), | |
| 5141 | try Value.Tag.int_big_positive.create(arena, limbs), | |
| 5280 | Type.comptime_int, | |
| 5281 | try mod.intValue_big(Type.comptime_int, .{ | |
| 5282 | .limbs = limbs, | |
| 5283 | .positive = true, | |
| 5284 | }), | |
| 5142 | 5285 | ); |
| 5143 | 5286 | } |
| 5144 | 5287 | |
| 5145 | 5288 | fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5146 | 5289 | _ = block; |
| 5147 | const arena = sema.arena; | |
| 5148 | 5290 | const number = sema.code.instructions.items(.data)[inst].float; |
| 5149 | 5291 | return sema.addConstant( |
| 5150 | Type.initTag(.comptime_float), | |
| 5151 | try Value.Tag.float_64.create(arena, number), | |
| 5292 | Type.comptime_float, | |
| 5293 | try sema.mod.floatValue(Type.comptime_float, number), | |
| 5152 | 5294 | ); |
| 5153 | 5295 | } |
| 5154 | 5296 | |
| 5155 | 5297 | fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5156 | 5298 | _ = block; |
| 5157 | const arena = sema.arena; | |
| 5158 | 5299 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5159 | 5300 | const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; |
| 5160 | 5301 | const number = extra.get(); |
| 5161 | 5302 | return sema.addConstant( |
| 5162 | Type.initTag(.comptime_float), | |
| 5163 | try Value.Tag.float_128.create(arena, number), | |
| 5303 | Type.comptime_float, | |
| 5304 | try sema.mod.floatValue(Type.comptime_float, number), | |
| 5164 | 5305 | ); |
| 5165 | 5306 | } |
| 5166 | 5307 | |
| ... | ... | @@ -5179,7 +5320,9 @@ fn zirCompileLog( |
| 5179 | 5320 | sema: *Sema, |
| 5180 | 5321 | extended: Zir.Inst.Extended.InstData, |
| 5181 | 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 | 5326 | defer sema.mod.compile_log_text = managed.moveToUnmanaged(); |
| 5184 | 5327 | const writer = managed.writer(); |
| 5185 | 5328 | |
| ... | ... | @@ -5192,19 +5335,18 @@ fn zirCompileLog( |
| 5192 | 5335 | |
| 5193 | 5336 | const arg = try sema.resolveInst(arg_ref); |
| 5194 | 5337 | const arg_ty = sema.typeOf(arg); |
| 5195 | if (try sema.resolveMaybeUndefVal(arg)) |val| { | |
| 5196 | try sema.resolveLazyValue(val); | |
| 5338 | if (try sema.resolveMaybeUndefLazyVal(arg)) |val| { | |
| 5197 | 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 | 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 | 5346 | try writer.print("\n", .{}); |
| 5205 | 5347 | |
| 5206 | 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 | 5350 | if (!gop.found_existing) { |
| 5209 | 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 | 5377 | const tracy = trace(@src()); |
| 5236 | 5378 | defer tracy.end(); |
| 5237 | 5379 | |
| 5380 | const mod = sema.mod; | |
| 5238 | 5381 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5239 | 5382 | const src = inst_data.src(); |
| 5240 | 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 | 5427 | try sema.analyzeBody(&loop_block, body); |
| 5285 | 5428 | |
| 5286 | 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 | 5431 | // If the loop ended with a noreturn terminator, then there is no way for it to loop, |
| 5289 | 5432 | // so we can just use the block instead. |
| 5290 | 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 | 5454 | |
| 5312 | 5455 | // we check this here to avoid undefined symbols |
| 5313 | 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 | 5459 | var c_import_buf = std.ArrayList(u8).init(sema.gpa); |
| 5317 | 5460 | defer c_import_buf.deinit(); |
| ... | ... | @@ -5354,7 +5497,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 5354 | 5497 | if (!mod.comp.bin_file.options.link_libc) |
| 5355 | 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 | 5501 | if (!gop.found_existing) { |
| 5359 | 5502 | var errs = try std.ArrayListUnmanaged(Module.CImportError).initCapacity(sema.gpa, c_import_res.errors.len); |
| 5360 | 5503 | errdefer { |
| ... | ... | @@ -5537,7 +5680,7 @@ fn analyzeBlockBody( |
| 5537 | 5680 | |
| 5538 | 5681 | // Blocks must terminate with noreturn instruction. |
| 5539 | 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 | 5685 | if (merges.results.items.len == 0) { |
| 5543 | 5686 | // No need for a block instruction. We can put the new instructions |
| ... | ... | @@ -5578,7 +5721,7 @@ fn analyzeBlockBody( |
| 5578 | 5721 | try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{}); |
| 5579 | 5722 | |
| 5580 | 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 | 5726 | break :msg msg; |
| 5584 | 5727 | }; |
| ... | ... | @@ -5649,15 +5792,16 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 5649 | 5792 | const tracy = trace(@src()); |
| 5650 | 5793 | defer tracy.end(); |
| 5651 | 5794 | |
| 5795 | const mod = sema.mod; | |
| 5652 | 5796 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5653 | 5797 | const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; |
| 5654 | 5798 | const src = inst_data.src(); |
| 5655 | 5799 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 5656 | 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 | 5802 | const decl_index = if (extra.namespace != .none) index_blk: { |
| 5659 | 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 | 5806 | const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false); |
| 5663 | 5807 | break :index_blk maybe_index orelse |
| ... | ... | @@ -5671,10 +5815,10 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 5671 | 5815 | else => |e| return e, |
| 5672 | 5816 | }; |
| 5673 | 5817 | { |
| 5674 | try sema.mod.ensureDeclAnalyzed(decl_index); | |
| 5675 | const exported_decl = sema.mod.declPtr(decl_index); | |
| 5676 | if (exported_decl.val.castTag(.function)) |some| { | |
| 5677 | return sema.analyzeExport(block, src, options, some.data.owner_decl); | |
| 5818 | try mod.ensureDeclAnalyzed(decl_index); | |
| 5819 | const exported_decl = mod.declPtr(decl_index); | |
| 5820 | if (exported_decl.val.getFunction(mod)) |function| { | |
| 5821 | return sema.analyzeExport(block, src, options, function.owner_decl); | |
| 5678 | 5822 | } |
| 5679 | 5823 | } |
| 5680 | 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 | 5841 | }, |
| 5698 | 5842 | else => |e| return e, |
| 5699 | 5843 | }; |
| 5700 | const decl_index = switch (operand.val.tag()) { | |
| 5701 | .function => operand.val.castTag(.function).?.data.owner_decl, | |
| 5702 | else => blk: { | |
| 5703 | var anon_decl = try block.startAnonDecl(); | |
| 5704 | defer anon_decl.deinit(); | |
| 5705 | break :blk try anon_decl.finish( | |
| 5706 | try operand.ty.copy(anon_decl.arena()), | |
| 5707 | try operand.val.copy(anon_decl.arena()), | |
| 5708 | 0, | |
| 5709 | ); | |
| 5710 | }, | |
| 5844 | const decl_index = if (operand.val.getFunction(sema.mod)) |function| function.owner_decl else blk: { | |
| 5845 | var anon_decl = try block.startAnonDecl(); | |
| 5846 | defer anon_decl.deinit(); | |
| 5847 | break :blk try anon_decl.finish( | |
| 5848 | operand.ty, | |
| 5849 | operand.val, | |
| 5850 | 0, | |
| 5851 | ); | |
| 5711 | 5852 | }; |
| 5712 | 5853 | try sema.analyzeExport(block, src, options, decl_index); |
| 5713 | 5854 | } |
| ... | ... | @@ -5716,13 +5857,13 @@ pub fn analyzeExport( |
| 5716 | 5857 | sema: *Sema, |
| 5717 | 5858 | block: *Block, |
| 5718 | 5859 | src: LazySrcLoc, |
| 5719 | borrowed_options: std.builtin.ExportOptions, | |
| 5860 | options: Module.Export.Options, | |
| 5720 | 5861 | exported_decl_index: Decl.Index, |
| 5721 | 5862 | ) !void { |
| 5722 | 5863 | const Export = Module.Export; |
| 5723 | 5864 | const mod = sema.mod; |
| 5724 | 5865 | |
| 5725 | if (borrowed_options.linkage == .Internal) { | |
| 5866 | if (options.linkage == .Internal) { | |
| 5726 | 5867 | return; |
| 5727 | 5868 | } |
| 5728 | 5869 | |
| ... | ... | @@ -5731,11 +5872,11 @@ pub fn analyzeExport( |
| 5731 | 5872 | |
| 5732 | 5873 | if (!try sema.validateExternType(exported_decl.ty, .other)) { |
| 5733 | 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 | 5876 | errdefer msg.destroy(sema.gpa); |
| 5736 | 5877 | |
| 5737 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 5738 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), exported_decl.ty, .other); | |
| 5878 | const src_decl = mod.declPtr(block.src_decl); | |
| 5879 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other); | |
| 5739 | 5880 | |
| 5740 | 5881 | try sema.addDeclaredHereNote(msg, exported_decl.ty); |
| 5741 | 5882 | break :msg msg; |
| ... | ... | @@ -5744,15 +5885,15 @@ pub fn analyzeExport( |
| 5744 | 5885 | } |
| 5745 | 5886 | |
| 5746 | 5887 | // TODO: some backends might support re-exporting extern decls |
| 5747 | if (exported_decl.isExtern()) { | |
| 5888 | if (exported_decl.isExtern(mod)) { | |
| 5748 | 5889 | return sema.fail(block, src, "export target cannot be extern", .{}); |
| 5749 | 5890 | } |
| 5750 | 5891 | |
| 5751 | 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 | 5894 | try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); |
| 5754 | 5895 | |
| 5755 | const gpa = mod.gpa; | |
| 5896 | const gpa = sema.gpa; | |
| 5756 | 5897 | |
| 5757 | 5898 | try mod.decl_exports.ensureUnusedCapacity(gpa, 1); |
| 5758 | 5899 | try mod.export_owners.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -5760,19 +5901,8 @@ pub fn analyzeExport( |
| 5760 | 5901 | const new_export = try gpa.create(Export); |
| 5761 | 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 | 5904 | new_export.* = .{ |
| 5770 | .options = .{ | |
| 5771 | .name = symbol_name, | |
| 5772 | .linkage = borrowed_options.linkage, | |
| 5773 | .section = section, | |
| 5774 | .visibility = borrowed_options.visibility, | |
| 5775 | }, | |
| 5905 | .opts = options, | |
| 5776 | 5906 | .src = src, |
| 5777 | 5907 | .owner_decl = sema.owner_decl_index, |
| 5778 | 5908 | .src_decl = block.src_decl, |
| ... | ... | @@ -5798,6 +5928,7 @@ pub fn analyzeExport( |
| 5798 | 5928 | } |
| 5799 | 5929 | |
| 5800 | 5930 | fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| 5931 | const mod = sema.mod; | |
| 5801 | 5932 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 5802 | 5933 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 5803 | 5934 | const src = LazySrcLoc.nodeOffset(extra.node); |
| ... | ... | @@ -5807,11 +5938,12 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 5807 | 5938 | alignment, |
| 5808 | 5939 | }); |
| 5809 | 5940 | } |
| 5810 | const func = sema.func orelse | |
| 5941 | const func_index = sema.func_index.unwrap() orelse | |
| 5811 | 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); | |
| 5814 | switch (fn_owner_decl.ty.fnCallingConvention()) { | |
| 5945 | const fn_owner_decl = mod.declPtr(func.owner_decl); | |
| 5946 | switch (fn_owner_decl.ty.fnCallingConvention(mod)) { | |
| 5815 | 5947 | .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}), |
| 5816 | 5948 | .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}), |
| 5817 | 5949 | else => if (block.inlining != null) { |
| ... | ... | @@ -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 | 5955 | if (gop.found_existing) { |
| 5824 | 5956 | const msg = msg: { |
| 5825 | 5957 | const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{}); |
| ... | ... | @@ -5971,10 +6103,11 @@ fn addDbgVar( |
| 5971 | 6103 | air_tag: Air.Inst.Tag, |
| 5972 | 6104 | name: []const u8, |
| 5973 | 6105 | ) CompileError!void { |
| 6106 | const mod = sema.mod; | |
| 5974 | 6107 | const operand_ty = sema.typeOf(operand); |
| 5975 | 6108 | switch (air_tag) { |
| 5976 | 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 | 6112 | .dbg_var_val => { |
| 5980 | 6113 | if (!(try sema.typeHasRuntimeBits(operand_ty))) return; |
| ... | ... | @@ -6003,29 +6136,32 @@ fn addDbgVar( |
| 6003 | 6136 | } |
| 6004 | 6137 | |
| 6005 | 6138 | fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6139 | const mod = sema.mod; | |
| 6006 | 6140 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 6007 | 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 | 6143 | const decl_index = try sema.lookupIdentifier(block, src, decl_name); |
| 6010 | 6144 | try sema.addReferencedBy(block, src, decl_index); |
| 6011 | 6145 | return sema.analyzeDeclRef(decl_index); |
| 6012 | 6146 | } |
| 6013 | 6147 | |
| 6014 | 6148 | fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6149 | const mod = sema.mod; | |
| 6015 | 6150 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 6016 | 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 | 6153 | const decl = try sema.lookupIdentifier(block, src, decl_name); |
| 6019 | 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 | 6159 | var namespace = block.namespace; |
| 6024 | 6160 | while (true) { |
| 6025 | 6161 | if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl_index| { |
| 6026 | 6162 | return decl_index; |
| 6027 | 6163 | } |
| 6028 | namespace = namespace.parent orelse break; | |
| 6164 | namespace = mod.namespacePtr(namespace).parent.unwrap() orelse break; | |
| 6029 | 6165 | } |
| 6030 | 6166 | unreachable; // AstGen detects use of undeclared identifier errors. |
| 6031 | 6167 | } |
| ... | ... | @@ -6036,21 +6172,22 @@ fn lookupInNamespace( |
| 6036 | 6172 | sema: *Sema, |
| 6037 | 6173 | block: *Block, |
| 6038 | 6174 | src: LazySrcLoc, |
| 6039 | namespace: *Namespace, | |
| 6040 | ident_name: []const u8, | |
| 6175 | namespace_index: Namespace.Index, | |
| 6176 | ident_name: InternPool.NullTerminatedString, | |
| 6041 | 6177 | observe_usingnamespace: bool, |
| 6042 | 6178 | ) CompileError!?Decl.Index { |
| 6043 | 6179 | const mod = sema.mod; |
| 6044 | 6180 | |
| 6045 | const namespace_decl_index = namespace.getDeclIndex(); | |
| 6046 | const namespace_decl = sema.mod.declPtr(namespace_decl_index); | |
| 6181 | const namespace = mod.namespacePtr(namespace_index); | |
| 6182 | const namespace_decl_index = namespace.getDeclIndex(mod); | |
| 6183 | const namespace_decl = mod.declPtr(namespace_decl_index); | |
| 6047 | 6184 | if (namespace_decl.analysis == .file_failure) { |
| 6048 | 6185 | try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index); |
| 6049 | 6186 | return error.AnalysisFail; |
| 6050 | 6187 | } |
| 6051 | 6188 | |
| 6052 | 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 | 6192 | const gpa = sema.gpa; |
| 6056 | 6193 | var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, bool) = .{}; |
| ... | ... | @@ -6069,7 +6206,7 @@ fn lookupInNamespace( |
| 6069 | 6206 | // Skip decls which are not marked pub, which are in a different |
| 6070 | 6207 | // file than the `a.b`/`@hasDecl` syntax. |
| 6071 | 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 | 6210 | try candidates.append(gpa, decl_index); |
| 6074 | 6211 | } |
| 6075 | 6212 | } |
| ... | ... | @@ -6080,15 +6217,15 @@ fn lookupInNamespace( |
| 6080 | 6217 | if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue; |
| 6081 | 6218 | const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index); |
| 6082 | 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 | 6221 | // Skip usingnamespace decls which are not marked pub, which are in |
| 6085 | 6222 | // a different file than the `a.b`/`@hasDecl` syntax. |
| 6086 | 6223 | continue; |
| 6087 | 6224 | } |
| 6088 | 6225 | try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index); |
| 6089 | const ns_ty = sub_usingnamespace_decl.val.castTag(.ty).?.data; | |
| 6090 | const sub_ns = ns_ty.getNamespace().?; | |
| 6091 | try checked_namespaces.put(gpa, sub_ns, src_file == sub_usingnamespace_decl.getFileScope()); | |
| 6226 | const ns_ty = sub_usingnamespace_decl.val.toType(); | |
| 6227 | const sub_ns = ns_ty.getNamespace(mod).?; | |
| 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 | 6253 | errdefer msg.destroy(gpa); |
| 6117 | 6254 | for (candidates.items) |candidate_index| { |
| 6118 | 6255 | const candidate = mod.declPtr(candidate_index); |
| 6119 | const src_loc = candidate.srcLoc(); | |
| 6256 | const src_loc = candidate.srcLoc(mod); | |
| 6120 | 6257 | try mod.errNoteNonLazy(src_loc, msg, "declared here", .{}); |
| 6121 | 6258 | } |
| 6122 | 6259 | break :msg msg; |
| ... | ... | @@ -6129,9 +6266,6 @@ fn lookupInNamespace( |
| 6129 | 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 | 6269 | // TODO This dependency is too strong. Really, it should only be a dependency |
| 6136 | 6270 | // on the non-existence of `ident_name` in the namespace. We can lessen the number of |
| 6137 | 6271 | // outdated declarations by making this dependency more sophisticated. |
| ... | ... | @@ -6140,22 +6274,28 @@ fn lookupInNamespace( |
| 6140 | 6274 | } |
| 6141 | 6275 | |
| 6142 | 6276 | fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { |
| 6277 | const mod = sema.mod; | |
| 6143 | 6278 | const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; |
| 6144 | if (func_val.isUndef()) return null; | |
| 6145 | const owner_decl_index = switch (func_val.tag()) { | |
| 6146 | .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl, | |
| 6147 | .function => func_val.castTag(.function).?.data.owner_decl, | |
| 6148 | .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, | |
| 6279 | if (func_val.isUndef(mod)) return null; | |
| 6280 | const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { | |
| 6281 | .extern_func => |extern_func| extern_func.decl, | |
| 6282 | .func => |func| mod.funcPtr(func.index).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 | 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 | 6292 | pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { |
| 6293 | const mod = sema.mod; | |
| 6294 | const gpa = sema.gpa; | |
| 6155 | 6295 | const src = sema.src; |
| 6156 | 6296 | |
| 6157 | if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none; | |
| 6158 | if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none; | |
| 6297 | if (!mod.backendSupportsFeature(.error_return_trace)) return .none; | |
| 6298 | if (!mod.comp.bin_file.options.error_return_tracing) return .none; | |
| 6159 | 6299 | |
| 6160 | 6300 | if (block.is_comptime) |
| 6161 | 6301 | return .none; |
| ... | ... | @@ -6168,7 +6308,8 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref |
| 6168 | 6308 | error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, |
| 6169 | 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 | 6313 | error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, |
| 6173 | 6314 | else => |e| return e, |
| 6174 | 6315 | }; |
| ... | ... | @@ -6191,6 +6332,8 @@ fn popErrorReturnTrace( |
| 6191 | 6332 | operand: Air.Inst.Ref, |
| 6192 | 6333 | saved_error_trace_index: Air.Inst.Ref, |
| 6193 | 6334 | ) CompileError!void { |
| 6335 | const mod = sema.mod; | |
| 6336 | const gpa = sema.gpa; | |
| 6194 | 6337 | var is_non_error: ?bool = null; |
| 6195 | 6338 | var is_non_error_inst: Air.Inst.Ref = undefined; |
| 6196 | 6339 | if (operand != .none) { |
| ... | ... | @@ -6205,15 +6348,16 @@ fn popErrorReturnTrace( |
| 6205 | 6348 | |
| 6206 | 6349 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 6207 | 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 | 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 | 6355 | try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); |
| 6212 | 6356 | } else if (is_non_error == null) { |
| 6213 | 6357 | // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need |
| 6214 | 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 | 6361 | const cond_block_inst = try block.addInstAsIndex(.{ |
| 6218 | 6362 | .tag = .block, |
| 6219 | 6363 | .data = .{ |
| ... | ... | @@ -6225,28 +6369,29 @@ fn popErrorReturnTrace( |
| 6225 | 6369 | }); |
| 6226 | 6370 | |
| 6227 | 6371 | var then_block = block.makeSubBlock(); |
| 6228 | defer then_block.instructions.deinit(sema.gpa); | |
| 6372 | defer then_block.instructions.deinit(gpa); | |
| 6229 | 6373 | |
| 6230 | 6374 | // If non-error, then pop the error return trace by restoring the index. |
| 6231 | 6375 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 6232 | 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 | 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 | 6381 | try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); |
| 6237 | 6382 | _ = try then_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); |
| 6238 | 6383 | |
| 6239 | 6384 | // Otherwise, do nothing |
| 6240 | 6385 | var else_block = block.makeSubBlock(); |
| 6241 | defer else_block.instructions.deinit(sema.gpa); | |
| 6386 | defer else_block.instructions.deinit(gpa); | |
| 6242 | 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 | 6390 | then_block.instructions.items.len + else_block.instructions.items.len + |
| 6246 | 6391 | @typeInfo(Air.Block).Struct.fields.len + 1); // +1 for the sole .cond_br instruction in the .block |
| 6247 | 6392 | |
| 6248 | 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 | 6395 | .operand = is_non_error_inst, |
| 6251 | 6396 | .payload = sema.addExtraAssumeCapacity(Air.CondBr{ |
| 6252 | 6397 | .then_body_len = @intCast(u32, then_block.instructions.items.len), |
| ... | ... | @@ -6270,6 +6415,7 @@ fn zirCall( |
| 6270 | 6415 | const tracy = trace(@src()); |
| 6271 | 6416 | defer tracy.end(); |
| 6272 | 6417 | |
| 6418 | const mod = sema.mod; | |
| 6273 | 6419 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 6274 | 6420 | const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; |
| 6275 | 6421 | const call_src = inst_data.src(); |
| ... | ... | @@ -6288,7 +6434,7 @@ fn zirCall( |
| 6288 | 6434 | .direct => .{ .direct = try sema.resolveInst(extra.data.callee) }, |
| 6289 | 6435 | .field => blk: { |
| 6290 | 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 | 6438 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 6293 | 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 | 6466 | var input_is_error = false; |
| 6321 | 6467 | const block_index = @intCast(Air.Inst.Index, block.instructions.items.len); |
| 6322 | 6468 | |
| 6323 | const func_ty_info = func_ty.fnInfo(); | |
| 6324 | const fn_params_len = func_ty_info.param_types.len; | |
| 6469 | const fn_params_len = mod.typeToFunc(func_ty).?.param_types.len; | |
| 6325 | 6470 | const parent_comptime = block.is_comptime; |
| 6326 | 6471 | // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument. |
| 6327 | 6472 | var extra_index: usize = 0; |
| ... | ... | @@ -6330,32 +6475,33 @@ fn zirCall( |
| 6330 | 6475 | extra_index += 1; |
| 6331 | 6476 | arg_index += 1; |
| 6332 | 6477 | }) { |
| 6478 | const func_ty_info = mod.typeToFunc(func_ty).?; | |
| 6333 | 6479 | const arg_end = sema.code.extra[extra.end + extra_index]; |
| 6334 | 6480 | defer arg_start = arg_end; |
| 6335 | 6481 | |
| 6336 | 6482 | // Generate args to comptime params in comptime block. |
| 6337 | 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 | 6485 | block.is_comptime = true; |
| 6340 | 6486 | // TODO set comptime_reason |
| 6341 | 6487 | } |
| 6342 | 6488 | |
| 6343 | 6489 | sema.inst_map.putAssumeCapacity(inst, inst: { |
| 6344 | 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 | 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 | 6499 | const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); |
| 6354 | 6500 | const resolved_ty = sema.typeOf(resolved); |
| 6355 | if (resolved_ty.zigTypeTag() == .NoReturn) { | |
| 6501 | if (resolved_ty.zigTypeTag(mod) == .NoReturn) { | |
| 6356 | 6502 | return resolved; |
| 6357 | 6503 | } |
| 6358 | if (resolved_ty.isError()) { | |
| 6504 | if (resolved_ty.isError(mod)) { | |
| 6359 | 6505 | input_is_error = true; |
| 6360 | 6506 | } |
| 6361 | 6507 | resolved_args[arg_index] = resolved; |
| ... | ... | @@ -6367,7 +6513,7 @@ fn zirCall( |
| 6367 | 6513 | // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction. |
| 6368 | 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 | 6517 | !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) |
| 6372 | 6518 | { |
| 6373 | 6519 | const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: { |
| ... | ... | @@ -6375,15 +6521,16 @@ fn zirCall( |
| 6375 | 6521 | }; |
| 6376 | 6522 | |
| 6377 | 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 | 6525 | return call_inst; // call to "fn(...) noreturn", don't pop |
| 6380 | 6526 | |
| 6381 | 6527 | // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only |
| 6382 | 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 | 6530 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 6385 | 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 | 6535 | // Insert a save instruction before the arg resolution + call instructions we just generated |
| 6389 | 6536 | const save_inst = try block.insertInst(block_index, .{ |
| ... | ... | @@ -6417,24 +6564,24 @@ fn checkCallArgumentCount( |
| 6417 | 6564 | total_args: usize, |
| 6418 | 6565 | member_fn: bool, |
| 6419 | 6566 | ) !Type { |
| 6567 | const mod = sema.mod; | |
| 6420 | 6568 | const func_ty = func_ty: { |
| 6421 | switch (callee_ty.zigTypeTag()) { | |
| 6569 | switch (callee_ty.zigTypeTag(mod)) { | |
| 6422 | 6570 | .Fn => break :func_ty callee_ty, |
| 6423 | 6571 | .Pointer => { |
| 6424 | const ptr_info = callee_ty.ptrInfo().data; | |
| 6425 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) { | |
| 6572 | const ptr_info = callee_ty.ptrInfo(mod); | |
| 6573 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) { | |
| 6426 | 6574 | break :func_ty ptr_info.pointee_type; |
| 6427 | 6575 | } |
| 6428 | 6576 | }, |
| 6429 | 6577 | .Optional => { |
| 6430 | var buf: Type.Payload.ElemType = undefined; | |
| 6431 | const opt_child = callee_ty.optionalChild(&buf); | |
| 6432 | if (opt_child.zigTypeTag() == .Fn or (opt_child.isSinglePointer() and | |
| 6433 | opt_child.childType().zigTypeTag() == .Fn)) | |
| 6578 | const opt_child = callee_ty.optionalChild(mod); | |
| 6579 | if (opt_child.zigTypeTag(mod) == .Fn or (opt_child.isSinglePointer(mod) and | |
| 6580 | opt_child.childType(mod).zigTypeTag(mod) == .Fn)) | |
| 6434 | 6581 | { |
| 6435 | 6582 | const msg = msg: { |
| 6436 | 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 | 6586 | errdefer msg.destroy(sema.gpa); |
| 6440 | 6587 | try sema.errNote(block, func_src, msg, "consider using '.?', 'orelse' or 'if'", .{}); |
| ... | ... | @@ -6445,10 +6592,10 @@ fn checkCallArgumentCount( |
| 6445 | 6592 | }, |
| 6446 | 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 | 6599 | const fn_params_len = func_ty_info.param_types.len; |
| 6453 | 6600 | const args_len = total_args - @boolToInt(member_fn); |
| 6454 | 6601 | if (func_ty_info.is_var_args) { |
| ... | ... | @@ -6475,7 +6622,7 @@ fn checkCallArgumentCount( |
| 6475 | 6622 | ); |
| 6476 | 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 | 6626 | break :msg msg; |
| 6480 | 6627 | }; |
| 6481 | 6628 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -6488,22 +6635,23 @@ fn callBuiltin( |
| 6488 | 6635 | modifier: std.builtin.CallModifier, |
| 6489 | 6636 | args: []const Air.Inst.Ref, |
| 6490 | 6637 | ) !void { |
| 6638 | const mod = sema.mod; | |
| 6491 | 6639 | const callee_ty = sema.typeOf(builtin_fn); |
| 6492 | 6640 | const func_ty = func_ty: { |
| 6493 | switch (callee_ty.zigTypeTag()) { | |
| 6641 | switch (callee_ty.zigTypeTag(mod)) { | |
| 6494 | 6642 | .Fn => break :func_ty callee_ty, |
| 6495 | 6643 | .Pointer => { |
| 6496 | const ptr_info = callee_ty.ptrInfo().data; | |
| 6497 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) { | |
| 6644 | const ptr_info = callee_ty.ptrInfo(mod); | |
| 6645 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) { | |
| 6498 | 6646 | break :func_ty ptr_info.pointee_type; |
| 6499 | 6647 | } |
| 6500 | 6648 | }, |
| 6501 | 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 | 6655 | const fn_params_len = func_ty_info.param_types.len; |
| 6508 | 6656 | if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) { |
| 6509 | 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 | 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 | 6662 | fn analyzeCall( |
| 6585 | 6663 | sema: *Sema, |
| 6586 | 6664 | block: *Block, |
| ... | ... | @@ -6597,7 +6675,7 @@ fn analyzeCall( |
| 6597 | 6675 | const mod = sema.mod; |
| 6598 | 6676 | |
| 6599 | 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 | 6679 | const fn_params_len = func_ty_info.param_types.len; |
| 6602 | 6680 | const cc = func_ty_info.cc; |
| 6603 | 6681 | if (cc == .Naked) { |
| ... | ... | @@ -6611,7 +6689,7 @@ fn analyzeCall( |
| 6611 | 6689 | ); |
| 6612 | 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 | 6693 | break :msg msg; |
| 6616 | 6694 | }; |
| 6617 | 6695 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -6645,7 +6723,7 @@ fn analyzeCall( |
| 6645 | 6723 | var comptime_reason_buf: Block.ComptimeReason = undefined; |
| 6646 | 6724 | var comptime_reason: ?*const Block.ComptimeReason = null; |
| 6647 | 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 | 6727 | is_comptime_call = ct; |
| 6650 | 6728 | if (ct) { |
| 6651 | 6729 | // stage1 can't handle doing this directly |
| ... | ... | @@ -6653,7 +6731,7 @@ fn analyzeCall( |
| 6653 | 6731 | .block = block, |
| 6654 | 6732 | .func = func, |
| 6655 | 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 | 6736 | comptime_reason = &comptime_reason_buf; |
| 6659 | 6737 | } |
| ... | ... | @@ -6671,7 +6749,7 @@ fn analyzeCall( |
| 6671 | 6749 | func, |
| 6672 | 6750 | func_src, |
| 6673 | 6751 | call_src, |
| 6674 | func_ty_info, | |
| 6752 | func_ty, | |
| 6675 | 6753 | ensure_result_used, |
| 6676 | 6754 | uncasted_args, |
| 6677 | 6755 | call_tag, |
| ... | ... | @@ -6691,7 +6769,7 @@ fn analyzeCall( |
| 6691 | 6769 | .block = block, |
| 6692 | 6770 | .func = func, |
| 6693 | 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 | 6774 | comptime_reason = &comptime_reason_buf; |
| 6697 | 6775 | }, |
| ... | ... | @@ -6708,18 +6786,21 @@ fn analyzeCall( |
| 6708 | 6786 | if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err); |
| 6709 | 6787 | return err; |
| 6710 | 6788 | }; |
| 6711 | const module_fn = switch (func_val.tag()) { | |
| 6712 | .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data, | |
| 6713 | .function => func_val.castTag(.function).?.data, | |
| 6714 | .extern_fn => return sema.fail(block, call_src, "{s} call of extern function", .{ | |
| 6789 | const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { | |
| 6790 | .extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{ | |
| 6715 | 6791 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), |
| 6716 | 6792 | }), |
| 6717 | else => { | |
| 6718 | assert(callee_ty.isPtrAtRuntime()); | |
| 6719 | return sema.fail(block, call_src, "{s} call of function pointer", .{ | |
| 6720 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | |
| 6721 | }); | |
| 6793 | .func => |function| function.index, | |
| 6794 | .ptr => |ptr| switch (ptr.addr) { | |
| 6795 | .decl => |decl| mod.declPtr(decl).val.getFunctionIndex(mod).unwrap().?, | |
| 6796 | else => { | |
| 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 | 6805 | if (func_ty_info.is_var_args) { |
| 6725 | 6806 | return sema.fail(block, call_src, "{s} call of variadic function", .{ |
| ... | ... | @@ -6752,8 +6833,9 @@ fn analyzeCall( |
| 6752 | 6833 | // In order to save a bit of stack space, directly modify Sema rather |
| 6753 | 6834 | // than create a child one. |
| 6754 | 6835 | const parent_zir = sema.code; |
| 6836 | const module_fn = mod.funcPtr(module_fn_index); | |
| 6755 | 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 | 6839 | defer sema.code = parent_zir; |
| 6758 | 6840 | |
| 6759 | 6841 | try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body); |
| ... | ... | @@ -6767,14 +6849,17 @@ fn analyzeCall( |
| 6767 | 6849 | } |
| 6768 | 6850 | |
| 6769 | 6851 | const parent_func = sema.func; |
| 6852 | const parent_func_index = sema.func_index; | |
| 6770 | 6853 | sema.func = module_fn; |
| 6854 | sema.func_index = module_fn_index.toOptional(); | |
| 6771 | 6855 | defer sema.func = parent_func; |
| 6856 | defer sema.func_index = parent_func_index; | |
| 6772 | 6857 | |
| 6773 | 6858 | const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry; |
| 6774 | 6859 | sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index; |
| 6775 | 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 | 6863 | defer wip_captures.deinit(); |
| 6779 | 6864 | |
| 6780 | 6865 | var child_block: Block = .{ |
| ... | ... | @@ -6797,28 +6882,18 @@ fn analyzeCall( |
| 6797 | 6882 | defer child_block.instructions.deinit(gpa); |
| 6798 | 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 | 6885 | try sema.emitBackwardBranch(block, call_src); |
| 6814 | 6886 | |
| 6815 | // Whether this call should be memoized, set to false if the call can mutate | |
| 6816 | // comptime state. | |
| 6887 | // Whether this call should be memoized, set to false if the call can mutate comptime state. | |
| 6817 | 6888 | var should_memoize = true; |
| 6818 | 6889 | |
| 6819 | var new_fn_info = fn_owner_decl.ty.fnInfo(); | |
| 6820 | new_fn_info.param_types = try sema.arena.alloc(Type, new_fn_info.param_types.len); | |
| 6821 | new_fn_info.comptime_params = (try sema.arena.alloc(bool, new_fn_info.param_types.len)).ptr; | |
| 6890 | // If it's a comptime function call, we need to memoize it as long as no external | |
| 6891 | // comptime memory is mutated. | |
| 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 | 6898 | // This will have return instructions analyzed as break instructions to |
| 6824 | 6899 | // the block_inst above. Here we are performing "comptime/inline semantic analysis" |
| ... | ... | @@ -6837,31 +6912,31 @@ fn analyzeCall( |
| 6837 | 6912 | &child_block, |
| 6838 | 6913 | .unneeded, |
| 6839 | 6914 | inst, |
| 6840 | new_fn_info, | |
| 6915 | &new_fn_info, | |
| 6841 | 6916 | &arg_i, |
| 6842 | 6917 | uncasted_args, |
| 6843 | 6918 | is_comptime_call, |
| 6844 | 6919 | &should_memoize, |
| 6845 | memoized_call_key, | |
| 6846 | func_ty_info.param_types, | |
| 6920 | memoized_arg_values, | |
| 6921 | mod.typeToFunc(func_ty).?.param_types, | |
| 6847 | 6922 | func, |
| 6848 | 6923 | &has_comptime_args, |
| 6849 | 6924 | ) catch |err| switch (err) { |
| 6850 | 6925 | error.NeededSourceLocation => { |
| 6851 | 6926 | _ = sema.inst_map.remove(inst); |
| 6852 | const decl = sema.mod.declPtr(block.src_decl); | |
| 6927 | const decl = mod.declPtr(block.src_decl); | |
| 6853 | 6928 | try sema.analyzeInlineCallArg( |
| 6854 | 6929 | block, |
| 6855 | 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 | 6932 | inst, |
| 6858 | new_fn_info, | |
| 6933 | &new_fn_info, | |
| 6859 | 6934 | &arg_i, |
| 6860 | 6935 | uncasted_args, |
| 6861 | 6936 | is_comptime_call, |
| 6862 | 6937 | &should_memoize, |
| 6863 | memoized_call_key, | |
| 6864 | func_ty_info.param_types, | |
| 6938 | memoized_arg_values, | |
| 6939 | mod.typeToFunc(func_ty).?.param_types, | |
| 6865 | 6940 | func, |
| 6866 | 6941 | &has_comptime_args, |
| 6867 | 6942 | ); |
| ... | ... | @@ -6897,21 +6972,15 @@ fn analyzeCall( |
| 6897 | 6972 | // Create a fresh inferred error set type for inline/comptime calls. |
| 6898 | 6973 | const fn_ret_ty = blk: { |
| 6899 | 6974 | if (module_fn.hasInferredErrorSet(mod)) { |
| 6900 | const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); | |
| 6901 | node.data = .{ .func = module_fn }; | |
| 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, | |
| 6975 | const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ | |
| 6976 | .func = module_fn_index, | |
| 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 | 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 | 6984 | const parent_fn_ret_ty = sema.fn_ret_ty; |
| 6916 | 6985 | sema.fn_ret_ty = fn_ret_ty; |
| 6917 | 6986 | defer sema.fn_ret_ty = parent_fn_ret_ty; |
| ... | ... | @@ -6920,23 +6989,22 @@ fn analyzeCall( |
| 6920 | 6989 | // bug generating invalid LLVM IR. |
| 6921 | 6990 | const res2: Air.Inst.Ref = res2: { |
| 6922 | 6991 | if (should_memoize and is_comptime_call) { |
| 6923 | if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| { | |
| 6924 | const ty_inst = try sema.addType(fn_ret_ty); | |
| 6925 | try sema.air_values.append(gpa, result.val); | |
| 6926 | sema.air_instructions.set(block_inst, .{ | |
| 6927 | .tag = .constant, | |
| 6928 | .data = .{ .ty_pl = .{ | |
| 6929 | .ty = ty_inst, | |
| 6930 | .payload = @intCast(u32, sema.air_values.items.len - 1), | |
| 6931 | } }, | |
| 6932 | }); | |
| 6933 | break :res2 Air.indexToRef(block_inst); | |
| 6992 | if (mod.intern_pool.getIfExists(.{ .memoized_call = .{ | |
| 6993 | .func = module_fn_index, | |
| 6994 | .arg_values = memoized_arg_values, | |
| 6995 | .result = .none, | |
| 6996 | } })) |memoized_call_index| { | |
| 6997 | const memoized_call = mod.intern_pool.indexToKey(memoized_call_index).memoized_call; | |
| 6998 | break :res2 try sema.addConstant( | |
| 6999 | mod.intern_pool.typeOf(memoized_call.result).toType(), | |
| 7000 | memoized_call.result.toValue(), | |
| 7001 | ); | |
| 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 | 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 | 7009 | const zir_tags = sema.code.instructions.items(.tag); |
| 6942 | 7010 | for (fn_info.param_body) |param| switch (zir_tags[param]) { |
| ... | ... | @@ -6968,7 +7036,7 @@ fn analyzeCall( |
| 6968 | 7036 | error.ComptimeReturn => break :result inlining.comptime_result, |
| 6969 | 7037 | error.AnalysisFail => { |
| 6970 | 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 | 7040 | try sema.errNote(block, call_src, err_msg, "called from here", .{}); |
| 6973 | 7041 | err_msg.clearTrace(sema.gpa); |
| 6974 | 7042 | return err; |
| ... | ... | @@ -6978,11 +7046,11 @@ fn analyzeCall( |
| 6978 | 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 | 7050 | try sema.emitDbgInline( |
| 6983 | 7051 | block, |
| 6984 | module_fn, | |
| 6985 | parent_func.?, | |
| 7052 | module_fn_index, | |
| 7053 | parent_func_index.unwrap().?, | |
| 6986 | 7054 | mod.declPtr(parent_func.?.owner_decl).ty, |
| 6987 | 7055 | .dbg_inline_end, |
| 6988 | 7056 | ); |
| ... | ... | @@ -6993,23 +7061,11 @@ fn analyzeCall( |
| 6993 | 7061 | |
| 6994 | 7062 | // TODO: check whether any external comptime memory was mutated by the |
| 6995 | 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 | |
| 6997 | // it should be fine to use the Decl arena for the function. | |
| 6998 | { | |
| 6999 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); | |
| 7000 | errdefer arena_allocator.deinit(); | |
| 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 | } | |
| 7064 | _ = try mod.intern(.{ .memoized_call = .{ | |
| 7065 | .func = module_fn_index, | |
| 7066 | .arg_values = memoized_arg_values, | |
| 7067 | .result = try result_val.intern(fn_ret_ty, mod), | |
| 7068 | } }); | |
| 7013 | 7069 | } |
| 7014 | 7070 | |
| 7015 | 7071 | break :res2 result; |
| ... | ... | @@ -7028,7 +7084,7 @@ fn analyzeCall( |
| 7028 | 7084 | .func_inst = func, |
| 7029 | 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 | 7088 | args[i] = sema.analyzeCallArg( |
| 7033 | 7089 | block, |
| 7034 | 7090 | .unneeded, |
| ... | ... | @@ -7037,10 +7093,10 @@ fn analyzeCall( |
| 7037 | 7093 | opts, |
| 7038 | 7094 | ) catch |err| switch (err) { |
| 7039 | 7095 | error.NeededSourceLocation => { |
| 7040 | const decl = sema.mod.declPtr(block.src_decl); | |
| 7096 | const decl = mod.declPtr(block.src_decl); | |
| 7041 | 7097 | _ = try sema.analyzeCallArg( |
| 7042 | 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 | 7100 | param_ty, |
| 7045 | 7101 | uncasted_arg, |
| 7046 | 7102 | opts, |
| ... | ... | @@ -7052,11 +7108,11 @@ fn analyzeCall( |
| 7052 | 7108 | } else { |
| 7053 | 7109 | args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) { |
| 7054 | 7110 | error.NeededSourceLocation => { |
| 7055 | const decl = sema.mod.declPtr(block.src_decl); | |
| 7111 | const decl = mod.declPtr(block.src_decl); | |
| 7056 | 7112 | _ = try sema.coerceVarArgParam( |
| 7057 | 7113 | block, |
| 7058 | 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 | 7117 | unreachable; |
| 7062 | 7118 | }, |
| ... | ... | @@ -7067,14 +7123,14 @@ fn analyzeCall( |
| 7067 | 7123 | |
| 7068 | 7124 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); |
| 7069 | 7125 | |
| 7070 | try sema.queueFullTypeResolution(func_ty_info.return_type); | |
| 7071 | if (sema.owner_func != null and func_ty_info.return_type.isError()) { | |
| 7126 | try sema.queueFullTypeResolution(func_ty_info.return_type.toType()); | |
| 7127 | if (sema.owner_func != null and func_ty_info.return_type.toType().isError(mod)) { | |
| 7072 | 7128 | sema.owner_func.?.calls_or_awaits_errorable_fn = true; |
| 7073 | 7129 | } |
| 7074 | 7130 | |
| 7075 | 7131 | if (try sema.resolveMaybeUndefVal(func)) |func_val| { |
| 7076 | if (func_val.castTag(.function)) |func_obj| { | |
| 7077 | try sema.mod.ensureFuncBodyAnalysisQueued(func_obj.data); | |
| 7132 | if (mod.intern_pool.indexToFunc(func_val.toIntern()).unwrap()) |func_index| { | |
| 7133 | try mod.ensureFuncBodyAnalysisQueued(func_index); | |
| 7078 | 7134 | } |
| 7079 | 7135 | } |
| 7080 | 7136 | |
| ... | ... | @@ -7096,23 +7152,24 @@ fn analyzeCall( |
| 7096 | 7152 | try sema.ensureResultUsed(block, sema.typeOf(func_inst), call_src); |
| 7097 | 7153 | } |
| 7098 | 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 | 7157 | // Function pointers and extern functions aren't guaranteed to |
| 7101 | 7158 | // actually be noreturn so we add a safety check for them. |
| 7102 | check: { | |
| 7103 | var func_val = (try sema.resolveMaybeUndefVal(func)) orelse break :check; | |
| 7104 | switch (func_val.tag()) { | |
| 7105 | .function, .decl_ref => { | |
| 7106 | _ = try block.addNoOp(.unreach); | |
| 7107 | return Air.Inst.Ref.unreachable_value; | |
| 7159 | if (try sema.resolveMaybeUndefVal(func)) |func_val| { | |
| 7160 | switch (mod.intern_pool.indexToKey(func_val.toIntern())) { | |
| 7161 | .func => break :skip_safety, | |
| 7162 | .ptr => |ptr| switch (ptr.addr) { | |
| 7163 | .decl => |decl| if (!mod.declPtr(decl).isExtern(mod)) break :skip_safety, | |
| 7164 | else => {}, | |
| 7108 | 7165 | }, |
| 7109 | else => break :check, | |
| 7166 | else => {}, | |
| 7110 | 7167 | } |
| 7111 | 7168 | } |
| 7112 | ||
| 7113 | 7169 | try sema.safetyPanic(block, .noreturn_returned); |
| 7114 | 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 | 7173 | _ = try block.addNoOp(.unreach); |
| 7117 | 7174 | return Air.Inst.Ref.unreachable_value; |
| 7118 | 7175 | } |
| ... | ... | @@ -7126,17 +7183,18 @@ fn analyzeCall( |
| 7126 | 7183 | } |
| 7127 | 7184 | |
| 7128 | 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(); | |
| 7130 | const backend = sema.mod.comp.getZigBackend(); | |
| 7186 | const mod = sema.mod; | |
| 7187 | const target = mod.getTarget(); | |
| 7188 | const backend = mod.comp.getZigBackend(); | |
| 7131 | 7189 | if (!target_util.supportsTailCall(target, backend)) { |
| 7132 | 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 | 7191 | @tagName(backend), @tagName(target.cpu.arch), |
| 7134 | 7192 | }); |
| 7135 | 7193 | } |
| 7136 | const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl); | |
| 7137 | if (!func_ty.eql(func_decl.ty, sema.mod)) { | |
| 7194 | const func_decl = mod.declPtr(sema.owner_func.?.owner_decl); | |
| 7195 | if (!func_ty.eql(func_decl.ty, mod)) { | |
| 7138 | 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 | 7200 | _ = try block.addUnOp(.ret, result); |
| ... | ... | @@ -7149,16 +7207,17 @@ fn analyzeInlineCallArg( |
| 7149 | 7207 | param_block: *Block, |
| 7150 | 7208 | arg_src: LazySrcLoc, |
| 7151 | 7209 | inst: Zir.Inst.Index, |
| 7152 | new_fn_info: Type.Payload.Function.Data, | |
| 7210 | new_fn_info: *InternPool.Key.FuncType, | |
| 7153 | 7211 | arg_i: *usize, |
| 7154 | 7212 | uncasted_args: []const Air.Inst.Ref, |
| 7155 | 7213 | is_comptime_call: bool, |
| 7156 | 7214 | should_memoize: *bool, |
| 7157 | memoized_call_key: Module.MemoizedCall.Key, | |
| 7158 | raw_param_types: []const Type, | |
| 7215 | memoized_arg_values: []InternPool.Index, | |
| 7216 | raw_param_types: []const InternPool.Index, | |
| 7159 | 7217 | func_inst: Air.Inst.Ref, |
| 7160 | 7218 | has_comptime_args: *bool, |
| 7161 | 7219 | ) !void { |
| 7220 | const mod = sema.mod; | |
| 7162 | 7221 | const zir_tags = sema.code.instructions.items(.tag); |
| 7163 | 7222 | switch (zir_tags[inst]) { |
| 7164 | 7223 | .param_comptime, .param_anytype_comptime => has_comptime_args.* = true, |
| ... | ... | @@ -7174,13 +7233,14 @@ fn analyzeInlineCallArg( |
| 7174 | 7233 | const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 7175 | 7234 | const param_ty = param_ty: { |
| 7176 | 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 | 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 | 7241 | new_fn_info.param_types[arg_i.*] = param_ty; |
| 7182 | 7242 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 7183 | if (try sema.typeRequiresComptime(param_ty)) { | |
| 7243 | if (try sema.typeRequiresComptime(param_ty.toType())) { | |
| 7184 | 7244 | _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| { |
| 7185 | 7245 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); |
| 7186 | 7246 | return err; |
| ... | ... | @@ -7188,7 +7248,7 @@ fn analyzeInlineCallArg( |
| 7188 | 7248 | } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) { |
| 7189 | 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 | 7252 | .func_inst = func_inst, |
| 7193 | 7253 | .param_i = @intCast(u32, arg_i.*), |
| 7194 | 7254 | } }) catch |err| switch (err) { |
| ... | ... | @@ -7202,24 +7262,20 @@ fn analyzeInlineCallArg( |
| 7202 | 7262 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); |
| 7203 | 7263 | return err; |
| 7204 | 7264 | }; |
| 7205 | switch (arg_val.tag()) { | |
| 7265 | switch (arg_val.toIntern()) { | |
| 7206 | 7266 | .generic_poison, .generic_poison_type => { |
| 7207 | 7267 | // This function is currently evaluated as part of an as-of-yet unresolvable |
| 7208 | 7268 | // parameter or return type. |
| 7209 | 7269 | return error.GenericPoison; |
| 7210 | 7270 | }, |
| 7211 | 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 | }, | |
| 7271 | else => {}, | |
| 7217 | 7272 | } |
| 7218 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); | |
| 7219 | memoized_call_key.args[arg_i.*] = .{ | |
| 7220 | .ty = param_ty, | |
| 7221 | .val = arg_val, | |
| 7222 | }; | |
| 7273 | // Needed so that lazy values do not trigger | |
| 7274 | // assertion due to type not being resolved | |
| 7275 | // when the hash function is called. | |
| 7276 | const resolved_arg_val = try sema.resolveLazyValue(arg_val); | |
| 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 | 7279 | } else { |
| 7224 | 7280 | sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); |
| 7225 | 7281 | } |
| ... | ... | @@ -7233,7 +7289,7 @@ fn analyzeInlineCallArg( |
| 7233 | 7289 | .param_anytype, .param_anytype_comptime => { |
| 7234 | 7290 | // No coercion needed. |
| 7235 | 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 | 7294 | if (is_comptime_call) { |
| 7239 | 7295 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); |
| ... | ... | @@ -7241,24 +7297,20 @@ fn analyzeInlineCallArg( |
| 7241 | 7297 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); |
| 7242 | 7298 | return err; |
| 7243 | 7299 | }; |
| 7244 | switch (arg_val.tag()) { | |
| 7300 | switch (arg_val.toIntern()) { | |
| 7245 | 7301 | .generic_poison, .generic_poison_type => { |
| 7246 | 7302 | // This function is currently evaluated as part of an as-of-yet unresolvable |
| 7247 | 7303 | // parameter or return type. |
| 7248 | 7304 | return error.GenericPoison; |
| 7249 | 7305 | }, |
| 7250 | 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 | }, | |
| 7306 | else => {}, | |
| 7256 | 7307 | } |
| 7257 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); | |
| 7258 | memoized_call_key.args[arg_i.*] = .{ | |
| 7259 | .ty = sema.typeOf(uncasted_arg), | |
| 7260 | .val = arg_val, | |
| 7261 | }; | |
| 7308 | // Needed so that lazy values do not trigger | |
| 7309 | // assertion due to type not being resolved | |
| 7310 | // when the hash function is called. | |
| 7311 | const resolved_arg_val = try sema.resolveLazyValue(arg_val); | |
| 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 | 7314 | } else { |
| 7263 | 7315 | if (zir_tags[inst] == .param_anytype_comptime) { |
| 7264 | 7316 | _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); |
| ... | ... | @@ -7298,14 +7350,15 @@ fn analyzeGenericCallArg( |
| 7298 | 7350 | uncasted_arg: Air.Inst.Ref, |
| 7299 | 7351 | comptime_arg: TypedValue, |
| 7300 | 7352 | runtime_args: []Air.Inst.Ref, |
| 7301 | new_fn_info: Type.Payload.Function.Data, | |
| 7353 | new_fn_info: InternPool.Key.FuncType, | |
| 7302 | 7354 | runtime_i: *u32, |
| 7303 | 7355 | ) !void { |
| 7304 | const is_runtime = comptime_arg.val.tag() == .generic_poison and | |
| 7305 | comptime_arg.ty.hasRuntimeBits() and | |
| 7356 | const mod = sema.mod; | |
| 7357 | const is_runtime = comptime_arg.val.isGenericPoison() and | |
| 7358 | comptime_arg.ty.hasRuntimeBits(mod) and | |
| 7306 | 7359 | !(try sema.typeRequiresComptime(comptime_arg.ty)); |
| 7307 | 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 | 7362 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 7310 | 7363 | try sema.queueFullTypeResolution(param_ty); |
| 7311 | 7364 | runtime_args[runtime_i.*] = casted_arg; |
| ... | ... | @@ -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 { | |
| 7319 | const arg_val = try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime"); | |
| 7320 | try sema.resolveLazyValue(arg_val); | |
| 7321 | return arg_val; | |
| 7371 | fn analyzeGenericCallArgVal( | |
| 7372 | sema: *Sema, | |
| 7373 | block: *Block, | |
| 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 | 7383 | fn instantiateGenericCall( |
| ... | ... | @@ -7327,7 +7386,7 @@ fn instantiateGenericCall( |
| 7327 | 7386 | func: Air.Inst.Ref, |
| 7328 | 7387 | func_src: LazySrcLoc, |
| 7329 | 7388 | call_src: LazySrcLoc, |
| 7330 | func_ty_info: Type.Payload.Function.Data, | |
| 7389 | generic_func_ty: Type, | |
| 7331 | 7390 | ensure_result_used: bool, |
| 7332 | 7391 | uncasted_args: []const Air.Inst.Ref, |
| 7333 | 7392 | call_tag: Air.Inst.Tag, |
| ... | ... | @@ -7338,46 +7397,41 @@ fn instantiateGenericCall( |
| 7338 | 7397 | const gpa = sema.gpa; |
| 7339 | 7398 | |
| 7340 | 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()) { | |
| 7342 | .function => func_val.castTag(.function).?.data, | |
| 7343 | .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data, | |
| 7400 | const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { | |
| 7401 | .func => |function| function.index, | |
| 7402 | .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?, | |
| 7344 | 7403 | else => unreachable, |
| 7345 | 7404 | }; |
| 7405 | const module_fn = mod.funcPtr(module_fn_index); | |
| 7346 | 7406 | // Check the Module's generic function map with an adapted context, so that we |
| 7347 | 7407 | // can match against `uncasted_args` rather than doing the work below to create a |
| 7348 | 7408 | // generic Scope only to junk it if it matches an existing instantiation. |
| 7349 | 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 | 7412 | const fn_zir = namespace.file_scope.zir; |
| 7352 | 7413 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 7353 | 7414 | const zir_tags = fn_zir.instructions.items(.tag); |
| 7354 | 7415 | |
| 7355 | // This hash must match `Module.MonomorphedFuncsContext.hash`. | |
| 7356 | // For parameters explicitly marked comptime and simple parameter type expressions, | |
| 7357 | // we know whether a parameter is elided from a monomorphed function, and can | |
| 7358 | // use it in the hash here. However, for parameter type expressions that are not | |
| 7359 | // explicitly marked comptime and rely on previous parameter comptime values, we | |
| 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; | |
| 7416 | const monomorphed_args = try sema.arena.alloc(InternPool.Index, mod.typeToFunc(generic_func_ty).?.param_types.len); | |
| 7417 | const callee_index = callee: { | |
| 7418 | var arg_i: usize = 0; | |
| 7419 | var monomorphed_arg_i: u32 = 0; | |
| 7420 | var known_unique = false; | |
| 7368 | 7421 | for (fn_info.param_body) |inst| { |
| 7422 | const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?; | |
| 7369 | 7423 | var is_comptime = false; |
| 7370 | 7424 | var is_anytype = false; |
| 7371 | 7425 | switch (zir_tags[inst]) { |
| 7372 | 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 | 7429 | .param_comptime => { |
| 7376 | 7430 | is_comptime = true; |
| 7377 | 7431 | }, |
| 7378 | 7432 | .param_anytype => { |
| 7379 | 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 | 7436 | .param_anytype_comptime => { |
| 7383 | 7437 | is_anytype = true; |
| ... | ... | @@ -7386,87 +7440,90 @@ fn instantiateGenericCall( |
| 7386 | 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 | 7468 | if (is_comptime or is_anytype) { |
| 7391 | 7469 | // Tuple default values are a part of the type and need to be |
| 7392 | 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 | 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 | 7476 | error.NeededSourceLocation => { |
| 7399 | const decl = sema.mod.declPtr(block.src_decl); | |
| 7400 | const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src); | |
| 7401 | _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]); | |
| 7477 | const decl = mod.declPtr(block.src_decl); | |
| 7478 | const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src); | |
| 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 | 7489 | unreachable; |
| 7403 | 7490 | }, |
| 7404 | 7491 | else => |e| return e, |
| 7405 | 7492 | }; |
| 7406 | arg_val.hashUncoerced(arg_ty, &hasher, mod); | |
| 7407 | if (is_anytype) { | |
| 7408 | arg_ty.hashWithHasher(&hasher, mod); | |
| 7409 | generic_args[i] = .{ | |
| 7410 | .ty = arg_ty, | |
| 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 | }; | |
| 7493 | monomorphed_args[monomorphed_arg_i] = casted_arg.toIntern(); | |
| 7494 | monomorphed_arg_i += 1; | |
| 7495 | } else if (is_anytype or is_generic) { | |
| 7496 | monomorphed_args[monomorphed_arg_i] = try mod.intern(.{ .undef = arg_ty }); | |
| 7497 | monomorphed_arg_i += 1; | |
| 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 = .{ | |
| 7443 | .generic_fn = module_fn, | |
| 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); | |
| 7511 | const new_module_func_index = try mod.createFunc(undefined); | |
| 7512 | const new_module_func = mod.funcPtr(new_module_func_index); | |
| 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 | 7514 | new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional(); |
| 7457 | 7515 | new_module_func.comptime_args = null; |
| 7458 | gop.key_ptr.* = new_module_func; | |
| 7459 | 7516 | |
| 7460 | 7517 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 7461 | 7518 | |
| 7462 | 7519 | // Create a Decl for the new function. |
| 7463 | const src_decl_index = namespace.getDeclIndex(); | |
| 7520 | const src_decl_index = namespace.getDeclIndex(mod); | |
| 7464 | 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 | 7523 | const new_decl = mod.declPtr(new_decl_index); |
| 7467 | 7524 | // TODO better names for generic function instantiations |
| 7468 | const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{ | |
| 7469 | fn_owner_decl.name, @enumToInt(new_decl_index), | |
| 7525 | const decl_name = try mod.intern_pool.getOrPutStringFmt(gpa, "{}__anon_{d}", .{ | |
| 7526 | fn_owner_decl.name.fmt(&mod.intern_pool), @enumToInt(new_decl_index), | |
| 7470 | 7527 | }); |
| 7471 | 7528 | new_decl.name = decl_name; |
| 7472 | 7529 | new_decl.src_line = fn_owner_decl.src_line; |
| ... | ... | @@ -7488,25 +7545,21 @@ fn instantiateGenericCall( |
| 7488 | 7545 | assert(new_decl.dependencies.keys().len == 0); |
| 7489 | 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 | 7548 | const new_func = sema.resolveGenericInstantiationType( |
| 7495 | 7549 | block, |
| 7496 | new_decl_arena_allocator, | |
| 7497 | 7550 | fn_zir, |
| 7498 | 7551 | new_decl, |
| 7499 | 7552 | new_decl_index, |
| 7500 | 7553 | uncasted_args, |
| 7501 | module_fn, | |
| 7502 | new_module_func, | |
| 7503 | namespace, | |
| 7504 | func_ty_info, | |
| 7554 | monomorphed_arg_i, | |
| 7555 | module_fn_index, | |
| 7556 | new_module_func_index, | |
| 7557 | namespace_index, | |
| 7558 | generic_func_ty, | |
| 7505 | 7559 | call_src, |
| 7506 | 7560 | bound_arg_src, |
| 7507 | 7561 | ) catch |err| switch (err) { |
| 7508 | 7562 | error.GenericPoison, error.ComptimeReturn => { |
| 7509 | new_decl_arena.deinit(); | |
| 7510 | 7563 | // Resolving the new function type below will possibly declare more decl dependencies |
| 7511 | 7564 | // and so we remove them all here in case of error. |
| 7512 | 7565 | for (new_decl.dependencies.keys()) |dep_index| { |
| ... | ... | @@ -7515,16 +7568,10 @@ fn instantiateGenericCall( |
| 7515 | 7568 | } |
| 7516 | 7569 | assert(namespace.anon_decls.orderedRemove(new_decl_index)); |
| 7517 | 7570 | mod.destroyDecl(new_decl_index); |
| 7518 | assert(mod.monomorphed_funcs.remove(new_module_func)); | |
| 7519 | gpa.destroy(new_module_func); | |
| 7571 | mod.destroyFunc(new_module_func_index); | |
| 7520 | 7572 | return err; |
| 7521 | 7573 | }, |
| 7522 | 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 | 7575 | // TODO look up the compile error that happened here and attach a note to it |
| 7529 | 7576 | // pointing here, at the generic instantiation callsite. |
| 7530 | 7577 | if (sema.owner_func) |owner_func| { |
| ... | ... | @@ -7535,12 +7582,10 @@ fn instantiateGenericCall( |
| 7535 | 7582 | return err; |
| 7536 | 7583 | }, |
| 7537 | 7584 | }; |
| 7538 | errdefer new_decl_arena.deinit(); | |
| 7539 | 7585 | |
| 7540 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 7541 | 7586 | break :callee new_func; |
| 7542 | } else gop.key_ptr.*; | |
| 7543 | ||
| 7587 | }; | |
| 7588 | const callee = mod.funcPtr(callee_index); | |
| 7544 | 7589 | callee.branch_quota = @max(callee.branch_quota, sema.branch_quota); |
| 7545 | 7590 | |
| 7546 | 7591 | const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl); |
| ... | ... | @@ -7548,8 +7593,7 @@ fn instantiateGenericCall( |
| 7548 | 7593 | // Make a runtime call to the new function, making sure to omit the comptime args. |
| 7549 | 7594 | const comptime_args = callee.comptime_args.?; |
| 7550 | 7595 | const func_ty = mod.declPtr(callee.owner_decl).ty; |
| 7551 | const new_fn_info = func_ty.fnInfo(); | |
| 7552 | const runtime_args_len = @intCast(u32, new_fn_info.param_types.len); | |
| 7596 | const runtime_args_len = @intCast(u32, mod.typeToFunc(func_ty).?.param_types.len); | |
| 7553 | 7597 | const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); |
| 7554 | 7598 | { |
| 7555 | 7599 | var runtime_i: u32 = 0; |
| ... | ... | @@ -7565,18 +7609,18 @@ fn instantiateGenericCall( |
| 7565 | 7609 | uncasted_args[total_i], |
| 7566 | 7610 | comptime_args[total_i], |
| 7567 | 7611 | runtime_args, |
| 7568 | new_fn_info, | |
| 7612 | mod.typeToFunc(func_ty).?, | |
| 7569 | 7613 | &runtime_i, |
| 7570 | 7614 | ) catch |err| switch (err) { |
| 7571 | 7615 | error.NeededSourceLocation => { |
| 7572 | const decl = sema.mod.declPtr(block.src_decl); | |
| 7616 | const decl = mod.declPtr(block.src_decl); | |
| 7573 | 7617 | _ = try sema.analyzeGenericCallArg( |
| 7574 | 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 | 7620 | uncasted_args[total_i], |
| 7577 | 7621 | comptime_args[total_i], |
| 7578 | 7622 | runtime_args, |
| 7579 | new_fn_info, | |
| 7623 | mod.typeToFunc(func_ty).?, | |
| 7580 | 7624 | &runtime_i, |
| 7581 | 7625 | ); |
| 7582 | 7626 | unreachable; |
| ... | ... | @@ -7586,16 +7630,16 @@ fn instantiateGenericCall( |
| 7586 | 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 | 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 | 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 | 7644 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 7601 | 7645 | runtime_args_len); |
| ... | ... | @@ -7616,7 +7660,7 @@ fn instantiateGenericCall( |
| 7616 | 7660 | if (call_tag == .call_always_tail) { |
| 7617 | 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 | 7664 | _ = try block.addNoOp(.unreach); |
| 7621 | 7665 | return Air.Inst.Ref.unreachable_value; |
| 7622 | 7666 | } |
| ... | ... | @@ -7626,22 +7670,23 @@ fn instantiateGenericCall( |
| 7626 | 7670 | fn resolveGenericInstantiationType( |
| 7627 | 7671 | sema: *Sema, |
| 7628 | 7672 | block: *Block, |
| 7629 | new_decl_arena_allocator: Allocator, | |
| 7630 | 7673 | fn_zir: Zir, |
| 7631 | 7674 | new_decl: *Decl, |
| 7632 | 7675 | new_decl_index: Decl.Index, |
| 7633 | 7676 | uncasted_args: []const Air.Inst.Ref, |
| 7634 | module_fn: *Module.Fn, | |
| 7635 | new_module_func: *Module.Fn, | |
| 7636 | namespace: *Namespace, | |
| 7637 | func_ty_info: Type.Payload.Function.Data, | |
| 7677 | monomorphed_args_len: u32, | |
| 7678 | module_fn_index: Module.Fn.Index, | |
| 7679 | new_module_func: Module.Fn.Index, | |
| 7680 | namespace: Namespace.Index, | |
| 7681 | generic_func_ty: Type, | |
| 7638 | 7682 | call_src: LazySrcLoc, |
| 7639 | 7683 | bound_arg_src: ?LazySrcLoc, |
| 7640 | ) !*Module.Fn { | |
| 7684 | ) !Module.Fn.Index { | |
| 7641 | 7685 | const mod = sema.mod; |
| 7642 | 7686 | const gpa = sema.gpa; |
| 7643 | 7687 | |
| 7644 | 7688 | const zir_tags = fn_zir.instructions.items(.tag); |
| 7689 | const module_fn = mod.funcPtr(module_fn_index); | |
| 7645 | 7690 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 7646 | 7691 | |
| 7647 | 7692 | // Re-run the block that creates the function, with the comptime parameters |
| ... | ... | @@ -7652,23 +7697,26 @@ fn resolveGenericInstantiationType( |
| 7652 | 7697 | .mod = mod, |
| 7653 | 7698 | .gpa = gpa, |
| 7654 | 7699 | .arena = sema.arena, |
| 7655 | .perm_arena = new_decl_arena_allocator, | |
| 7656 | 7700 | .code = fn_zir, |
| 7657 | 7701 | .owner_decl = new_decl, |
| 7658 | 7702 | .owner_decl_index = new_decl_index, |
| 7659 | 7703 | .func = null, |
| 7704 | .func_index = .none, | |
| 7660 | 7705 | .fn_ret_ty = Type.void, |
| 7661 | 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 | 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 | 7712 | .is_generic_instantiation = true, |
| 7666 | 7713 | .branch_quota = sema.branch_quota, |
| 7667 | 7714 | .branch_count = sema.branch_count, |
| 7715 | .comptime_mutable_decls = sema.comptime_mutable_decls, | |
| 7668 | 7716 | }; |
| 7669 | 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 | 7720 | defer wip_captures.deinit(); |
| 7673 | 7721 | |
| 7674 | 7722 | var child_block: Block = .{ |
| ... | ... | @@ -7690,18 +7738,19 @@ fn resolveGenericInstantiationType( |
| 7690 | 7738 | |
| 7691 | 7739 | var arg_i: usize = 0; |
| 7692 | 7740 | for (fn_info.param_body) |inst| { |
| 7741 | const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?; | |
| 7693 | 7742 | var is_comptime = false; |
| 7694 | 7743 | var is_anytype = false; |
| 7695 | 7744 | switch (zir_tags[inst]) { |
| 7696 | 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 | 7748 | .param_comptime => { |
| 7700 | 7749 | is_comptime = true; |
| 7701 | 7750 | }, |
| 7702 | 7751 | .param_anytype => { |
| 7703 | 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 | 7755 | .param_anytype_comptime => { |
| 7707 | 7756 | is_anytype = true; |
| ... | ... | @@ -7719,8 +7768,8 @@ fn resolveGenericInstantiationType( |
| 7719 | 7768 | if (try sema.typeRequiresComptime(arg_ty)) { |
| 7720 | 7769 | const arg_val = sema.resolveConstValue(block, .unneeded, arg, "") catch |err| switch (err) { |
| 7721 | 7770 | error.NeededSourceLocation => { |
| 7722 | const decl = sema.mod.declPtr(block.src_decl); | |
| 7723 | const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src); | |
| 7771 | const decl = mod.declPtr(block.src_decl); | |
| 7772 | const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src); | |
| 7724 | 7773 | _ = try sema.resolveConstValue(block, arg_src, arg, "argument to parameter with comptime-only type must be comptime-known"); |
| 7725 | 7774 | unreachable; |
| 7726 | 7775 | }, |
| ... | ... | @@ -7752,50 +7801,61 @@ fn resolveGenericInstantiationType( |
| 7752 | 7801 | |
| 7753 | 7802 | const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst); |
| 7754 | 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; | |
| 7756 | errdefer new_func.deinit(gpa); | |
| 7804 | const new_func = new_func_val.getFunctionIndex(mod).unwrap().?; | |
| 7757 | 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 | 7812 | arg_i = 0; |
| 7760 | 7813 | for (fn_info.param_body) |inst| { |
| 7814 | const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?; | |
| 7761 | 7815 | var is_comptime = false; |
| 7816 | var is_anytype = false; | |
| 7762 | 7817 | switch (zir_tags[inst]) { |
| 7763 | 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 | 7821 | .param_comptime => { |
| 7767 | 7822 | is_comptime = true; |
| 7768 | 7823 | }, |
| 7769 | 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 | 7828 | .param_anytype_comptime => { |
| 7829 | is_anytype = true; | |
| 7773 | 7830 | is_comptime = true; |
| 7774 | 7831 | }, |
| 7775 | 7832 | else => continue, |
| 7776 | 7833 | } |
| 7777 | 7834 | |
| 7778 | // We populate the Type here regardless because it is needed by | |
| 7779 | // `GenericCallAdapter.eql` as well as function body analysis. | |
| 7780 | // Whether it is anytype is communicated by `isAnytypeParam`. | |
| 7835 | const param_ty = generic_func_ty_info.param_types[arg_i]; | |
| 7836 | const is_generic = !is_anytype and param_ty == .generic_poison_type; | |
| 7837 | ||
| 7781 | 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)) { | |
| 7785 | is_comptime = true; | |
| 7786 | } | |
| 7841 | if (is_generic) if (mod.monomorphed_funcs.fetchPutAssumeCapacityContext(.{ | |
| 7842 | .func = module_fn_index, | |
| 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 | 7848 | if (is_comptime) { |
| 7789 | 7849 | const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?; |
| 7790 | child_sema.comptime_args[arg_i] = .{ | |
| 7791 | .ty = copied_arg_ty, | |
| 7792 | .val = try arg_val.copy(new_decl_arena_allocator), | |
| 7793 | }; | |
| 7850 | monomorphed_args[monomorphed_arg_i] = arg_val.toIntern(); | |
| 7851 | monomorphed_arg_i += 1; | |
| 7852 | child_sema.comptime_args[arg_i] = .{ .ty = arg_ty, .val = arg_val }; | |
| 7794 | 7853 | } else { |
| 7795 | child_sema.comptime_args[arg_i] = .{ | |
| 7796 | .ty = copied_arg_ty, | |
| 7797 | .val = Value.initTag(.generic_poison), | |
| 7798 | }; | |
| 7854 | if (is_anytype or is_generic) { | |
| 7855 | monomorphed_args[monomorphed_arg_i] = try mod.intern(.{ .undef = arg_ty.toIntern() }); | |
| 7856 | monomorphed_arg_i += 1; | |
| 7857 | } | |
| 7858 | child_sema.comptime_args[arg_i] = .{ .ty = arg_ty, .val = Value.generic_poison }; | |
| 7799 | 7859 | } |
| 7800 | 7860 | |
| 7801 | 7861 | arg_i += 1; |
| ... | ... | @@ -7804,11 +7864,11 @@ fn resolveGenericInstantiationType( |
| 7804 | 7864 | try wip_captures.finalize(); |
| 7805 | 7865 | |
| 7806 | 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 | 7868 | // If the call evaluated to a return type that requires comptime, never mind |
| 7809 | 7869 | // our generic instantiation. Instead we need to perform a comptime call. |
| 7810 | const new_fn_info = new_decl.ty.fnInfo(); | |
| 7811 | if (try sema.typeRequiresComptime(new_fn_info.return_type)) { | |
| 7870 | const new_fn_info = mod.typeToFunc(new_decl.ty).?; | |
| 7871 | if (try sema.typeRequiresComptime(new_fn_info.return_type.toType())) { | |
| 7812 | 7872 | return error.ComptimeReturn; |
| 7813 | 7873 | } |
| 7814 | 7874 | // Similarly, if the call evaluated to a generic type we need to instead |
| ... | ... | @@ -7817,15 +7877,20 @@ fn resolveGenericInstantiationType( |
| 7817 | 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 | 7884 | new_decl.@"align" = 0; |
| 7822 | 7885 | new_decl.has_tv = true; |
| 7823 | 7886 | new_decl.owns_tv = true; |
| 7824 | 7887 | new_decl.analysis = .complete; |
| 7825 | 7888 | |
| 7826 | log.debug("generic function '{s}' instantiated with type {}", .{ | |
| 7827 | new_decl.name, new_decl.ty.fmtDebug(), | |
| 7828 | }); | |
| 7889 | mod.monomorphed_funcs.putAssumeCapacityNoClobberContext(.{ | |
| 7890 | .func = module_fn_index, | |
| 7891 | .args_index = monomorphed_args_index, | |
| 7892 | .args_len = monomorphed_arg_i, | |
| 7893 | }, new_decl.val.toIntern(), .{ .mod = mod }); | |
| 7829 | 7894 | |
| 7830 | 7895 | // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field |
| 7831 | 7896 | // will be populated, ensuring it will have `analyzeBody` called with the ZIR |
| ... | ... | @@ -7835,46 +7900,46 @@ fn resolveGenericInstantiationType( |
| 7835 | 7900 | } |
| 7836 | 7901 | |
| 7837 | 7902 | fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { |
| 7838 | if (!ty.isSimpleTupleOrAnonStruct()) return; | |
| 7839 | const tuple = ty.tupleFields(); | |
| 7840 | for (tuple.values, 0..) |field_val, i| { | |
| 7841 | try sema.resolveTupleLazyValues(block, src, tuple.types[i]); | |
| 7842 | if (field_val.tag() == .unreachable_value) continue; | |
| 7843 | try sema.resolveLazyValue(field_val); | |
| 7903 | const mod = sema.mod; | |
| 7904 | const tuple = switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 7905 | .anon_struct_type => |tuple| tuple, | |
| 7906 | else => return, | |
| 7907 | }; | |
| 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 | 7916 | fn emitDbgInline( |
| 7848 | 7917 | sema: *Sema, |
| 7849 | 7918 | block: *Block, |
| 7850 | old_func: *Module.Fn, | |
| 7851 | new_func: *Module.Fn, | |
| 7919 | old_func: Module.Fn.Index, | |
| 7920 | new_func: Module.Fn.Index, | |
| 7852 | 7921 | new_func_ty: Type, |
| 7853 | 7922 | tag: Air.Inst.Tag, |
| 7854 | 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 | 7927 | // Recursive inline call; no dbg_inline needed. |
| 7858 | 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 | 7930 | _ = try block.addInst(.{ |
| 7862 | 7931 | .tag = tag, |
| 7863 | .data = .{ .ty_pl = .{ | |
| 7932 | .data = .{ .ty_fn = .{ | |
| 7864 | 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 { | |
| 7871 | _ = block; | |
| 7872 | const tracy = trace(@src()); | |
| 7873 | defer tracy.end(); | |
| 7874 | ||
| 7939 | fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 7940 | const mod = sema.mod; | |
| 7875 | 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); | |
| 7877 | ||
| 7942 | const ty = try mod.intType(int_type.signedness, int_type.bit_count); | |
| 7878 | 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 | 7947 | const tracy = trace(@src()); |
| 7883 | 7948 | defer tracy.end(); |
| 7884 | 7949 | |
| 7950 | const mod = sema.mod; | |
| 7885 | 7951 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 7886 | 7952 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; |
| 7887 | 7953 | const child_type = try sema.resolveType(block, operand_src, inst_data.operand); |
| 7888 | if (child_type.zigTypeTag() == .Opaque) { | |
| 7889 | return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); | |
| 7890 | } else if (child_type.zigTypeTag() == .Null) { | |
| 7891 | return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); | |
| 7954 | if (child_type.zigTypeTag(mod) == .Opaque) { | |
| 7955 | return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(mod)}); | |
| 7956 | } else if (child_type.zigTypeTag(mod) == .Null) { | |
| 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 | 7961 | return sema.addType(opt_type); |
| 7896 | 7962 | } |
| 7897 | 7963 | |
| 7898 | 7964 | fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 7965 | const mod = sema.mod; | |
| 7899 | 7966 | const bin = sema.code.instructions.items(.data)[inst].bin; |
| 7900 | 7967 | const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs); |
| 7901 | assert(indexable_ty.isIndexable()); // validated by a previous instruction | |
| 7902 | if (indexable_ty.zigTypeTag() == .Struct) { | |
| 7903 | const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs)); | |
| 7968 | assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction | |
| 7969 | if (indexable_ty.zigTypeTag(mod) == .Struct) { | |
| 7970 | const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs), mod); | |
| 7904 | 7971 | return sema.addType(elem_type); |
| 7905 | 7972 | } else { |
| 7906 | const elem_type = indexable_ty.elemType2(); | |
| 7973 | const elem_type = indexable_ty.elemType2(mod); | |
| 7907 | 7974 | return sema.addType(elem_type); |
| 7908 | 7975 | } |
| 7909 | 7976 | } |
| 7910 | 7977 | |
| 7911 | 7978 | fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 7979 | const mod = sema.mod; | |
| 7912 | 7980 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 7913 | 7981 | const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 7914 | 7982 | const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 7915 | 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 | 7985 | const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs); |
| 7918 | 7986 | try sema.checkVectorElemType(block, elem_type_src, elem_type); |
| 7919 | const vector_type = try Type.Tag.vector.create(sema.arena, .{ | |
| 7920 | .len = @intCast(u32, len), | |
| 7921 | .elem_type = elem_type, | |
| 7987 | const vector_type = try mod.vectorType(.{ | |
| 7988 | .len = len, | |
| 7989 | .child = elem_type.toIntern(), | |
| 7922 | 7990 | }); |
| 7923 | 7991 | return sema.addType(vector_type); |
| 7924 | 7992 | } |
| ... | ... | @@ -7960,9 +8028,10 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil |
| 7960 | 8028 | } |
| 7961 | 8029 | |
| 7962 | 8030 | fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: LazySrcLoc) !void { |
| 7963 | if (elem_type.zigTypeTag() == .Opaque) { | |
| 7964 | return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(sema.mod)}); | |
| 7965 | } else if (elem_type.zigTypeTag() == .NoReturn) { | |
| 8031 | const mod = sema.mod; | |
| 8032 | if (elem_type.zigTypeTag(mod) == .Opaque) { | |
| 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 | 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 | 8044 | if (true) { |
| 7976 | 8045 | return sema.failWithUseOfAsync(block, inst_data.src()); |
| 7977 | 8046 | } |
| 8047 | const mod = sema.mod; | |
| 7978 | 8048 | const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node }; |
| 7979 | 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 | 8052 | return sema.addType(anyframe_type); |
| 7983 | 8053 | } |
| ... | ... | @@ -7986,6 +8056,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 7986 | 8056 | const tracy = trace(@src()); |
| 7987 | 8057 | defer tracy.end(); |
| 7988 | 8058 | |
| 8059 | const mod = sema.mod; | |
| 7989 | 8060 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 7990 | 8061 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 7991 | 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 | 8064 | const error_set = try sema.resolveType(block, lhs_src, extra.lhs); |
| 7994 | 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 | 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 | 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 | 8074 | return sema.addType(err_union_ty); |
| 8004 | 8075 | } |
| 8005 | 8076 | |
| 8006 | 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 | 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 | 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 | 8090 | fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8019 | 8091 | _ = block; |
| 8020 | const tracy = trace(@src()); | |
| 8021 | defer tracy.end(); | |
| 8022 | ||
| 8092 | const mod = sema.mod; | |
| 8023 | 8093 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 8024 | ||
| 8025 | // Create an anonymous error set type with only this error value, and return the value. | |
| 8026 | const kv = try sema.mod.getErrorValue(inst_data.get(sema.code)); | |
| 8027 | const result_type = try Type.Tag.error_set_single.create(sema.arena, kv.key); | |
| 8028 | return sema.addConstant( | |
| 8029 | result_type, | |
| 8030 | try Value.Tag.@"error".create(sema.arena, .{ | |
| 8031 | .name = kv.key, | |
| 8032 | }), | |
| 8033 | ); | |
| 8094 | const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); | |
| 8095 | _ = try mod.getErrorValue(name); | |
| 8096 | // Create an error set type with only this error value, and return the value. | |
| 8097 | const error_set_type = try mod.singleErrorSetType(name); | |
| 8098 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ | |
| 8099 | .ty = error_set_type.toIntern(), | |
| 8100 | .name = name, | |
| 8101 | } })).toValue()); | |
| 8034 | 8102 | } |
| 8035 | 8103 | |
| 8036 | 8104 | fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 8037 | 8105 | const tracy = trace(@src()); |
| 8038 | 8106 | defer tracy.end(); |
| 8039 | 8107 | |
| 8108 | const mod = sema.mod; | |
| 8040 | 8109 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 8041 | 8110 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 8042 | 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 | 8113 | const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src); |
| 8045 | 8114 | |
| 8046 | 8115 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 8047 | if (val.isUndef()) { | |
| 8116 | if (val.isUndef(mod)) { | |
| 8048 | 8117 | return sema.addConstUndef(Type.err_int); |
| 8049 | 8118 | } |
| 8050 | switch (val.tag()) { | |
| 8051 | .@"error" => { | |
| 8052 | const payload = try sema.arena.create(Value.Payload.U64); | |
| 8053 | payload.* = .{ | |
| 8054 | .base = .{ .tag = .int_u64 }, | |
| 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 | } | |
| 8119 | const err_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; | |
| 8120 | return sema.addConstant(Type.err_int, try mod.intValue( | |
| 8121 | Type.err_int, | |
| 8122 | try mod.getErrorValue(err_name), | |
| 8123 | )); | |
| 8066 | 8124 | } |
| 8067 | 8125 | |
| 8068 | 8126 | const op_ty = sema.typeOf(uncasted_operand); |
| 8069 | 8127 | try sema.resolveInferredErrorSetTy(block, src, op_ty); |
| 8070 | if (!op_ty.isAnyError()) { | |
| 8071 | const names = op_ty.errorSetNames(); | |
| 8128 | if (!op_ty.isAnyError(mod)) { | |
| 8129 | const names = op_ty.errorSetNames(mod); | |
| 8072 | 8130 | switch (names.len) { |
| 8073 | 0 => return sema.addConstant(Type.err_int, Value.zero), | |
| 8074 | 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?), | |
| 8131 | 0 => return sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 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 | 8136 | else => {}, |
| 8076 | 8137 | } |
| 8077 | 8138 | } |
| ... | ... | @@ -8084,28 +8145,26 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 8084 | 8145 | const tracy = trace(@src()); |
| 8085 | 8146 | defer tracy.end(); |
| 8086 | 8147 | |
| 8148 | const mod = sema.mod; | |
| 8087 | 8149 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 8088 | 8150 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 8089 | 8151 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 8090 | 8152 | const uncasted_operand = try sema.resolveInst(extra.operand); |
| 8091 | 8153 | const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src); |
| 8092 | const target = sema.mod.getTarget(); | |
| 8093 | 8154 | |
| 8094 | 8155 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { |
| 8095 | const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(target)); | |
| 8096 | if (int > sema.mod.global_error_set.count() or int == 0) | |
| 8156 | const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(mod)); | |
| 8157 | if (int > mod.global_error_set.count() or int == 0) | |
| 8097 | 8158 | return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); |
| 8098 | const payload = try sema.arena.create(Value.Payload.Error); | |
| 8099 | payload.* = .{ | |
| 8100 | .base = .{ .tag = .@"error" }, | |
| 8101 | .data = .{ .name = sema.mod.error_name_list.items[int] }, | |
| 8102 | }; | |
| 8103 | return sema.addConstant(Type.anyerror, Value.initPayload(&payload.base)); | |
| 8159 | return sema.addConstant(Type.anyerror, (try mod.intern(.{ .err = .{ | |
| 8160 | .ty = .anyerror_type, | |
| 8161 | .name = mod.global_error_set.keys()[int], | |
| 8162 | } })).toValue()); | |
| 8104 | 8163 | } |
| 8105 | 8164 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 8106 | 8165 | if (block.wantSafety()) { |
| 8107 | 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 | 8168 | const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val); |
| 8110 | 8169 | const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero); |
| 8111 | 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 | 8182 | const tracy = trace(@src()); |
| 8124 | 8183 | defer tracy.end(); |
| 8125 | 8184 | |
| 8185 | const mod = sema.mod; | |
| 8126 | 8186 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 8127 | 8187 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 8128 | 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 | 8190 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| 8131 | 8191 | const lhs = try sema.resolveInst(extra.lhs); |
| 8132 | 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 | 8194 | const msg = msg: { |
| 8135 | 8195 | const msg = try sema.errMsg(block, lhs_src, "expected error set type, found 'bool'", .{}); |
| 8136 | 8196 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -8141,32 +8201,32 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 8141 | 8201 | } |
| 8142 | 8202 | const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); |
| 8143 | 8203 | const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); |
| 8144 | if (lhs_ty.zigTypeTag() != .ErrorSet) | |
| 8145 | return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(sema.mod)}); | |
| 8146 | if (rhs_ty.zigTypeTag() != .ErrorSet) | |
| 8147 | return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(sema.mod)}); | |
| 8204 | if (lhs_ty.zigTypeTag(mod) != .ErrorSet) | |
| 8205 | return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(mod)}); | |
| 8206 | if (rhs_ty.zigTypeTag(mod) != .ErrorSet) | |
| 8207 | return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(mod)}); | |
| 8148 | 8208 | |
| 8149 | 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 | 8211 | return Air.Inst.Ref.anyerror_type; |
| 8152 | 8212 | } |
| 8153 | 8213 | |
| 8154 | if (lhs_ty.castTag(.error_set_inferred)) |payload| { | |
| 8155 | try sema.resolveInferredErrorSet(block, src, payload.data); | |
| 8214 | if (mod.typeToInferredErrorSetIndex(lhs_ty).unwrap()) |ies_index| { | |
| 8215 | try sema.resolveInferredErrorSet(block, src, ies_index); | |
| 8156 | 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 | 8218 | return Air.Inst.Ref.anyerror_type; |
| 8159 | 8219 | } |
| 8160 | 8220 | } |
| 8161 | if (rhs_ty.castTag(.error_set_inferred)) |payload| { | |
| 8162 | try sema.resolveInferredErrorSet(block, src, payload.data); | |
| 8221 | if (mod.typeToInferredErrorSetIndex(rhs_ty).unwrap()) |ies_index| { | |
| 8222 | try sema.resolveInferredErrorSet(block, src, ies_index); | |
| 8163 | 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 | 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 | 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 | 8235 | const tracy = trace(@src()); |
| 8176 | 8236 | defer tracy.end(); |
| 8177 | 8237 | |
| 8238 | const mod = sema.mod; | |
| 8178 | 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)); | |
| 8180 | return sema.addConstant( | |
| 8181 | Type.initTag(.enum_literal), | |
| 8182 | try Value.Tag.enum_literal.create(sema.arena, duped_name), | |
| 8183 | ); | |
| 8240 | const name = inst_data.get(sema.code); | |
| 8241 | return sema.addConstant(.{ .ip_index = .enum_literal_type }, (try mod.intern(.{ | |
| 8242 | .enum_literal = try mod.intern_pool.getOrPutString(sema.gpa, name), | |
| 8243 | })).toValue()); | |
| 8184 | 8244 | } |
| 8185 | 8245 | |
| 8186 | 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 | 8248 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 8189 | 8249 | const src = inst_data.src(); |
| 8190 | 8250 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 8191 | 8251 | const operand = try sema.resolveInst(inst_data.operand); |
| 8192 | 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 | 8255 | .Enum => operand, |
| 8196 | 8256 | .Union => blk: { |
| 8197 | 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 | 8259 | return sema.fail( |
| 8200 | 8260 | block, |
| 8201 | 8261 | operand_src, |
| ... | ... | @@ -8207,22 +8267,20 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8207 | 8267 | }, |
| 8208 | 8268 | else => { |
| 8209 | 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 | 8274 | const enum_tag_ty = sema.typeOf(enum_tag); |
| 8215 | 8275 | |
| 8216 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | |
| 8217 | const int_tag_ty = try enum_tag_ty.intTagType(&int_tag_type_buffer).copy(arena); | |
| 8276 | const int_tag_ty = enum_tag_ty.intTagType(mod); | |
| 8218 | 8277 | |
| 8219 | 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 | 8282 | if (try sema.resolveMaybeUndefVal(enum_tag)) |enum_tag_val| { |
| 8224 | var buffer: Value.Payload.U64 = undefined; | |
| 8225 | const val = enum_tag_val.enumToInt(enum_tag_ty, &buffer); | |
| 8283 | const val = try enum_tag_val.enumToInt(enum_tag_ty, mod); | |
| 8226 | 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 | 8289 | } |
| 8232 | 8290 | |
| 8233 | 8291 | fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8292 | const mod = sema.mod; | |
| 8234 | 8293 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 8235 | 8294 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 8236 | 8295 | const src = inst_data.src(); |
| ... | ... | @@ -8239,24 +8298,23 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8239 | 8298 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 8240 | 8299 | const operand = try sema.resolveInst(extra.rhs); |
| 8241 | 8300 | |
| 8242 | if (dest_ty.zigTypeTag() != .Enum) { | |
| 8243 | return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(sema.mod)}); | |
| 8301 | if (dest_ty.zigTypeTag(mod) != .Enum) { | |
| 8302 | return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(mod)}); | |
| 8244 | 8303 | } |
| 8245 | 8304 | _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); |
| 8246 | 8305 | |
| 8247 | 8306 | if (try sema.resolveMaybeUndefVal(operand)) |int_val| { |
| 8248 | if (dest_ty.isNonexhaustiveEnum()) { | |
| 8249 | var buffer: Type.Payload.Bits = undefined; | |
| 8250 | const int_tag_ty = dest_ty.intTagType(&buffer); | |
| 8307 | if (dest_ty.isNonexhaustiveEnum(mod)) { | |
| 8308 | const int_tag_ty = dest_ty.intTagType(mod); | |
| 8251 | 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 | 8312 | const msg = msg: { |
| 8255 | 8313 | const msg = try sema.errMsg( |
| 8256 | 8314 | block, |
| 8257 | 8315 | src, |
| 8258 | 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 | 8319 | errdefer msg.destroy(sema.gpa); |
| 8262 | 8320 | try sema.addDeclaredHereNote(msg, dest_ty); |
| ... | ... | @@ -8264,7 +8322,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8264 | 8322 | }; |
| 8265 | 8323 | return sema.failWithOwnedErrorMsg(msg); |
| 8266 | 8324 | } |
| 8267 | if (int_val.isUndef()) { | |
| 8325 | if (int_val.isUndef(mod)) { | |
| 8268 | 8326 | return sema.failWithUseOfUndef(block, operand_src); |
| 8269 | 8327 | } |
| 8270 | 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 | 8331 | block, |
| 8274 | 8332 | src, |
| 8275 | 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 | 8336 | errdefer msg.destroy(sema.gpa); |
| 8279 | 8337 | try sema.addDeclaredHereNote(msg, dest_ty); |
| ... | ... | @@ -8281,7 +8339,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8281 | 8339 | }; |
| 8282 | 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 | 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 | 8353 | |
| 8296 | 8354 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 8297 | 8355 | const result = try block.addTyOp(.intcast, dest_ty, operand); |
| 8298 | if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and | |
| 8299 | sema.mod.backendSupportsFeature(.is_named_enum_value)) | |
| 8356 | if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum(mod) and | |
| 8357 | mod.backendSupportsFeature(.is_named_enum_value)) | |
| 8300 | 8358 | { |
| 8301 | 8359 | const ok = try block.addUnOp(.is_named_enum_value, result); |
| 8302 | 8360 | try sema.addSafetyCheck(block, ok, .invalid_enum_value); |
| ... | ... | @@ -8329,49 +8387,44 @@ fn analyzeOptionalPayloadPtr( |
| 8329 | 8387 | safety_check: bool, |
| 8330 | 8388 | initializing: bool, |
| 8331 | 8389 | ) CompileError!Air.Inst.Ref { |
| 8390 | const mod = sema.mod; | |
| 8332 | 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(); | |
| 8336 | if (opt_type.zigTypeTag() != .Optional) { | |
| 8337 | return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(sema.mod)}); | |
| 8394 | const opt_type = optional_ptr_ty.childType(mod); | |
| 8395 | if (opt_type.zigTypeTag(mod) != .Optional) { | |
| 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); | |
| 8341 | const child_pointer = try Type.ptr(sema.arena, sema.mod, .{ | |
| 8399 | const child_type = opt_type.optionalChild(mod); | |
| 8400 | const child_pointer = try Type.ptr(sema.arena, mod, .{ | |
| 8342 | 8401 | .pointee_type = child_type, |
| 8343 | .mutable = !optional_ptr_ty.isConstPtr(), | |
| 8344 | .@"addrspace" = optional_ptr_ty.ptrAddressSpace(), | |
| 8402 | .mutable = !optional_ptr_ty.isConstPtr(mod), | |
| 8403 | .@"addrspace" = optional_ptr_ty.ptrAddressSpace(mod), | |
| 8345 | 8404 | }); |
| 8346 | 8405 | |
| 8347 | 8406 | if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| { |
| 8348 | 8407 | if (initializing) { |
| 8349 | if (!ptr_val.isComptimeMutablePtr()) { | |
| 8408 | if (!ptr_val.isComptimeMutablePtr(mod)) { | |
| 8350 | 8409 | // If the pointer resulting from this function was stored at comptime, |
| 8351 | 8410 | // the optional non-null bit would be set that way. But in this case, |
| 8352 | 8411 | // we need to emit a runtime instruction to do it. |
| 8353 | 8412 | _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); |
| 8354 | 8413 | } |
| 8355 | return sema.addConstant( | |
| 8356 | child_pointer, | |
| 8357 | try Value.Tag.opt_payload_ptr.create(sema.arena, .{ | |
| 8358 | .container_ptr = ptr_val, | |
| 8359 | .container_ty = optional_ptr_ty.childType(), | |
| 8360 | }), | |
| 8361 | ); | |
| 8414 | return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{ | |
| 8415 | .ty = child_pointer.toIntern(), | |
| 8416 | .addr = .{ .opt_payload = ptr_val.toIntern() }, | |
| 8417 | } })).toValue()); | |
| 8362 | 8418 | } |
| 8363 | 8419 | if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| { |
| 8364 | if (val.isNull()) { | |
| 8420 | if (val.isNull(mod)) { | |
| 8365 | 8421 | return sema.fail(block, src, "unable to unwrap null", .{}); |
| 8366 | 8422 | } |
| 8367 | 8423 | // The same Value represents the pointer to the optional and the payload. |
| 8368 | return sema.addConstant( | |
| 8369 | child_pointer, | |
| 8370 | try Value.Tag.opt_payload_ptr.create(sema.arena, .{ | |
| 8371 | .container_ptr = ptr_val, | |
| 8372 | .container_ty = optional_ptr_ty.childType(), | |
| 8373 | }), | |
| 8374 | ); | |
| 8424 | return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{ | |
| 8425 | .ty = child_pointer.toIntern(), | |
| 8426 | .addr = .{ .opt_payload = ptr_val.toIntern() }, | |
| 8427 | } })).toValue()); | |
| 8375 | 8428 | } |
| 8376 | 8429 | } |
| 8377 | 8430 | |
| ... | ... | @@ -8397,21 +8450,22 @@ fn zirOptionalPayload( |
| 8397 | 8450 | const tracy = trace(@src()); |
| 8398 | 8451 | defer tracy.end(); |
| 8399 | 8452 | |
| 8453 | const mod = sema.mod; | |
| 8400 | 8454 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 8401 | 8455 | const src = inst_data.src(); |
| 8402 | 8456 | const operand = try sema.resolveInst(inst_data.operand); |
| 8403 | 8457 | const operand_ty = sema.typeOf(operand); |
| 8404 | const result_ty = switch (operand_ty.zigTypeTag()) { | |
| 8405 | .Optional => try operand_ty.optionalChildAlloc(sema.arena), | |
| 8458 | const result_ty = switch (operand_ty.zigTypeTag(mod)) { | |
| 8459 | .Optional => operand_ty.optionalChild(mod), | |
| 8406 | 8460 | .Pointer => t: { |
| 8407 | if (operand_ty.ptrSize() != .C) { | |
| 8461 | if (operand_ty.ptrSize(mod) != .C) { | |
| 8408 | 8462 | return sema.failWithExpectedOptionalType(block, src, operand_ty); |
| 8409 | 8463 | } |
| 8410 | 8464 | // TODO https://github.com/ziglang/zig/issues/6597 |
| 8411 | 8465 | if (true) break :t operand_ty; |
| 8412 | const ptr_info = operand_ty.ptrInfo().data; | |
| 8413 | break :t try Type.ptr(sema.arena, sema.mod, .{ | |
| 8414 | .pointee_type = try ptr_info.pointee_type.copy(sema.arena), | |
| 8466 | const ptr_info = operand_ty.ptrInfo(mod); | |
| 8467 | break :t try Type.ptr(sema.arena, mod, .{ | |
| 8468 | .pointee_type = ptr_info.pointee_type, | |
| 8415 | 8469 | .@"align" = ptr_info.@"align", |
| 8416 | 8470 | .@"addrspace" = ptr_info.@"addrspace", |
| 8417 | 8471 | .mutable = ptr_info.mutable, |
| ... | ... | @@ -8424,13 +8478,10 @@ fn zirOptionalPayload( |
| 8424 | 8478 | }; |
| 8425 | 8479 | |
| 8426 | 8480 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 8427 | if (val.isNull()) { | |
| 8428 | return sema.fail(block, src, "unable to unwrap null", .{}); | |
| 8429 | } | |
| 8430 | if (val.castTag(.opt_payload)) |payload| { | |
| 8431 | return sema.addConstant(result_ty, payload.data); | |
| 8432 | } | |
| 8433 | return sema.addConstant(result_ty, val); | |
| 8481 | return if (val.optionalValue(mod)) |payload| | |
| 8482 | sema.addConstant(result_ty, payload) | |
| 8483 | else | |
| 8484 | sema.fail(block, src, "unable to unwrap null", .{}); | |
| 8434 | 8485 | } |
| 8435 | 8486 | |
| 8436 | 8487 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -8450,14 +8501,15 @@ fn zirErrUnionPayload( |
| 8450 | 8501 | const tracy = trace(@src()); |
| 8451 | 8502 | defer tracy.end(); |
| 8452 | 8503 | |
| 8504 | const mod = sema.mod; | |
| 8453 | 8505 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 8454 | 8506 | const src = inst_data.src(); |
| 8455 | 8507 | const operand = try sema.resolveInst(inst_data.operand); |
| 8456 | 8508 | const operand_src = src; |
| 8457 | 8509 | const err_union_ty = sema.typeOf(operand); |
| 8458 | if (err_union_ty.zigTypeTag() != .ErrorUnion) { | |
| 8510 | if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { | |
| 8459 | 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 | 8515 | return sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false); |
| ... | ... | @@ -8468,24 +8520,27 @@ fn analyzeErrUnionPayload( |
| 8468 | 8520 | block: *Block, |
| 8469 | 8521 | src: LazySrcLoc, |
| 8470 | 8522 | err_union_ty: Type, |
| 8471 | operand: Zir.Inst.Ref, | |
| 8523 | operand: Air.Inst.Ref, | |
| 8472 | 8524 | operand_src: LazySrcLoc, |
| 8473 | 8525 | safety_check: bool, |
| 8474 | 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 | 8529 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { |
| 8477 | if (val.getError()) |name| { | |
| 8478 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); | |
| 8530 | if (val.getErrorName(mod).unwrap()) |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; | |
| 8481 | return sema.addConstant(payload_ty, data); | |
| 8533 | return sema.addConstant( | |
| 8534 | payload_ty, | |
| 8535 | mod.intern_pool.indexToKey(val.toIntern()).error_union.val.payload.toValue(), | |
| 8536 | ); | |
| 8482 | 8537 | } |
| 8483 | 8538 | |
| 8484 | 8539 | try sema.requireRuntimeBlock(block, src, null); |
| 8485 | 8540 | |
| 8486 | 8541 | // If the error set has no fields then no safety check is needed. |
| 8487 | 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 | 8545 | try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err); |
| 8491 | 8546 | } |
| ... | ... | @@ -8517,52 +8572,46 @@ fn analyzeErrUnionPayloadPtr( |
| 8517 | 8572 | safety_check: bool, |
| 8518 | 8573 | initializing: bool, |
| 8519 | 8574 | ) CompileError!Air.Inst.Ref { |
| 8575 | const mod = sema.mod; | |
| 8520 | 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 | 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(); | |
| 8530 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 8531 | const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 8585 | const err_union_ty = operand_ty.childType(mod); | |
| 8586 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 8587 | const operand_pointer_ty = try Type.ptr(sema.arena, mod, .{ | |
| 8532 | 8588 | .pointee_type = payload_ty, |
| 8533 | .mutable = !operand_ty.isConstPtr(), | |
| 8534 | .@"addrspace" = operand_ty.ptrAddressSpace(), | |
| 8589 | .mutable = !operand_ty.isConstPtr(mod), | |
| 8590 | .@"addrspace" = operand_ty.ptrAddressSpace(mod), | |
| 8535 | 8591 | }); |
| 8536 | 8592 | |
| 8537 | 8593 | if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| { |
| 8538 | 8594 | if (initializing) { |
| 8539 | if (!ptr_val.isComptimeMutablePtr()) { | |
| 8595 | if (!ptr_val.isComptimeMutablePtr(mod)) { | |
| 8540 | 8596 | // If the pointer resulting from this function was stored at comptime, |
| 8541 | 8597 | // the error union error code would be set that way. But in this case, |
| 8542 | 8598 | // we need to emit a runtime instruction to do it. |
| 8543 | 8599 | try sema.requireRuntimeBlock(block, src, null); |
| 8544 | 8600 | _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); |
| 8545 | 8601 | } |
| 8546 | return sema.addConstant( | |
| 8547 | operand_pointer_ty, | |
| 8548 | try Value.Tag.eu_payload_ptr.create(sema.arena, .{ | |
| 8549 | .container_ptr = ptr_val, | |
| 8550 | .container_ty = operand_ty.elemType(), | |
| 8551 | }), | |
| 8552 | ); | |
| 8602 | return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{ | |
| 8603 | .ty = operand_pointer_ty.toIntern(), | |
| 8604 | .addr = .{ .eu_payload = ptr_val.toIntern() }, | |
| 8605 | } })).toValue()); | |
| 8553 | 8606 | } |
| 8554 | 8607 | if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| { |
| 8555 | if (val.getError()) |name| { | |
| 8556 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); | |
| 8608 | if (val.getErrorName(mod).unwrap()) |name| { | |
| 8609 | return sema.fail(block, src, "caught unexpected error '{}'", .{name.fmt(&mod.intern_pool)}); | |
| 8557 | 8610 | } |
| 8558 | ||
| 8559 | return sema.addConstant( | |
| 8560 | operand_pointer_ty, | |
| 8561 | try Value.Tag.eu_payload_ptr.create(sema.arena, .{ | |
| 8562 | .container_ptr = ptr_val, | |
| 8563 | .container_ty = operand_ty.elemType(), | |
| 8564 | }), | |
| 8565 | ); | |
| 8611 | return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{ | |
| 8612 | .ty = operand_pointer_ty.toIntern(), | |
| 8613 | .addr = .{ .eu_payload = ptr_val.toIntern() }, | |
| 8614 | } })).toValue()); | |
| 8566 | 8615 | } |
| 8567 | 8616 | } |
| 8568 | 8617 | |
| ... | ... | @@ -8570,7 +8619,7 @@ fn analyzeErrUnionPayloadPtr( |
| 8570 | 8619 | |
| 8571 | 8620 | // If the error set has no fields then no safety check is needed. |
| 8572 | 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 | 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 | 8643 | } |
| 8595 | 8644 | |
| 8596 | 8645 | fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref { |
| 8646 | const mod = sema.mod; | |
| 8597 | 8647 | const operand_ty = sema.typeOf(operand); |
| 8598 | if (operand_ty.zigTypeTag() != .ErrorUnion) { | |
| 8648 | if (operand_ty.zigTypeTag(mod) != .ErrorUnion) { | |
| 8599 | 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 | 8656 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 8607 | assert(val.getError() != null); | |
| 8608 | return sema.addConstant(result_ty, val); | |
| 8657 | return sema.addConstant(result_ty, (try mod.intern(.{ .err = .{ | |
| 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 | 8663 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -8617,23 +8669,24 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 8617 | 8669 | const tracy = trace(@src()); |
| 8618 | 8670 | defer tracy.end(); |
| 8619 | 8671 | |
| 8672 | const mod = sema.mod; | |
| 8620 | 8673 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 8621 | 8674 | const src = inst_data.src(); |
| 8622 | 8675 | const operand = try sema.resolveInst(inst_data.operand); |
| 8623 | 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 | 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 | 8687 | if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { |
| 8635 | 8688 | if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { |
| 8636 | assert(val.getError() != null); | |
| 8689 | assert(val.getErrorName(mod) != .none); | |
| 8637 | 8690 | return sema.addConstant(result_ty, val); |
| 8638 | 8691 | } |
| 8639 | 8692 | } |
| ... | ... | @@ -8667,7 +8720,7 @@ fn zirFunc( |
| 8667 | 8720 | break :blk ret_ty; |
| 8668 | 8721 | } else |err| switch (err) { |
| 8669 | 8722 | error.GenericPoison => { |
| 8670 | break :blk Type.initTag(.generic_poison); | |
| 8723 | break :blk Type.generic_poison; | |
| 8671 | 8724 | }, |
| 8672 | 8725 | else => |e| return e, |
| 8673 | 8726 | } |
| ... | ... | @@ -8677,8 +8730,7 @@ fn zirFunc( |
| 8677 | 8730 | extra_index += ret_ty_body.len; |
| 8678 | 8731 | |
| 8679 | 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; | |
| 8681 | break :blk try ret_ty_val.toType(&buffer).copy(sema.arena); | |
| 8733 | break :blk ret_ty_val.toType(); | |
| 8682 | 8734 | }, |
| 8683 | 8735 | }; |
| 8684 | 8736 | |
| ... | ... | @@ -8745,10 +8797,10 @@ fn resolveGenericBody( |
| 8745 | 8797 | }; |
| 8746 | 8798 | switch (err) { |
| 8747 | 8799 | error.GenericPoison => { |
| 8748 | if (dest_ty.tag() == .type) { | |
| 8749 | return Value.initTag(.generic_poison_type); | |
| 8800 | if (dest_ty.toIntern() == .type_type) { | |
| 8801 | return Value.generic_poison_type; | |
| 8750 | 8802 | } else { |
| 8751 | return Value.initTag(.generic_poison); | |
| 8803 | return Value.generic_poison; | |
| 8752 | 8804 | } |
| 8753 | 8805 | }, |
| 8754 | 8806 | else => |e| return e, |
| ... | ... | @@ -8822,7 +8874,7 @@ fn handleExternLibName( |
| 8822 | 8874 | const FuncLinkSection = union(enum) { |
| 8823 | 8875 | generic, |
| 8824 | 8876 | default, |
| 8825 | explicit: []const u8, | |
| 8877 | explicit: InternPool.NullTerminatedString, | |
| 8826 | 8878 | }; |
| 8827 | 8879 | |
| 8828 | 8880 | fn funcCommon( |
| ... | ... | @@ -8849,11 +8901,13 @@ fn funcCommon( |
| 8849 | 8901 | noalias_bits: u32, |
| 8850 | 8902 | is_noinline: bool, |
| 8851 | 8903 | ) CompileError!Air.Inst.Ref { |
| 8904 | const mod = sema.mod; | |
| 8905 | const gpa = sema.gpa; | |
| 8852 | 8906 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; |
| 8853 | 8907 | const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; |
| 8854 | 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 | 8911 | alignment == null or |
| 8858 | 8912 | address_space == null or |
| 8859 | 8913 | section == .generic or |
| ... | ... | @@ -8869,70 +8923,42 @@ fn funcCommon( |
| 8869 | 8923 | } |
| 8870 | 8924 | |
| 8871 | 8925 | var destroy_fn_on_error = false; |
| 8872 | const new_func: *Module.Fn = new_func: { | |
| 8926 | const new_func_index = new_func: { | |
| 8873 | 8927 | if (!has_body) break :new_func undefined; |
| 8874 | 8928 | if (sema.comptime_args_fn_inst == func_inst) { |
| 8875 | const new_func = sema.preallocated_new_func.?; | |
| 8876 | sema.preallocated_new_func = null; // take ownership | |
| 8877 | break :new_func new_func; | |
| 8929 | const new_func_index = sema.preallocated_new_func.unwrap().?; | |
| 8930 | sema.preallocated_new_func = .none; // take ownership | |
| 8931 | break :new_func new_func_index; | |
| 8878 | 8932 | } |
| 8879 | 8933 | destroy_fn_on_error = true; |
| 8880 | const new_func = try sema.gpa.create(Module.Fn); | |
| 8934 | var new_func: Module.Fn = undefined; | |
| 8881 | 8935 | // Set this here so that the inferred return type can be printed correctly if it appears in an error. |
| 8882 | 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); | |
| 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. | |
| 8940 | errdefer if (destroy_fn_on_error) mod.destroyFunc(new_func_index); | |
| 8890 | 8941 | |
| 8891 | const target = sema.mod.getTarget(); | |
| 8942 | const target = mod.getTarget(); | |
| 8892 | 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 | 8944 | // In the case of generic calling convention, or generic alignment, we use |
| 8919 | 8945 | // default values which are only meaningful for the generic function, *not* |
| 8920 | 8946 | // the instantiation, which can depend on comptime parameters. |
| 8921 | 8947 | // Related proposal: https://github.com/ziglang/zig/issues/11834 |
| 8922 | 8948 | const cc_resolved = cc orelse .Unspecified; |
| 8923 | const param_types = try sema.arena.alloc(Type, block.params.items.len); | |
| 8924 | const comptime_params = try sema.arena.alloc(bool, block.params.items.len); | |
| 8925 | for (block.params.items, 0..) |param, i| { | |
| 8949 | const param_types = try sema.arena.alloc(InternPool.Index, block.params.items.len); | |
| 8950 | var comptime_bits: u32 = 0; | |
| 8951 | for (param_types, block.params.items, 0..) |*dest_param_ty, param, i| { | |
| 8926 | 8952 | const is_noalias = blk: { |
| 8927 | 8953 | const index = std.math.cast(u5, i) orelse break :blk false; |
| 8928 | 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 | 8957 | sema.analyzeParameter( |
| 8932 | 8958 | block, |
| 8933 | 8959 | .unneeded, |
| 8934 | 8960 | param, |
| 8935 | comptime_params, | |
| 8961 | &comptime_bits, | |
| 8936 | 8962 | i, |
| 8937 | 8963 | &is_generic, |
| 8938 | 8964 | cc_resolved, |
| ... | ... | @@ -8940,12 +8966,12 @@ fn funcCommon( |
| 8940 | 8966 | is_noalias, |
| 8941 | 8967 | ) catch |err| switch (err) { |
| 8942 | 8968 | error.NeededSourceLocation => { |
| 8943 | const decl = sema.mod.declPtr(block.src_decl); | |
| 8969 | const decl = mod.declPtr(block.src_decl); | |
| 8944 | 8970 | try sema.analyzeParameter( |
| 8945 | 8971 | block, |
| 8946 | Module.paramSrc(src_node_offset, sema.gpa, decl, i), | |
| 8972 | Module.paramSrc(src_node_offset, mod, decl, i), | |
| 8947 | 8973 | param, |
| 8948 | comptime_params, | |
| 8974 | &comptime_bits, | |
| 8949 | 8975 | i, |
| 8950 | 8976 | &is_generic, |
| 8951 | 8977 | cc_resolved, |
| ... | ... | @@ -8961,7 +8987,7 @@ fn funcCommon( |
| 8961 | 8987 | var ret_ty_requires_comptime = false; |
| 8962 | 8988 | const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: { |
| 8963 | 8989 | ret_ty_requires_comptime = ret_comptime; |
| 8964 | break :rp bare_return_type.tag() == .generic_poison; | |
| 8990 | break :rp bare_return_type.isGenericPoison(); | |
| 8965 | 8991 | } else |err| switch (err) { |
| 8966 | 8992 | error.GenericPoison => rp: { |
| 8967 | 8993 | is_generic = true; |
| ... | ... | @@ -8970,43 +8996,41 @@ fn funcCommon( |
| 8970 | 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 | 9000 | bare_return_type |
| 8975 | 9001 | else blk: { |
| 8976 | 9002 | try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); |
| 8977 | const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); | |
| 8978 | node.data = .{ .func = new_func }; | |
| 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, | |
| 9003 | const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ | |
| 9004 | .func = new_func_index, | |
| 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()) { | |
| 8989 | const opaque_str = if (return_type.zigTypeTag() == .Opaque) "opaque " else ""; | |
| 9010 | if (!return_type.isValidReturnType(mod)) { | |
| 9011 | const opaque_str = if (return_type.zigTypeTag(mod) == .Opaque) "opaque " else ""; | |
| 8990 | 9012 | const msg = msg: { |
| 8991 | 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 | 9018 | try sema.addDeclaredHereNote(msg, return_type); |
| 8997 | 9019 | break :msg msg; |
| 8998 | 9020 | }; |
| 8999 | 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 | 9026 | const msg = msg: { |
| 9003 | 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); | |
| 9009 | try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl), return_type, .ret_ty); | |
| 9032 | const src_decl = mod.declPtr(block.src_decl); | |
| 9033 | try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty); | |
| 9010 | 9034 | |
| 9011 | 9035 | try sema.addDeclaredHereNote(msg, return_type); |
| 9012 | 9036 | break :msg msg; |
| ... | ... | @@ -9024,9 +9048,9 @@ fn funcCommon( |
| 9024 | 9048 | block, |
| 9025 | 9049 | ret_ty_src, |
| 9026 | 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 | 9055 | const tags = sema.code.instructions.items(.tag); |
| 9032 | 9056 | const data = sema.code.instructions.items(.data); |
| ... | ... | @@ -9049,7 +9073,7 @@ fn funcCommon( |
| 9049 | 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 | 9077 | if (switch (cc_resolved) { |
| 9054 | 9078 | .Unspecified, .C, .Naked, .Async, .Inline => null, |
| 9055 | 9079 | .Interrupt => switch (arch) { |
| ... | ... | @@ -9092,8 +9116,7 @@ fn funcCommon( |
| 9092 | 9116 | return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); |
| 9093 | 9117 | } |
| 9094 | 9118 | if (is_generic and sema.no_partial_func_ty) return error.GenericPoison; |
| 9095 | for (comptime_params) |ct| is_generic = is_generic or ct; | |
| 9096 | is_generic = is_generic or ret_ty_requires_comptime; | |
| 9119 | is_generic = is_generic or comptime_bits != 0 or ret_ty_requires_comptime; | |
| 9097 | 9120 | |
| 9098 | 9121 | if (!is_generic and sema.wantErrorReturnTracing(return_type)) { |
| 9099 | 9122 | // Make sure that StackTrace's fields are resolved so that the backend can |
| ... | ... | @@ -9102,68 +9125,58 @@ fn funcCommon( |
| 9102 | 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 | 9129 | .param_types = param_types, |
| 9107 | .comptime_params = comptime_params.ptr, | |
| 9108 | .return_type = return_type, | |
| 9130 | .noalias_bits = noalias_bits, | |
| 9131 | .comptime_bits = comptime_bits, | |
| 9132 | .return_type = return_type.toIntern(), | |
| 9109 | 9133 | .cc = cc_resolved, |
| 9110 | 9134 | .cc_is_generic = cc == null, |
| 9111 | .alignment = alignment orelse 0, | |
| 9135 | .alignment = if (alignment) |a| InternPool.Alignment.fromByteUnits(a) else .none, | |
| 9112 | 9136 | .align_is_generic = alignment == null, |
| 9113 | 9137 | .section_is_generic = section == .generic, |
| 9114 | 9138 | .addrspace_is_generic = address_space == null, |
| 9115 | 9139 | .is_var_args = var_args, |
| 9116 | 9140 | .is_generic = is_generic, |
| 9117 | 9141 | .is_noinline = is_noinline, |
| 9118 | .noalias_bits = noalias_bits, | |
| 9119 | 9142 | }); |
| 9120 | 9143 | }; |
| 9121 | 9144 | |
| 9122 | 9145 | sema.owner_decl.@"linksection" = switch (section) { |
| 9123 | .generic => undefined, | |
| 9124 | .default => null, | |
| 9125 | .explicit => |section_name| try sema.perm_arena.dupeZ(u8, section_name), | |
| 9146 | .generic => .none, | |
| 9147 | .default => .none, | |
| 9148 | .explicit => |section_name| section_name.toOptional(), | |
| 9126 | 9149 | }; |
| 9127 | 9150 | sema.owner_decl.@"align" = alignment orelse 0; |
| 9128 | 9151 | sema.owner_decl.@"addrspace" = address_space orelse .generic; |
| 9129 | 9152 | |
| 9130 | 9153 | if (is_extern) { |
| 9131 | const new_extern_fn = try sema.gpa.create(Module.ExternFn); | |
| 9132 | errdefer sema.gpa.destroy(new_extern_fn); | |
| 9133 | ||
| 9134 | new_extern_fn.* = Module.ExternFn{ | |
| 9135 | .owner_decl = sema.owner_decl_index, | |
| 9136 | .lib_name = null, | |
| 9137 | }; | |
| 9138 | ||
| 9139 | if (opt_lib_name) |lib_name| { | |
| 9140 | new_extern_fn.lib_name = try sema.handleExternLibName(block, .{ | |
| 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)); | |
| 9154 | return sema.addConstant(fn_ty, (try mod.intern(.{ .extern_func = .{ | |
| 9155 | .ty = fn_ty.toIntern(), | |
| 9156 | .decl = sema.owner_decl_index, | |
| 9157 | .lib_name = if (opt_lib_name) |lib_name| (try mod.intern_pool.getOrPutString( | |
| 9158 | gpa, | |
| 9159 | try sema.handleExternLibName(block, .{ | |
| 9160 | .node_offset_lib_name = src_node_offset, | |
| 9161 | }, lib_name), | |
| 9162 | )).toOptional() else .none, | |
| 9163 | } })).toValue()); | |
| 9151 | 9164 | } |
| 9152 | 9165 | |
| 9153 | 9166 | if (!has_body) { |
| 9154 | 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 | 9171 | const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none; |
| 9159 | 9172 | |
| 9160 | 9173 | const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: { |
| 9161 | 9174 | break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr; |
| 9162 | 9175 | } else null; |
| 9163 | 9176 | |
| 9177 | const new_func = mod.funcPtr(new_func_index); | |
| 9164 | 9178 | const hash = new_func.hash; |
| 9165 | 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 | 9180 | new_func.* = .{ |
| 9168 | 9181 | .state = anal_state, |
| 9169 | 9182 | .zir_body_inst = func_inst, |
| ... | ... | @@ -9178,15 +9191,10 @@ fn funcCommon( |
| 9178 | 9191 | .branch_quota = default_branch_quota, |
| 9179 | 9192 | .is_noinline = is_noinline, |
| 9180 | 9193 | }; |
| 9181 | if (maybe_inferred_error_set_node) |node| { | |
| 9182 | new_func.inferred_error_sets.prepend(node); | |
| 9183 | } | |
| 9184 | maybe_inferred_error_set_node = null; | |
| 9185 | fn_payload.* = .{ | |
| 9186 | .base = .{ .tag = .function }, | |
| 9187 | .data = new_func, | |
| 9188 | }; | |
| 9189 | return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base)); | |
| 9194 | return sema.addConstant(fn_ty, (try mod.intern(.{ .func = .{ | |
| 9195 | .ty = fn_ty.toIntern(), | |
| 9196 | .index = new_func_index, | |
| 9197 | } })).toValue()); | |
| 9190 | 9198 | } |
| 9191 | 9199 | |
| 9192 | 9200 | fn analyzeParameter( |
| ... | ... | @@ -9194,29 +9202,32 @@ fn analyzeParameter( |
| 9194 | 9202 | block: *Block, |
| 9195 | 9203 | param_src: LazySrcLoc, |
| 9196 | 9204 | param: Block.Param, |
| 9197 | comptime_params: []bool, | |
| 9205 | comptime_bits: *u32, | |
| 9198 | 9206 | i: usize, |
| 9199 | 9207 | is_generic: *bool, |
| 9200 | 9208 | cc: std.builtin.CallingConvention, |
| 9201 | 9209 | has_body: bool, |
| 9202 | 9210 | is_noalias: bool, |
| 9203 | 9211 | ) !void { |
| 9212 | const mod = sema.mod; | |
| 9204 | 9213 | const requires_comptime = try sema.typeRequiresComptime(param.ty); |
| 9205 | comptime_params[i] = param.is_comptime or requires_comptime; | |
| 9206 | const this_generic = param.ty.tag() == .generic_poison; | |
| 9214 | if (param.is_comptime or requires_comptime) { | |
| 9215 | comptime_bits.* |= @as(u32, 1) << @intCast(u5, i); // TODO: handle cast error | |
| 9216 | } | |
| 9217 | const this_generic = param.ty.isGenericPoison(); | |
| 9207 | 9218 | is_generic.* = is_generic.* or this_generic; |
| 9208 | const target = sema.mod.getTarget(); | |
| 9209 | if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(target, cc)) { | |
| 9219 | const target = mod.getTarget(); | |
| 9220 | if (param.is_comptime and !target_util.fnCallConvAllowsZigTypes(target, cc)) { | |
| 9210 | 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 | 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()) { | |
| 9216 | const opaque_str = if (param.ty.zigTypeTag() == .Opaque) "opaque " else ""; | |
| 9226 | if (!param.ty.isValidParamType(mod)) { | |
| 9227 | const opaque_str = if (param.ty.zigTypeTag(mod) == .Opaque) "opaque " else ""; | |
| 9217 | 9228 | const msg = msg: { |
| 9218 | 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 | 9232 | errdefer msg.destroy(sema.gpa); |
| 9222 | 9233 | |
| ... | ... | @@ -9225,15 +9236,15 @@ fn analyzeParameter( |
| 9225 | 9236 | }; |
| 9226 | 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 | 9240 | const msg = msg: { |
| 9230 | 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 | 9244 | errdefer msg.destroy(sema.gpa); |
| 9234 | 9245 | |
| 9235 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 9236 | try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl), param.ty, .param_ty); | |
| 9246 | const src_decl = mod.declPtr(block.src_decl); | |
| 9247 | try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl, mod), param.ty, .param_ty); | |
| 9237 | 9248 | |
| 9238 | 9249 | try sema.addDeclaredHereNote(msg, param.ty); |
| 9239 | 9250 | break :msg msg; |
| ... | ... | @@ -9243,12 +9254,12 @@ fn analyzeParameter( |
| 9243 | 9254 | if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) { |
| 9244 | 9255 | const msg = msg: { |
| 9245 | 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 | 9259 | errdefer msg.destroy(sema.gpa); |
| 9249 | 9260 | |
| 9250 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 9251 | try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl), param.ty); | |
| 9261 | const src_decl = mod.declPtr(block.src_decl); | |
| 9262 | try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl, mod), param.ty); | |
| 9252 | 9263 | |
| 9253 | 9264 | try sema.addDeclaredHereNote(msg, param.ty); |
| 9254 | 9265 | break :msg msg; |
| ... | ... | @@ -9256,7 +9267,7 @@ fn analyzeParameter( |
| 9256 | 9267 | return sema.failWithOwnedErrorMsg(msg); |
| 9257 | 9268 | } |
| 9258 | 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 | 9272 | return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{}); |
| 9262 | 9273 | } |
| ... | ... | @@ -9283,7 +9294,7 @@ fn zirParam( |
| 9283 | 9294 | const prev_preallocated_new_func = sema.preallocated_new_func; |
| 9284 | 9295 | const prev_no_partial_func_type = sema.no_partial_func_ty; |
| 9285 | 9296 | block.params = .{}; |
| 9286 | sema.preallocated_new_func = null; | |
| 9297 | sema.preallocated_new_func = .none; | |
| 9287 | 9298 | sema.no_partial_func_ty = true; |
| 9288 | 9299 | defer { |
| 9289 | 9300 | block.params.deinit(sema.gpa); |
| ... | ... | @@ -9309,7 +9320,7 @@ fn zirParam( |
| 9309 | 9320 | // We result the param instruction with a poison value and |
| 9310 | 9321 | // insert an anytype parameter. |
| 9311 | 9322 | try block.params.append(sema.gpa, .{ |
| 9312 | .ty = Type.initTag(.generic_poison), | |
| 9323 | .ty = Type.generic_poison, | |
| 9313 | 9324 | .is_comptime = comptime_syntax, |
| 9314 | 9325 | .name = param_name, |
| 9315 | 9326 | }); |
| ... | ... | @@ -9330,7 +9341,7 @@ fn zirParam( |
| 9330 | 9341 | // We result the param instruction with a poison value and |
| 9331 | 9342 | // insert an anytype parameter. |
| 9332 | 9343 | try block.params.append(sema.gpa, .{ |
| 9333 | .ty = Type.initTag(.generic_poison), | |
| 9344 | .ty = Type.generic_poison, | |
| 9334 | 9345 | .is_comptime = comptime_syntax, |
| 9335 | 9346 | .name = param_name, |
| 9336 | 9347 | }); |
| ... | ... | @@ -9340,7 +9351,7 @@ fn zirParam( |
| 9340 | 9351 | else => |e| return e, |
| 9341 | 9352 | } or comptime_syntax; |
| 9342 | 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 | 9355 | // We have a comptime value for this parameter so it should be elided from the |
| 9345 | 9356 | // function type of the function instruction in this block. |
| 9346 | 9357 | const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) { |
| ... | ... | @@ -9363,7 +9374,7 @@ fn zirParam( |
| 9363 | 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 | 9378 | if (try sema.typeHasOnePossibleValue(param_ty)) |opv| { |
| 9368 | 9379 | // In this case we are instantiating a generic function call with a non-comptime |
| 9369 | 9380 | // non-anytype parameter that ended up being a one-possible-type. |
| ... | ... | @@ -9383,7 +9394,7 @@ fn zirParam( |
| 9383 | 9394 | if (is_comptime) { |
| 9384 | 9395 | // If this is a comptime parameter we can add a constant generic_poison |
| 9385 | 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 | 9398 | sema.inst_map.putAssumeCapacityNoClobber(inst, result); |
| 9388 | 9399 | } else { |
| 9389 | 9400 | // Otherwise we need a dummy runtime instruction. |
| ... | ... | @@ -9428,7 +9439,7 @@ fn zirParamAnytype( |
| 9428 | 9439 | // We are evaluating a generic function without any comptime args provided. |
| 9429 | 9440 | |
| 9430 | 9441 | try block.params.append(sema.gpa, .{ |
| 9431 | .ty = Type.initTag(.generic_poison), | |
| 9442 | .ty = Type.generic_poison, | |
| 9432 | 9443 | .is_comptime = comptime_syntax, |
| 9433 | 9444 | .name = param_name, |
| 9434 | 9445 | }); |
| ... | ... | @@ -9472,13 +9483,14 @@ fn analyzeAs( |
| 9472 | 9483 | zir_operand: Zir.Inst.Ref, |
| 9473 | 9484 | no_cast_to_comptime_int: bool, |
| 9474 | 9485 | ) CompileError!Air.Inst.Ref { |
| 9486 | const mod = sema.mod; | |
| 9475 | 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 | 9489 | const dest_ty = sema.resolveType(block, src, zir_dest_type) catch |err| switch (err) { |
| 9478 | 9490 | error.GenericPoison => return operand, |
| 9479 | 9491 | else => |e| return e, |
| 9480 | 9492 | }; |
| 9481 | if (dest_ty.zigTypeTag() == .NoReturn) { | |
| 9493 | if (dest_ty.zigTypeTag(mod) == .NoReturn) { | |
| 9482 | 9494 | return sema.fail(block, src, "cannot cast to noreturn", .{}); |
| 9483 | 9495 | } |
| 9484 | 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 | 9507 | const tracy = trace(@src()); |
| 9496 | 9508 | defer tracy.end(); |
| 9497 | 9509 | |
| 9510 | const mod = sema.mod; | |
| 9498 | 9511 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 9499 | 9512 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9500 | 9513 | const ptr = try sema.resolveInst(inst_data.operand); |
| 9501 | 9514 | const ptr_ty = sema.typeOf(ptr); |
| 9502 | if (!ptr_ty.isPtrAtRuntime()) { | |
| 9503 | return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}); | |
| 9515 | if (!ptr_ty.isPtrAtRuntime(mod)) { | |
| 9516 | return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(mod)}); | |
| 9504 | 9517 | } |
| 9505 | 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 | 9524 | try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); |
| 9509 | 9525 | return block.addUnOp(.ptrtoint, ptr); |
| ... | ... | @@ -9513,11 +9529,12 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 9513 | 9529 | const tracy = trace(@src()); |
| 9514 | 9530 | defer tracy.end(); |
| 9515 | 9531 | |
| 9532 | const mod = sema.mod; | |
| 9516 | 9533 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9517 | 9534 | const src = inst_data.src(); |
| 9518 | 9535 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 9519 | 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 | 9538 | const object = try sema.resolveInst(extra.lhs); |
| 9522 | 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 | 9543 | const tracy = trace(@src()); |
| 9527 | 9544 | defer tracy.end(); |
| 9528 | 9545 | |
| 9546 | const mod = sema.mod; | |
| 9529 | 9547 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9530 | 9548 | const src = inst_data.src(); |
| 9531 | 9549 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 9532 | 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 | 9552 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 9535 | 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 | 9562 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 9545 | 9563 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 9546 | 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 | 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 | 9575 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 9558 | 9576 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 9559 | 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 | 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 | 9604 | operand_src: LazySrcLoc, |
| 9587 | 9605 | runtime_safety: bool, |
| 9588 | 9606 | ) CompileError!Air.Inst.Ref { |
| 9607 | const mod = sema.mod; | |
| 9589 | 9608 | const operand_ty = sema.typeOf(operand); |
| 9590 | 9609 | const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src); |
| 9591 | 9610 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 9592 | 9611 | |
| 9593 | 9612 | if (try sema.isComptimeKnown(operand)) { |
| 9594 | 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 | 9615 | return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{}); |
| 9597 | 9616 | } |
| 9598 | 9617 | |
| 9599 | 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 | 9621 | if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| { |
| 9603 | 9622 | // requirement: intCast(u0, input) iff input == 0 |
| 9604 | 9623 | if (runtime_safety and block.wantSafety()) { |
| 9605 | 9624 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 9606 | const target = sema.mod.getTarget(); | |
| 9607 | const wanted_info = dest_scalar_ty.intInfo(target); | |
| 9625 | const wanted_info = dest_scalar_ty.intInfo(mod); | |
| 9608 | 9626 | const wanted_bits = wanted_info.bits; |
| 9609 | 9627 | |
| 9610 | 9628 | if (wanted_bits == 0) { |
| 9611 | 9629 | const ok = if (is_vector) ok: { |
| 9612 | const zeros = try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 9613 | const zero_inst = try sema.addConstant(sema.typeOf(operand), zeros); | |
| 9630 | const zeros = try sema.splat(operand_ty, try mod.intValue(operand_scalar_ty, 0)); | |
| 9631 | const zero_inst = try sema.addConstant(operand_ty, zeros); | |
| 9614 | 9632 | const is_in_range = try block.addCmpVector(operand, zero_inst, .eq); |
| 9615 | 9633 | const all_in_range = try block.addInst(.{ |
| 9616 | 9634 | .tag = .reduce, |
| ... | ... | @@ -9618,7 +9636,7 @@ fn intCast( |
| 9618 | 9636 | }); |
| 9619 | 9637 | break :ok all_in_range; |
| 9620 | 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 | 9640 | const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst); |
| 9623 | 9641 | break :ok is_in_range; |
| 9624 | 9642 | }; |
| ... | ... | @@ -9631,9 +9649,8 @@ fn intCast( |
| 9631 | 9649 | |
| 9632 | 9650 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 9633 | 9651 | if (runtime_safety and block.wantSafety()) { |
| 9634 | const target = sema.mod.getTarget(); | |
| 9635 | const actual_info = operand_scalar_ty.intInfo(target); | |
| 9636 | const wanted_info = dest_scalar_ty.intInfo(target); | |
| 9652 | const actual_info = operand_scalar_ty.intInfo(mod); | |
| 9653 | const wanted_info = dest_scalar_ty.intInfo(mod); | |
| 9637 | 9654 | const actual_bits = actual_info.bits; |
| 9638 | 9655 | const wanted_bits = wanted_info.bits; |
| 9639 | 9656 | const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); |
| ... | ... | @@ -9642,26 +9659,24 @@ fn intCast( |
| 9642 | 9659 | // range shrinkage |
| 9643 | 9660 | // requirement: int value fits into target type |
| 9644 | 9661 | if (wanted_value_bits < actual_value_bits) { |
| 9645 | const dest_max_val_scalar = try dest_scalar_ty.maxInt(sema.arena, target); | |
| 9646 | const dest_max_val = if (is_vector) | |
| 9647 | try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar) | |
| 9648 | else | |
| 9649 | dest_max_val_scalar; | |
| 9662 | const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty); | |
| 9663 | const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar); | |
| 9650 | 9664 | const dest_max = try sema.addConstant(operand_ty, dest_max_val); |
| 9651 | 9665 | const diff = try block.addBinOp(.subwrap, dest_max, operand); |
| 9652 | 9666 | |
| 9653 | 9667 | if (actual_info.signedness == .signed) { |
| 9654 | 9668 | // Reinterpret the sign-bit as part of the value. This will make |
| 9655 | 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 | 9671 | const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff); |
| 9658 | 9672 | |
| 9659 | 9673 | // If the destination type is signed, then we need to double its |
| 9660 | 9674 | // range to account for negative values. |
| 9661 | 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); | |
| 9663 | break :range_val try sema.intAdd(range_minus_one, Value.one, unsigned_operand_ty); | |
| 9664 | } else dest_max_val; | |
| 9676 | const one = try mod.intValue(unsigned_operand_ty, 1); | |
| 9677 | const range_minus_one = try dest_max_val.shl(one, unsigned_operand_ty, sema.arena, mod); | |
| 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 | 9680 | const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val); |
| 9666 | 9681 | |
| 9667 | 9682 | const ok = if (is_vector) ok: { |
| ... | ... | @@ -9701,7 +9716,8 @@ fn intCast( |
| 9701 | 9716 | // no shrinkage, yes sign loss |
| 9702 | 9717 | // requirement: signed to unsigned >= 0 |
| 9703 | 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 | 9721 | const zero_inst = try sema.addConstant(operand_ty, zero_val); |
| 9706 | 9722 | const is_in_range = try block.addCmpVector(operand, zero_inst, .gte); |
| 9707 | 9723 | const all_in_range = try block.addInst(.{ |
| ... | ... | @@ -9713,7 +9729,7 @@ fn intCast( |
| 9713 | 9729 | }); |
| 9714 | 9730 | break :ok all_in_range; |
| 9715 | 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 | 9733 | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); |
| 9718 | 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 | 9743 | const tracy = trace(@src()); |
| 9728 | 9744 | defer tracy.end(); |
| 9729 | 9745 | |
| 9746 | const mod = sema.mod; | |
| 9730 | 9747 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9731 | 9748 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9732 | 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 | 9752 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 9736 | 9753 | const operand = try sema.resolveInst(extra.rhs); |
| 9737 | 9754 | const operand_ty = sema.typeOf(operand); |
| 9738 | switch (dest_ty.zigTypeTag()) { | |
| 9755 | switch (dest_ty.zigTypeTag(mod)) { | |
| 9739 | 9756 | .AnyFrame, |
| 9740 | 9757 | .ComptimeFloat, |
| 9741 | 9758 | .ComptimeInt, |
| ... | ... | @@ -9751,14 +9768,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9751 | 9768 | .Type, |
| 9752 | 9769 | .Undefined, |
| 9753 | 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 | 9773 | .Enum => { |
| 9757 | 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 | 9776 | errdefer msg.destroy(sema.gpa); |
| 9760 | switch (operand_ty.zigTypeTag()) { | |
| 9761 | .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}), | |
| 9777 | switch (operand_ty.zigTypeTag(mod)) { | |
| 9778 | .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(mod)}), | |
| 9762 | 9779 | else => {}, |
| 9763 | 9780 | } |
| 9764 | 9781 | |
| ... | ... | @@ -9769,11 +9786,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9769 | 9786 | |
| 9770 | 9787 | .Pointer => { |
| 9771 | 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 | 9790 | errdefer msg.destroy(sema.gpa); |
| 9774 | switch (operand_ty.zigTypeTag()) { | |
| 9775 | .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(sema.mod)}), | |
| 9776 | .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(sema.mod)}), | |
| 9791 | switch (operand_ty.zigTypeTag(mod)) { | |
| 9792 | .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(mod)}), | |
| 9793 | .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(mod)}), | |
| 9777 | 9794 | else => {}, |
| 9778 | 9795 | } |
| 9779 | 9796 | |
| ... | ... | @@ -9781,14 +9798,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9781 | 9798 | }; |
| 9782 | 9799 | return sema.failWithOwnedErrorMsg(msg); |
| 9783 | 9800 | }, |
| 9784 | .Struct, .Union => if (dest_ty.containerLayout() == .Auto) { | |
| 9785 | const container = switch (dest_ty.zigTypeTag()) { | |
| 9801 | .Struct, .Union => if (dest_ty.containerLayout(mod) == .Auto) { | |
| 9802 | const container = switch (dest_ty.zigTypeTag(mod)) { | |
| 9786 | 9803 | .Struct => "struct", |
| 9787 | 9804 | .Union => "union", |
| 9788 | 9805 | else => unreachable, |
| 9789 | 9806 | }; |
| 9790 | 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 | 9816 | .Vector, |
| 9800 | 9817 | => {}, |
| 9801 | 9818 | } |
| 9802 | switch (operand_ty.zigTypeTag()) { | |
| 9819 | switch (operand_ty.zigTypeTag(mod)) { | |
| 9803 | 9820 | .AnyFrame, |
| 9804 | 9821 | .ComptimeFloat, |
| 9805 | 9822 | .ComptimeInt, |
| ... | ... | @@ -9815,14 +9832,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9815 | 9832 | .Type, |
| 9816 | 9833 | .Undefined, |
| 9817 | 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 | 9837 | .Enum => { |
| 9821 | 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 | 9840 | errdefer msg.destroy(sema.gpa); |
| 9824 | switch (dest_ty.zigTypeTag()) { | |
| 9825 | .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}), | |
| 9841 | switch (dest_ty.zigTypeTag(mod)) { | |
| 9842 | .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(mod)}), | |
| 9826 | 9843 | else => {}, |
| 9827 | 9844 | } |
| 9828 | 9845 | |
| ... | ... | @@ -9832,11 +9849,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9832 | 9849 | }, |
| 9833 | 9850 | .Pointer => { |
| 9834 | 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 | 9853 | errdefer msg.destroy(sema.gpa); |
| 9837 | switch (dest_ty.zigTypeTag()) { | |
| 9838 | .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}), | |
| 9839 | .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(sema.mod)}), | |
| 9854 | switch (dest_ty.zigTypeTag(mod)) { | |
| 9855 | .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(mod)}), | |
| 9856 | .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(mod)}), | |
| 9840 | 9857 | else => {}, |
| 9841 | 9858 | } |
| 9842 | 9859 | |
| ... | ... | @@ -9844,14 +9861,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9844 | 9861 | }; |
| 9845 | 9862 | return sema.failWithOwnedErrorMsg(msg); |
| 9846 | 9863 | }, |
| 9847 | .Struct, .Union => if (operand_ty.containerLayout() == .Auto) { | |
| 9848 | const container = switch (operand_ty.zigTypeTag()) { | |
| 9864 | .Struct, .Union => if (operand_ty.containerLayout(mod) == .Auto) { | |
| 9865 | const container = switch (operand_ty.zigTypeTag(mod)) { | |
| 9849 | 9866 | .Struct => "struct", |
| 9850 | 9867 | .Union => "union", |
| 9851 | 9868 | else => unreachable, |
| 9852 | 9869 | }; |
| 9853 | 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 | 9886 | const tracy = trace(@src()); |
| 9870 | 9887 | defer tracy.end(); |
| 9871 | 9888 | |
| 9889 | const mod = sema.mod; | |
| 9872 | 9890 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9873 | 9891 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9874 | 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 | 9895 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 9878 | 9896 | const operand = try sema.resolveInst(extra.rhs); |
| 9879 | 9897 | |
| 9880 | const target = sema.mod.getTarget(); | |
| 9881 | const dest_is_comptime_float = switch (dest_ty.zigTypeTag()) { | |
| 9898 | const target = mod.getTarget(); | |
| 9899 | const dest_is_comptime_float = switch (dest_ty.zigTypeTag(mod)) { | |
| 9882 | 9900 | .ComptimeFloat => true, |
| 9883 | 9901 | .Float => false, |
| 9884 | 9902 | else => return sema.fail( |
| 9885 | 9903 | block, |
| 9886 | 9904 | dest_ty_src, |
| 9887 | 9905 | "expected float type, found '{}'", |
| 9888 | .{dest_ty.fmt(sema.mod)}, | |
| 9906 | .{dest_ty.fmt(mod)}, | |
| 9889 | 9907 | ), |
| 9890 | 9908 | }; |
| 9891 | 9909 | |
| 9892 | 9910 | const operand_ty = sema.typeOf(operand); |
| 9893 | switch (operand_ty.zigTypeTag()) { | |
| 9911 | switch (operand_ty.zigTypeTag(mod)) { | |
| 9894 | 9912 | .ComptimeFloat, .Float, .ComptimeInt => {}, |
| 9895 | 9913 | else => return sema.fail( |
| 9896 | 9914 | block, |
| 9897 | 9915 | operand_src, |
| 9898 | 9916 | "expected float type, found '{}'", |
| 9899 | .{operand_ty.fmt(sema.mod)}, | |
| 9917 | .{operand_ty.fmt(mod)}, | |
| 9900 | 9918 | ), |
| 9901 | 9919 | } |
| 9902 | 9920 | |
| 9903 | 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 | 9924 | if (dest_is_comptime_float) { |
| 9907 | 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 | 9962 | const tracy = trace(@src()); |
| 9945 | 9963 | defer tracy.end(); |
| 9946 | 9964 | |
| 9965 | const mod = sema.mod; | |
| 9947 | 9966 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9948 | 9967 | const src = inst_data.src(); |
| 9949 | 9968 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 9950 | 9969 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 9951 | 9970 | const elem_index = try sema.resolveInst(extra.rhs); |
| 9952 | 9971 | const indexable_ty = sema.typeOf(array_ptr); |
| 9953 | if (indexable_ty.zigTypeTag() != .Pointer) { | |
| 9972 | if (indexable_ty.zigTypeTag(mod) != .Pointer) { | |
| 9954 | 9973 | const capture_src: LazySrcLoc = .{ .for_capture_from_input = inst_data.src_node }; |
| 9955 | 9974 | const msg = msg: { |
| 9956 | 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 | 9978 | errdefer msg.destroy(sema.gpa); |
| 9960 | if (indexable_ty.zigTypeTag() == .Array) { | |
| 9979 | if (indexable_ty.zigTypeTag(mod) == .Array) { | |
| 9961 | 9980 | try sema.errNote(block, src, msg, "consider using '&' here", .{}); |
| 9962 | 9981 | } |
| 9963 | 9982 | break :msg msg; |
| ... | ... | @@ -10054,7 +10073,7 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10054 | 10073 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 10055 | 10074 | const start = try sema.resolveInst(extra.start); |
| 10056 | 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 | 10077 | const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; |
| 10059 | 10078 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset }; |
| 10060 | 10079 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; |
| ... | ... | @@ -10076,6 +10095,8 @@ fn zirSwitchCapture( |
| 10076 | 10095 | const tracy = trace(@src()); |
| 10077 | 10096 | defer tracy.end(); |
| 10078 | 10097 | |
| 10098 | const mod = sema.mod; | |
| 10099 | const gpa = sema.gpa; | |
| 10079 | 10100 | const zir_datas = sema.code.instructions.items(.data); |
| 10080 | 10101 | const capture_info = zir_datas[inst].switch_capture; |
| 10081 | 10102 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; |
| ... | ... | @@ -10087,47 +10108,49 @@ fn zirSwitchCapture( |
| 10087 | 10108 | const operand_is_ref = cond_tag == .switch_cond_ref; |
| 10088 | 10109 | const operand_ptr = try sema.resolveInst(cond_info.operand); |
| 10089 | 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 | 10113 | if (block.inline_case_capture != .none) { |
| 10093 | 10114 | const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable; |
| 10094 | if (operand_ty.zigTypeTag() == .Union) { | |
| 10095 | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?); | |
| 10096 | const union_obj = operand_ty.cast(Type.Payload.Union).?.data; | |
| 10115 | const resolved_item_val = try sema.resolveLazyValue(item_val); | |
| 10116 | if (operand_ty.zigTypeTag(mod) == .Union) { | |
| 10117 | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, mod).?); | |
| 10118 | const union_obj = mod.typeToUnion(operand_ty).?; | |
| 10097 | 10119 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 10098 | 10120 | if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| { |
| 10099 | 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 | 10123 | .pointee_type = field_ty, |
| 10102 | .mutable = operand_ptr_ty.ptrIsMutable(), | |
| 10103 | .@"volatile" = operand_ptr_ty.isVolatilePtr(), | |
| 10104 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(), | |
| 10124 | .mutable = operand_ptr_ty.ptrIsMutable(mod), | |
| 10125 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), | |
| 10126 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), | |
| 10105 | 10127 | }); |
| 10106 | return sema.addConstant( | |
| 10107 | ptr_field_ty, | |
| 10108 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 10109 | .container_ptr = union_val, | |
| 10110 | .container_ty = operand_ty, | |
| 10111 | .field_index = field_index, | |
| 10112 | }), | |
| 10113 | ); | |
| 10128 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 10129 | .ty = ptr_field_ty.toIntern(), | |
| 10130 | .addr = .{ .field = .{ | |
| 10131 | .base = union_val.toIntern(), | |
| 10132 | .index = field_index, | |
| 10133 | } }, | |
| 10134 | } })).toValue()); | |
| 10114 | 10135 | } |
| 10115 | const tag_and_val = union_val.castTag(.@"union").?.data; | |
| 10116 | return sema.addConstant(field_ty, tag_and_val.val); | |
| 10136 | return sema.addConstant( | |
| 10137 | field_ty, | |
| 10138 | mod.intern_pool.indexToKey(union_val.toIntern()).un.val.toValue(), | |
| 10139 | ); | |
| 10117 | 10140 | } |
| 10118 | 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 | 10143 | .pointee_type = field_ty, |
| 10121 | .mutable = operand_ptr_ty.ptrIsMutable(), | |
| 10122 | .@"volatile" = operand_ptr_ty.isVolatilePtr(), | |
| 10123 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(), | |
| 10144 | .mutable = operand_ptr_ty.ptrIsMutable(mod), | |
| 10145 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), | |
| 10146 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), | |
| 10124 | 10147 | }); |
| 10125 | 10148 | return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty); |
| 10126 | 10149 | } else { |
| 10127 | 10150 | return block.addStructFieldVal(operand_ptr, field_index, field_ty); |
| 10128 | 10151 | } |
| 10129 | 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 | 10154 | } else { |
| 10132 | 10155 | return block.inline_case_capture; |
| 10133 | 10156 | } |
| ... | ... | @@ -10144,7 +10167,7 @@ fn zirSwitchCapture( |
| 10144 | 10167 | return operand_ptr; |
| 10145 | 10168 | } |
| 10146 | 10169 | |
| 10147 | switch (operand_ty.zigTypeTag()) { | |
| 10170 | switch (operand_ty.zigTypeTag(mod)) { | |
| 10148 | 10171 | .ErrorSet => if (block.switch_else_err_ty) |some| { |
| 10149 | 10172 | return sema.bitCast(block, some, operand, operand_src, null); |
| 10150 | 10173 | } else { |
| ... | ... | @@ -10162,14 +10185,14 @@ fn zirSwitchCapture( |
| 10162 | 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 | 10189 | .Union => { |
| 10167 | const union_obj = operand_ty.cast(Type.Payload.Union).?.data; | |
| 10190 | const union_obj = mod.typeToUnion(operand_ty).?; | |
| 10168 | 10191 | const first_item = try sema.resolveInst(items[0]); |
| 10169 | 10192 | // Previous switch validation ensured this will succeed |
| 10170 | 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 | 10196 | const first_field = union_obj.fields.values()[first_field_index]; |
| 10174 | 10197 | |
| 10175 | 10198 | for (items[1..], 0..) |item, i| { |
| ... | ... | @@ -10177,22 +10200,22 @@ fn zirSwitchCapture( |
| 10177 | 10200 | // Previous switch validation ensured this will succeed |
| 10178 | 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 | 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 | 10206 | const msg = msg: { |
| 10184 | 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 | 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 | 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 | 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); | |
| 10194 | try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)}); | |
| 10195 | try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)}); | |
| 10216 | const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); | |
| 10217 | try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)}); | |
| 10218 | try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)}); | |
| 10196 | 10219 | break :msg msg; |
| 10197 | 10220 | }; |
| 10198 | 10221 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -10200,21 +10223,20 @@ fn zirSwitchCapture( |
| 10200 | 10223 | } |
| 10201 | 10224 | |
| 10202 | 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 | 10227 | .pointee_type = first_field.ty, |
| 10205 | 10228 | .@"addrspace" = .generic, |
| 10206 | .mutable = operand_ptr_ty.ptrIsMutable(), | |
| 10229 | .mutable = operand_ptr_ty.ptrIsMutable(mod), | |
| 10207 | 10230 | }); |
| 10208 | 10231 | |
| 10209 | 10232 | if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| { |
| 10210 | return sema.addConstant( | |
| 10211 | field_ty_ptr, | |
| 10212 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 10213 | .container_ptr = op_ptr_val, | |
| 10214 | .container_ty = operand_ty, | |
| 10215 | .field_index = first_field_index, | |
| 10216 | }), | |
| 10217 | ); | |
| 10233 | return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{ | |
| 10234 | .ty = field_ty_ptr.toIntern(), | |
| 10235 | .addr = .{ .field = .{ | |
| 10236 | .base = op_ptr_val.toIntern(), | |
| 10237 | .index = first_field_index, | |
| 10238 | } }, | |
| 10239 | } })).toValue()); | |
| 10218 | 10240 | } |
| 10219 | 10241 | try sema.requireRuntimeBlock(block, operand_src, null); |
| 10220 | 10242 | return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr); |
| ... | ... | @@ -10223,7 +10245,7 @@ fn zirSwitchCapture( |
| 10223 | 10245 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { |
| 10224 | 10246 | return sema.addConstant( |
| 10225 | 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 | 10251 | try sema.requireRuntimeBlock(block, operand_src, null); |
| ... | ... | @@ -10231,28 +10253,23 @@ fn zirSwitchCapture( |
| 10231 | 10253 | }, |
| 10232 | 10254 | .ErrorSet => { |
| 10233 | 10255 | if (is_multi) { |
| 10234 | var names: Module.ErrorSet.NameMap = .{}; | |
| 10256 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; | |
| 10235 | 10257 | try names.ensureUnusedCapacity(sema.arena, items.len); |
| 10236 | 10258 | for (items) |item| { |
| 10237 | 10259 | const item_ref = try sema.resolveInst(item); |
| 10238 | 10260 | // Previous switch validation ensured this will succeed |
| 10239 | const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; | |
| 10240 | names.putAssumeCapacityNoClobber( | |
| 10241 | item_val.getError().?, | |
| 10242 | {}, | |
| 10243 | ); | |
| 10261 | const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; | |
| 10262 | names.putAssumeCapacityNoClobber(item_val.getErrorName(mod).unwrap().?, {}); | |
| 10244 | 10263 | } |
| 10245 | // names must be sorted | |
| 10246 | Module.ErrorSet.sortNames(&names); | |
| 10247 | const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); | |
| 10264 | const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); | |
| 10248 | 10265 | |
| 10249 | 10266 | return sema.bitCast(block, else_error_ty, operand, operand_src, null); |
| 10250 | 10267 | } else { |
| 10251 | 10268 | const item_ref = try sema.resolveInst(items[0]); |
| 10252 | 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 | 10273 | return sema.bitCast(block, item_ty, operand, operand_src, null); |
| 10257 | 10274 | } |
| 10258 | 10275 | }, |
| ... | ... | @@ -10269,6 +10286,7 @@ fn zirSwitchCapture( |
| 10269 | 10286 | } |
| 10270 | 10287 | |
| 10271 | 10288 | fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 10289 | const mod = sema.mod; | |
| 10272 | 10290 | const zir_datas = sema.code.instructions.items(.data); |
| 10273 | 10291 | const inst_data = zir_datas[inst].un_tok; |
| 10274 | 10292 | const src = inst_data.src(); |
| ... | ... | @@ -10278,12 +10296,12 @@ fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile |
| 10278 | 10296 | const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node; |
| 10279 | 10297 | const operand_ptr = try sema.resolveInst(cond_data.operand); |
| 10280 | 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 | 10302 | const msg = msg: { |
| 10285 | 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 | 10306 | errdefer msg.destroy(sema.gpa); |
| 10289 | 10307 | try sema.addDeclaredHereNote(msg, operand_ty); |
| ... | ... | @@ -10301,6 +10319,7 @@ fn zirSwitchCond( |
| 10301 | 10319 | inst: Zir.Inst.Index, |
| 10302 | 10320 | is_ref: bool, |
| 10303 | 10321 | ) CompileError!Air.Inst.Ref { |
| 10322 | const mod = sema.mod; | |
| 10304 | 10323 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 10305 | 10324 | const src = inst_data.src(); |
| 10306 | 10325 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; |
| ... | ... | @@ -10311,7 +10330,7 @@ fn zirSwitchCond( |
| 10311 | 10330 | operand_ptr; |
| 10312 | 10331 | const operand_ty = sema.typeOf(operand); |
| 10313 | 10332 | |
| 10314 | switch (operand_ty.zigTypeTag()) { | |
| 10333 | switch (operand_ty.zigTypeTag(mod)) { | |
| 10315 | 10334 | .Type, |
| 10316 | 10335 | .Void, |
| 10317 | 10336 | .Bool, |
| ... | ... | @@ -10325,8 +10344,8 @@ fn zirSwitchCond( |
| 10325 | 10344 | .ErrorSet, |
| 10326 | 10345 | .Enum, |
| 10327 | 10346 | => { |
| 10328 | if (operand_ty.isSlice()) { | |
| 10329 | return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}); | |
| 10347 | if (operand_ty.isSlice(mod)) { | |
| 10348 | return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(mod)}); | |
| 10330 | 10349 | } |
| 10331 | 10350 | if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| { |
| 10332 | 10351 | return sema.addConstant(operand_ty, opv); |
| ... | ... | @@ -10336,12 +10355,12 @@ fn zirSwitchCond( |
| 10336 | 10355 | |
| 10337 | 10356 | .Union => { |
| 10338 | 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 | 10359 | const msg = msg: { |
| 10341 | 10360 | const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{}); |
| 10342 | 10361 | errdefer msg.destroy(sema.gpa); |
| 10343 | if (union_ty.declSrcLocOrNull(sema.mod)) |union_src| { | |
| 10344 | try sema.mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{}); | |
| 10362 | if (union_ty.declSrcLocOrNull(mod)) |union_src| { | |
| 10363 | try mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{}); | |
| 10345 | 10364 | } |
| 10346 | 10365 | break :msg msg; |
| 10347 | 10366 | }; |
| ... | ... | @@ -10361,17 +10380,19 @@ fn zirSwitchCond( |
| 10361 | 10380 | .Vector, |
| 10362 | 10381 | .Frame, |
| 10363 | 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 | 10389 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 10371 | 10390 | const tracy = trace(@src()); |
| 10372 | 10391 | defer tracy.end(); |
| 10373 | 10392 | |
| 10393 | const mod = sema.mod; | |
| 10374 | 10394 | const gpa = sema.gpa; |
| 10395 | const ip = &mod.intern_pool; | |
| 10375 | 10396 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 10376 | 10397 | const src = inst_data.src(); |
| 10377 | 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 | 10434 | const cond_index = Zir.refToIndex(extra.data.operand).?; |
| 10414 | 10435 | const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; |
| 10415 | 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 | 10441 | // Duplicate checking variables later also used for `inline else`. |
| 10421 | 10442 | var seen_enum_fields: []?Module.SwitchProngSrc = &.{}; |
| 10422 | 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 | 10445 | var true_count: u8 = 0; |
| 10425 | 10446 | var false_count: u8 = 0; |
| 10426 | 10447 | |
| ... | ... | @@ -10433,12 +10454,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10433 | 10454 | var empty_enum = false; |
| 10434 | 10455 | |
| 10435 | 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 | 10459 | var else_error_ty: ?Type = null; |
| 10439 | 10460 | |
| 10440 | 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 | 10463 | const msg = msg: { |
| 10443 | 10464 | const msg = try sema.errMsg( |
| 10444 | 10465 | block, |
| ... | ... | @@ -10459,14 +10480,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10459 | 10480 | return sema.failWithOwnedErrorMsg(msg); |
| 10460 | 10481 | } |
| 10461 | 10482 | |
| 10462 | const target = sema.mod.getTarget(); | |
| 10463 | ||
| 10464 | 10483 | // Validate for duplicate items, missing else prong, and invalid range. |
| 10465 | switch (operand_ty.zigTypeTag()) { | |
| 10484 | switch (operand_ty.zigTypeTag(mod)) { | |
| 10466 | 10485 | .Union => unreachable, // handled in zirSwitchCond |
| 10467 | 10486 | .Enum => { |
| 10468 | seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); | |
| 10469 | empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); | |
| 10487 | seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod)); | |
| 10488 | empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod); | |
| 10470 | 10489 | @memset(seen_enum_fields, null); |
| 10471 | 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 | 10540 | } else true; |
| 10522 | 10541 | |
| 10523 | 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 | 10544 | block, |
| 10526 | 10545 | special_prong_src, |
| 10527 | 10546 | "unreachable else prong; all cases already handled", |
| ... | ... | @@ -10539,25 +10558,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10539 | 10558 | for (seen_enum_fields, 0..) |seen_src, i| { |
| 10540 | 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 | 10562 | try sema.addFieldErrNote( |
| 10544 | 10563 | operand_ty, |
| 10545 | 10564 | i, |
| 10546 | 10565 | msg, |
| 10547 | "unhandled enumeration value: '{s}'", | |
| 10548 | .{field_name}, | |
| 10566 | "unhandled enumeration value: '{}'", | |
| 10567 | .{field_name.fmt(&mod.intern_pool)}, | |
| 10549 | 10568 | ); |
| 10550 | 10569 | } |
| 10551 | try sema.mod.errNoteNonLazy( | |
| 10552 | operand_ty.declSrcLoc(sema.mod), | |
| 10570 | try mod.errNoteNonLazy( | |
| 10571 | operand_ty.declSrcLoc(mod), | |
| 10553 | 10572 | msg, |
| 10554 | 10573 | "enum '{}' declared here", |
| 10555 | .{operand_ty.fmt(sema.mod)}, | |
| 10574 | .{operand_ty.fmt(mod)}, | |
| 10556 | 10575 | ); |
| 10557 | 10576 | break :msg msg; |
| 10558 | 10577 | }; |
| 10559 | 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 | 10580 | return sema.fail( |
| 10562 | 10581 | block, |
| 10563 | 10582 | src, |
| ... | ... | @@ -10614,7 +10633,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10614 | 10633 | |
| 10615 | 10634 | try sema.resolveInferredErrorSetTy(block, src, operand_ty); |
| 10616 | 10635 | |
| 10617 | if (operand_ty.isAnyError()) { | |
| 10636 | if (operand_ty.isAnyError(mod)) { | |
| 10618 | 10637 | if (special_prong != .@"else") { |
| 10619 | 10638 | return sema.fail( |
| 10620 | 10639 | block, |
| ... | ... | @@ -10628,7 +10647,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10628 | 10647 | var maybe_msg: ?*Module.ErrorMsg = null; |
| 10629 | 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 | 10651 | if (!seen_errors.contains(error_name) and special_prong != .@"else") { |
| 10633 | 10652 | const msg = maybe_msg orelse blk: { |
| 10634 | 10653 | maybe_msg = try sema.errMsg( |
| ... | ... | @@ -10644,8 +10663,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10644 | 10663 | block, |
| 10645 | 10664 | src, |
| 10646 | 10665 | msg, |
| 10647 | "unhandled error value: 'error.{s}'", | |
| 10648 | .{error_name}, | |
| 10666 | "unhandled error value: 'error.{}'", | |
| 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 | 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 | 10679 | // In order to enable common patterns for generic code allow simple else bodies |
| 10661 | 10680 | // else => unreachable, |
| 10662 | 10681 | // else => return, |
| ... | ... | @@ -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(); | |
| 10697 | var names: Module.ErrorSet.NameMap = .{}; | |
| 10715 | const error_names = operand_ty.errorSetNames(mod); | |
| 10716 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; | |
| 10698 | 10717 | try names.ensureUnusedCapacity(sema.arena, error_names.len); |
| 10699 | 10718 | for (error_names) |error_name| { |
| 10700 | 10719 | if (seen_errors.contains(error_name)) continue; |
| 10701 | 10720 | |
| 10702 | 10721 | names.putAssumeCapacityNoClobber(error_name, {}); |
| 10703 | 10722 | } |
| 10704 | ||
| 10705 | // names must be sorted | |
| 10706 | Module.ErrorSet.sortNames(&names); | |
| 10707 | else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); | |
| 10723 | // No need to keep the hash map metadata correct; here we | |
| 10724 | // extract the (sorted) keys only. | |
| 10725 | else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); | |
| 10708 | 10726 | } |
| 10709 | 10727 | }, |
| 10710 | 10728 | .Int, .ComptimeInt => { |
| ... | ... | @@ -10722,7 +10740,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10722 | 10740 | block, |
| 10723 | 10741 | &range_set, |
| 10724 | 10742 | item_ref, |
| 10725 | operand_ty, | |
| 10726 | 10743 | src_node_offset, |
| 10727 | 10744 | .{ .scalar = scalar_i }, |
| 10728 | 10745 | ); |
| ... | ... | @@ -10745,7 +10762,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10745 | 10762 | block, |
| 10746 | 10763 | &range_set, |
| 10747 | 10764 | item_ref, |
| 10748 | operand_ty, | |
| 10749 | 10765 | src_node_offset, |
| 10750 | 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 | 10779 | &range_set, |
| 10764 | 10780 | item_first, |
| 10765 | 10781 | item_last, |
| 10766 | operand_ty, | |
| 10767 | 10782 | src_node_offset, |
| 10768 | 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 | 10789 | } |
| 10775 | 10790 | |
| 10776 | 10791 | check_range: { |
| 10777 | if (operand_ty.zigTypeTag() == .Int) { | |
| 10778 | var arena = std.heap.ArenaAllocator.init(gpa); | |
| 10779 | defer arena.deinit(); | |
| 10780 | ||
| 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)) { | |
| 10792 | if (operand_ty.zigTypeTag(mod) == .Int) { | |
| 10793 | const min_int = try operand_ty.minInt(mod, operand_ty); | |
| 10794 | const max_int = try operand_ty.maxInt(mod, operand_ty); | |
| 10795 | if (try range_set.spans(min_int.toIntern(), max_int.toIntern())) { | |
| 10784 | 10796 | if (special_prong == .@"else") { |
| 10785 | 10797 | return sema.fail( |
| 10786 | 10798 | block, |
| ... | ... | @@ -10878,15 +10890,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10878 | 10890 | block, |
| 10879 | 10891 | src, |
| 10880 | 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, .{ | |
| 10886 | .ty = operand_ty, | |
| 10887 | .mod = sema.mod, | |
| 10888 | }); | |
| 10889 | defer seen_values.deinit(); | |
| 10897 | var seen_values = ValueSrcMap{}; | |
| 10898 | defer seen_values.deinit(gpa); | |
| 10890 | 10899 | |
| 10891 | 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 | 10957 | .ComptimeFloat, |
| 10949 | 10958 | .Float, |
| 10950 | 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 | 11000 | defer merges.deinit(gpa); |
| 10992 | 11001 | |
| 10993 | 11002 | if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { |
| 11003 | const resolved_operand_val = try sema.resolveLazyValue(operand_val); | |
| 10994 | 11004 | var extra_index: usize = special.end; |
| 10995 | 11005 | { |
| 10996 | 11006 | var scalar_i: usize = 0; |
| ... | ... | @@ -11005,8 +11015,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11005 | 11015 | |
| 11006 | 11016 | const item = try sema.resolveInst(item_ref); |
| 11007 | 11017 | // Validation above ensured these will succeed. |
| 11008 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable; | |
| 11009 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { | |
| 11018 | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; | |
| 11019 | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { | |
| 11010 | 11020 | if (is_inline) child_block.inline_case_capture = operand; |
| 11011 | 11021 | |
| 11012 | 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 | 11041 | for (items) |item_ref| { |
| 11032 | 11042 | const item = try sema.resolveInst(item_ref); |
| 11033 | 11043 | // Validation above ensured these will succeed. |
| 11034 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable; | |
| 11035 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { | |
| 11044 | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; | |
| 11045 | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { | |
| 11036 | 11046 | if (is_inline) child_block.inline_case_capture = operand; |
| 11037 | 11047 | |
| 11038 | 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 | 11060 | // Validation above ensured these will succeed. |
| 11051 | 11061 | const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable; |
| 11052 | 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 | |
| 11054 | (try sema.compareAll(operand_val, .lte, last_tv.val, operand_ty))) | |
| 11063 | if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and | |
| 11064 | (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty))) | |
| 11055 | 11065 | { |
| 11056 | 11066 | if (is_inline) child_block.inline_case_capture = operand; |
| 11057 | 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 | 11090 | if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { |
| 11081 | 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 | |
| 11084 | (!operand_ty.isNonexhaustiveEnum() or union_originally)) | |
| 11093 | if (mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag(mod) == .Enum and | |
| 11094 | (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) | |
| 11085 | 11095 | { |
| 11086 | 11096 | try sema.zirDbgStmt(block, cond_dbg_node_index); |
| 11087 | 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 | 11131 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11122 | 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 | 11135 | defer wip_captures.deinit(); |
| 11126 | 11136 | |
| 11127 | 11137 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | ... | @@ -11133,9 +11143,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11133 | 11143 | // `item` is already guaranteed to be constant known. |
| 11134 | 11144 | |
| 11135 | 11145 | const analyze_body = if (union_originally) blk: { |
| 11136 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; | |
| 11137 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); | |
| 11138 | break :blk field_ty.zigTypeTag() != .NoReturn; | |
| 11146 | const item_val = sema.resolveConstLazyValue(block, .unneeded, item, "") catch unreachable; | |
| 11147 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); | |
| 11148 | break :blk field_ty.zigTypeTag(mod) != .NoReturn; | |
| 11139 | 11149 | } else true; |
| 11140 | 11150 | |
| 11141 | 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 | 11207 | const item_last_ref = try sema.resolveInst(last_ref); |
| 11198 | 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 | 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 | 11217 | cases_len += 1; |
| 11205 | 11218 | |
| ... | ... | @@ -11212,8 +11225,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11212 | 11225 | if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) { |
| 11213 | 11226 | error.NeededSourceLocation => { |
| 11214 | 11227 | const case_src = Module.SwitchProngSrc{ .range = .{ .prong = multi_i, .item = range_i } }; |
| 11215 | const decl = sema.mod.declPtr(case_block.src_decl); | |
| 11216 | try sema.emitBackwardBranch(block, case_src.resolve(sema.gpa, decl, src_node_offset, .none)); | |
| 11228 | const decl = mod.declPtr(case_block.src_decl); | |
| 11229 | try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none)); | |
| 11217 | 11230 | unreachable; |
| 11218 | 11231 | }, |
| 11219 | 11232 | else => return err, |
| ... | ... | @@ -11241,15 +11254,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11241 | 11254 | |
| 11242 | 11255 | const analyze_body = if (union_originally) blk: { |
| 11243 | 11256 | const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; |
| 11244 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); | |
| 11245 | break :blk field_ty.zigTypeTag() != .NoReturn; | |
| 11257 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); | |
| 11258 | break :blk field_ty.zigTypeTag(mod) != .NoReturn; | |
| 11246 | 11259 | } else true; |
| 11247 | 11260 | |
| 11248 | 11261 | if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) { |
| 11249 | 11262 | error.NeededSourceLocation => { |
| 11250 | 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); | |
| 11252 | try sema.emitBackwardBranch(block, case_src.resolve(sema.gpa, decl, src_node_offset, .none)); | |
| 11264 | const decl = mod.declPtr(case_block.src_decl); | |
| 11265 | try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none)); | |
| 11253 | 11266 | unreachable; |
| 11254 | 11267 | }, |
| 11255 | 11268 | else => return err, |
| ... | ... | @@ -11285,8 +11298,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11285 | 11298 | for (items) |item_ref| { |
| 11286 | 11299 | const item = try sema.resolveInst(item_ref); |
| 11287 | 11300 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; |
| 11288 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); | |
| 11289 | if (field_ty.zigTypeTag() != .NoReturn) break true; | |
| 11301 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); | |
| 11302 | if (field_ty.zigTypeTag(mod) != .NoReturn) break true; | |
| 11290 | 11303 | } else false |
| 11291 | 11304 | else |
| 11292 | 11305 | true; |
| ... | ... | @@ -11366,7 +11379,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11366 | 11379 | var cond_body = try case_block.instructions.toOwnedSlice(gpa); |
| 11367 | 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 | 11383 | defer wip_captures.deinit(); |
| 11371 | 11384 | |
| 11372 | 11385 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | ... | @@ -11409,18 +11422,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11409 | 11422 | var final_else_body: []const Air.Inst.Index = &.{}; |
| 11410 | 11423 | if (special.body.len != 0 or !is_first or case_block.wantSafety()) { |
| 11411 | 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 | 11426 | .Enum => { |
| 11414 | if (operand_ty.isNonexhaustiveEnum() and !union_originally) { | |
| 11427 | if (operand_ty.isNonexhaustiveEnum(mod) and !union_originally) { | |
| 11415 | 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 | 11432 | for (seen_enum_fields, 0..) |f, i| { |
| 11420 | 11433 | if (f != null) continue; |
| 11421 | 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 | 11437 | const item_ref = try sema.addConstant(operand_ty, item_val); |
| 11425 | 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 | 11441 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 11429 | 11442 | |
| 11430 | 11443 | const analyze_body = if (union_originally) blk: { |
| 11431 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); | |
| 11432 | break :blk field_ty.zigTypeTag() != .NoReturn; | |
| 11444 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); | |
| 11445 | break :blk field_ty.zigTypeTag(mod) != .NoReturn; | |
| 11433 | 11446 | } else true; |
| 11434 | 11447 | |
| 11435 | 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 | 11462 | } |
| 11450 | 11463 | }, |
| 11451 | 11464 | .ErrorSet => { |
| 11452 | if (operand_ty.isAnyError()) { | |
| 11465 | if (operand_ty.isAnyError(mod)) { | |
| 11453 | 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 | 11472 | if (seen_errors.contains(error_name)) continue; |
| 11459 | 11473 | cases_len += 1; |
| 11460 | 11474 | |
| 11461 | const item_val = try Value.Tag.@"error".create(sema.arena, .{ .name = error_name }); | |
| 11462 | const item_ref = try sema.addConstant(operand_ty, item_val); | |
| 11475 | const item_val = try mod.intern(.{ .err = .{ | |
| 11476 | .ty = operand_ty.toIntern(), | |
| 11477 | .name = error_name, | |
| 11478 | } }); | |
| 11479 | const item_ref = try sema.addConstant(operand_ty, item_val.toValue()); | |
| 11463 | 11480 | case_block.inline_case_capture = item_ref; |
| 11464 | 11481 | |
| 11465 | 11482 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | ... | @@ -11482,7 +11499,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11482 | 11499 | while (try it.next()) |cur| { |
| 11483 | 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 | 11503 | case_block.inline_case_capture = item_ref; |
| 11487 | 11504 | |
| 11488 | 11505 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | ... | @@ -11539,19 +11556,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11539 | 11556 | } |
| 11540 | 11557 | }, |
| 11541 | 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 | 11564 | defer wip_captures.deinit(); |
| 11548 | 11565 | |
| 11549 | 11566 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11550 | 11567 | case_block.wip_capture_scope = wip_captures.scope; |
| 11551 | 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 | |
| 11554 | operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally)) | |
| 11570 | if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and | |
| 11571 | operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) | |
| 11555 | 11572 | { |
| 11556 | 11573 | try sema.zirDbgStmt(&case_block, cond_dbg_node_index); |
| 11557 | 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 | 11578 | const analyze_body = if (union_originally and !special.is_inline) |
| 11562 | 11579 | for (seen_enum_fields, 0..) |seen_field, index| { |
| 11563 | 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 | 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 | 11584 | } else false |
| 11568 | 11585 | else |
| 11569 | 11586 | true; |
| ... | ... | @@ -11620,47 +11637,70 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11620 | 11637 | } |
| 11621 | 11638 | |
| 11622 | 11639 | const RangeSetUnhandledIterator = struct { |
| 11623 | sema: *Sema, | |
| 11624 | ty: Type, | |
| 11625 | cur: Value, | |
| 11626 | max: Value, | |
| 11640 | mod: *Module, | |
| 11641 | cur: ?InternPool.Index, | |
| 11642 | max: InternPool.Index, | |
| 11643 | range_i: usize, | |
| 11627 | 11644 | ranges: []const RangeSet.Range, |
| 11628 | range_i: usize = 0, | |
| 11629 | first: bool = true, | |
| 11645 | limbs: []math.big.Limb, | |
| 11630 | 11646 | |
| 11631 | fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator { | |
| 11632 | const target = sema.mod.getTarget(); | |
| 11633 | const min = try ty.minInt(sema.arena, target); | |
| 11634 | const max = try ty.maxInt(sema.arena, target); | |
| 11647 | const preallocated_limbs = math.big.int.calcTwosCompLimbCount(128); | |
| 11635 | 11648 | |
| 11636 | return RangeSetUnhandledIterator{ | |
| 11637 | .sema = sema, | |
| 11638 | .ty = ty, | |
| 11639 | .cur = min, | |
| 11640 | .max = max, | |
| 11649 | fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator { | |
| 11650 | const mod = sema.mod; | |
| 11651 | const int_type = mod.intern_pool.indexToKey(ty.toIntern()).int_type; | |
| 11652 | const needed_limbs = math.big.int.calcTwosCompLimbCount(int_type.bits); | |
| 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 | 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 { | |
| 11646 | while (it.range_i < it.ranges.len) : (it.range_i += 1) { | |
| 11647 | if (!it.first) { | |
| 11648 | it.cur = try it.sema.intAdd(it.cur, Value.one, it.ty); | |
| 11649 | } | |
| 11650 | it.first = false; | |
| 11651 | if (it.cur.compareAll(.lt, it.ranges[it.range_i].first, it.ty, it.sema.mod)) { | |
| 11652 | return it.cur; | |
| 11653 | } | |
| 11654 | it.cur = it.ranges[it.range_i].last; | |
| 11655 | } | |
| 11656 | if (!it.first) { | |
| 11657 | it.cur = try it.sema.intAdd(it.cur, Value.one, it.ty); | |
| 11666 | fn addOne(it: *const RangeSetUnhandledIterator, val: InternPool.Index) !?InternPool.Index { | |
| 11667 | if (val == it.max) return null; | |
| 11668 | const int = it.mod.intern_pool.indexToKey(val).int; | |
| 11669 | ||
| 11670 | switch (int.storage) { | |
| 11671 | inline .u64, .i64 => |val_int| { | |
| 11672 | const next_int = @addWithOverflow(val_int, 1); | |
| 11673 | if (next_int[1] == 0) | |
| 11674 | return (try it.mod.intValue(int.ty.toType(), next_int[0])).toIntern(); | |
| 11675 | }, | |
| 11676 | .big_int => {}, | |
| 11677 | .lazy_align, .lazy_size => unreachable, | |
| 11658 | 11678 | } |
| 11659 | it.first = false; | |
| 11660 | if (it.cur.compareAll(.lte, it.max, it.ty, it.sema.mod)) { | |
| 11661 | return it.cur; | |
| 11679 | ||
| 11680 | var val_space: InternPool.Key.Int.Storage.BigIntSpace = undefined; | |
| 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 | 11711 | switch_node_offset: i32, |
| 11672 | 11712 | switch_prong_src: Module.SwitchProngSrc, |
| 11673 | 11713 | range_expand: Module.SwitchProngSrc.RangeExpand, |
| 11674 | ) CompileError!TypedValue { | |
| 11714 | ) CompileError!InternPool.Index { | |
| 11715 | const mod = sema.mod; | |
| 11675 | 11716 | const item = try sema.resolveInst(item_ref); |
| 11676 | const item_ty = sema.typeOf(item); | |
| 11677 | 11717 | // Constructing a LazySrcLoc is costly because we only have the switch AST node. |
| 11678 | 11718 | // Only if we know for sure we need to report a compile error do we resolve the |
| 11679 | 11719 | // full source locations. |
| 11680 | if (sema.resolveConstValue(block, .unneeded, item, "")) |val| { | |
| 11681 | try sema.resolveLazyValue(val); | |
| 11682 | return TypedValue{ .ty = item_ty, .val = val }; | |
| 11720 | if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| { | |
| 11721 | return val.toIntern(); | |
| 11683 | 11722 | } else |err| switch (err) { |
| 11684 | 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 | 11725 | _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); |
| 11687 | 11726 | unreachable; |
| 11688 | 11727 | }, |
| ... | ... | @@ -11696,17 +11735,17 @@ fn validateSwitchRange( |
| 11696 | 11735 | range_set: *RangeSet, |
| 11697 | 11736 | first_ref: Zir.Inst.Ref, |
| 11698 | 11737 | last_ref: Zir.Inst.Ref, |
| 11699 | operand_ty: Type, | |
| 11700 | 11738 | src_node_offset: i32, |
| 11701 | 11739 | switch_prong_src: Module.SwitchProngSrc, |
| 11702 | 11740 | ) CompileError!void { |
| 11703 | const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val; | |
| 11704 | const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val; | |
| 11705 | if (first_val.compareAll(.gt, last_val, operand_ty, sema.mod)) { | |
| 11706 | const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first); | |
| 11741 | const mod = sema.mod; | |
| 11742 | const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first); | |
| 11743 | const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last); | |
| 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 | 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 | 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 | 11754 | block: *Block, |
| 11716 | 11755 | range_set: *RangeSet, |
| 11717 | 11756 | item_ref: Zir.Inst.Ref, |
| 11718 | operand_ty: Type, | |
| 11719 | 11757 | src_node_offset: i32, |
| 11720 | 11758 | switch_prong_src: Module.SwitchProngSrc, |
| 11721 | 11759 | ) CompileError!void { |
| 11722 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | |
| 11723 | const maybe_prev_src = try range_set.add(item_val, item_val, operand_ty, switch_prong_src); | |
| 11760 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | |
| 11761 | const maybe_prev_src = try range_set.add(item, item, switch_prong_src); | |
| 11724 | 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 | 11771 | src_node_offset: i32, |
| 11734 | 11772 | switch_prong_src: Module.SwitchProngSrc, |
| 11735 | 11773 | ) CompileError!void { |
| 11736 | const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | |
| 11737 | const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse { | |
| 11738 | const maybe_prev_src = try range_set.add(item_tv.val, item_tv.val, item_tv.ty, switch_prong_src); | |
| 11774 | const ip = &sema.mod.intern_pool; | |
| 11775 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | |
| 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 | 11779 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 11740 | 11780 | }; |
| 11741 | 11781 | const maybe_prev_src = seen_fields[field_index]; |
| ... | ... | @@ -11751,9 +11791,10 @@ fn validateSwitchItemError( |
| 11751 | 11791 | src_node_offset: i32, |
| 11752 | 11792 | switch_prong_src: Module.SwitchProngSrc, |
| 11753 | 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 | 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 | 11798 | const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| |
| 11758 | 11799 | prev.value |
| 11759 | 11800 | else |
| ... | ... | @@ -11769,10 +11810,10 @@ fn validateSwitchDupe( |
| 11769 | 11810 | src_node_offset: i32, |
| 11770 | 11811 | ) CompileError!void { |
| 11771 | 11812 | const prev_prong_src = maybe_prev_src orelse return; |
| 11772 | const gpa = sema.gpa; | |
| 11773 | const block_src_decl = sema.mod.declPtr(block.src_decl); | |
| 11774 | const src = switch_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none); | |
| 11775 | const prev_src = prev_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none); | |
| 11813 | const mod = sema.mod; | |
| 11814 | const block_src_decl = mod.declPtr(block.src_decl); | |
| 11815 | const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); | |
| 11816 | const prev_src = prev_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); | |
| 11776 | 11817 | const msg = msg: { |
| 11777 | 11818 | const msg = try sema.errMsg( |
| 11778 | 11819 | block, |
| ... | ... | @@ -11802,20 +11843,21 @@ fn validateSwitchItemBool( |
| 11802 | 11843 | src_node_offset: i32, |
| 11803 | 11844 | switch_prong_src: Module.SwitchProngSrc, |
| 11804 | 11845 | ) CompileError!void { |
| 11805 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | |
| 11806 | if (item_val.toBool()) { | |
| 11846 | const mod = sema.mod; | |
| 11847 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | |
| 11848 | if (item.toValue().toBool()) { | |
| 11807 | 11849 | true_count.* += 1; |
| 11808 | 11850 | } else { |
| 11809 | 11851 | false_count.* += 1; |
| 11810 | 11852 | } |
| 11811 | 11853 | if (true_count.* + false_count.* > 2) { |
| 11812 | const block_src_decl = sema.mod.declPtr(block.src_decl); | |
| 11813 | const src = switch_prong_src.resolve(sema.gpa, block_src_decl, src_node_offset, .none); | |
| 11854 | const block_src_decl = mod.declPtr(block.src_decl); | |
| 11855 | const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); | |
| 11814 | 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 | 11862 | fn validateSwitchItemSparse( |
| 11821 | 11863 | sema: *Sema, |
| ... | ... | @@ -11825,8 +11867,8 @@ fn validateSwitchItemSparse( |
| 11825 | 11867 | src_node_offset: i32, |
| 11826 | 11868 | switch_prong_src: Module.SwitchProngSrc, |
| 11827 | 11869 | ) CompileError!void { |
| 11828 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | |
| 11829 | const kv = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return; | |
| 11870 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | |
| 11871 | const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return; | |
| 11830 | 11872 | return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); |
| 11831 | 11873 | } |
| 11832 | 11874 | |
| ... | ... | @@ -11864,7 +11906,8 @@ fn validateSwitchNoRange( |
| 11864 | 11906 | } |
| 11865 | 11907 | |
| 11866 | 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 | 11912 | const tags = sema.code.instructions.items(.tag); |
| 11870 | 11913 | for (body) |inst| { |
| ... | ... | @@ -11900,7 +11943,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op |
| 11900 | 11943 | .as_node => try sema.zirAsNode(block, inst), |
| 11901 | 11944 | .field_val => try sema.zirFieldVal(block, inst), |
| 11902 | 11945 | .@"unreachable" => { |
| 11903 | if (!sema.mod.comp.formatted_panics) { | |
| 11946 | if (!mod.comp.formatted_panics) { | |
| 11904 | 11947 | try sema.safetyPanic(block, .unwrap_error); |
| 11905 | 11948 | return true; |
| 11906 | 11949 | } |
| ... | ... | @@ -11923,7 +11966,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op |
| 11923 | 11966 | }, |
| 11924 | 11967 | else => unreachable, |
| 11925 | 11968 | }; |
| 11926 | if (sema.typeOf(air_inst).isNoReturn()) | |
| 11969 | if (sema.typeOf(air_inst).isNoReturn(mod)) | |
| 11927 | 11970 | return true; |
| 11928 | 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 | 11974 | } |
| 11932 | 11975 | |
| 11933 | 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 | 11978 | const index = Zir.refToIndex(cond) orelse return; |
| 11935 | 11979 | if (sema.code.instructions.items(.tag)[index] != .is_non_err) return; |
| 11936 | 11980 | |
| 11937 | 11981 | const err_inst_data = sema.code.instructions.items(.data)[index].un_node; |
| 11938 | 11982 | const err_operand = try sema.resolveInst(err_inst_data.operand); |
| 11939 | 11983 | const operand_ty = sema.typeOf(err_operand); |
| 11940 | if (operand_ty.zigTypeTag() == .ErrorSet) { | |
| 11984 | if (operand_ty.zigTypeTag(mod) == .ErrorSet) { | |
| 11941 | 11985 | try sema.maybeErrorUnwrapComptime(block, body, err_operand); |
| 11942 | 11986 | return; |
| 11943 | 11987 | } |
| 11944 | 11988 | if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| { |
| 11945 | if (!operand_ty.isError()) return; | |
| 11946 | if (val.getError() == null) return; | |
| 11989 | if (!operand_ty.isError(mod)) return; | |
| 11990 | if (val.getErrorName(mod) == .none) return; | |
| 11947 | 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 | 12009 | const src = inst_data.src(); |
| 11966 | 12010 | |
| 11967 | 12011 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 11968 | if (val.getError()) |name| { | |
| 11969 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); | |
| 12012 | if (val.getErrorName(sema.mod).unwrap()) |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 | 12018 | fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12019 | const mod = sema.mod; | |
| 11975 | 12020 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 11976 | 12021 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 11977 | 12022 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 11978 | 12023 | const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 11979 | 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 | 12026 | const ty = try sema.resolveTypeFields(unresolved_ty); |
| 12027 | const ip = &mod.intern_pool; | |
| 11982 | 12028 | |
| 11983 | 12029 | const has_field = hf: { |
| 11984 | if (ty.isSlice()) { | |
| 11985 | if (mem.eql(u8, field_name, "ptr")) break :hf true; | |
| 11986 | if (mem.eql(u8, field_name, "len")) break :hf true; | |
| 11987 | break :hf false; | |
| 11988 | } | |
| 11989 | if (ty.castTag(.anon_struct)) |pl| { | |
| 11990 | break :hf for (pl.data.names) |name| { | |
| 11991 | if (mem.eql(u8, name, field_name)) break true; | |
| 11992 | } else false; | |
| 11993 | } | |
| 11994 | if (ty.isTuple()) { | |
| 11995 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; | |
| 11996 | break :hf field_index < ty.structFieldCount(); | |
| 11997 | } | |
| 11998 | break :hf switch (ty.zigTypeTag()) { | |
| 11999 | .Struct => ty.structFields().contains(field_name), | |
| 12000 | .Union => ty.unionFields().contains(field_name), | |
| 12001 | .Enum => ty.enumFields().contains(field_name), | |
| 12002 | .Array => mem.eql(u8, field_name, "len"), | |
| 12003 | else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ | |
| 12004 | ty.fmt(sema.mod), | |
| 12005 | }), | |
| 12006 | }; | |
| 12030 | switch (ip.indexToKey(ty.toIntern())) { | |
| 12031 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 12032 | .Slice => { | |
| 12033 | if (ip.stringEqlSlice(field_name, "ptr")) break :hf true; | |
| 12034 | if (ip.stringEqlSlice(field_name, "len")) break :hf true; | |
| 12035 | break :hf false; | |
| 12036 | }, | |
| 12037 | else => {}, | |
| 12038 | }, | |
| 12039 | .anon_struct_type => |anon_struct| { | |
| 12040 | if (anon_struct.names.len != 0) { | |
| 12041 | break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, field_name) != null; | |
| 12042 | } else { | |
| 12043 | const field_index = field_name.toUnsigned(ip) orelse break :hf false; | |
| 12044 | break :hf field_index < ty.structFieldCount(mod); | |
| 12045 | } | |
| 12046 | }, | |
| 12047 | .struct_type => |struct_type| { | |
| 12048 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false; | |
| 12049 | assert(struct_obj.haveFieldTypes()); | |
| 12050 | break :hf struct_obj.fields.contains(field_name); | |
| 12051 | }, | |
| 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 | 12067 | if (has_field) { |
| 12009 | 12068 | return Air.Inst.Ref.bool_true; |
| ... | ... | @@ -12013,20 +12072,22 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12013 | 12072 | } |
| 12014 | 12073 | |
| 12015 | 12074 | fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12075 | const mod = sema.mod; | |
| 12016 | 12076 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12017 | 12077 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 12018 | 12078 | const src = inst_data.src(); |
| 12019 | 12079 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 12020 | 12080 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 12021 | 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 | 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 | 12088 | if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { |
| 12028 | const decl = sema.mod.declPtr(decl_index); | |
| 12029 | if (decl.is_pub or decl.getFileScope() == block.getFileScope()) { | |
| 12089 | const decl = mod.declPtr(decl_index); | |
| 12090 | if (decl.is_pub or decl.getFileScope(mod) == block.getFileScope(mod)) { | |
| 12030 | 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 | 12103 | const operand_src = inst_data.src(); |
| 12043 | 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 | 12107 | error.ImportOutsidePkgPath => { |
| 12047 | 12108 | return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand}); |
| 12048 | 12109 | }, |
| 12049 | 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 | 12112 | defer sema.gpa.free(name); |
| 12052 | 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 | 12134 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 12074 | 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 | 12138 | error.ImportOutsidePkgPath => { |
| 12078 | 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 | 12148 | var anon_decl = try block.startAnonDecl(); |
| 12088 | 12149 | defer anon_decl.deinit(); |
| 12089 | 12150 | |
| 12090 | const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1]; | |
| 12091 | ||
| 12092 | // TODO instead of using `Value.Tag.bytes`, create a new value tag for pointing at | |
| 12151 | // TODO instead of using `.bytes`, create a new value tag for pointing at | |
| 12093 | 12152 | // a `*Module.EmbedFile`. The purpose of this would be: |
| 12094 | 12153 | // - If only the length is read and the bytes are not inspected by comptime code, |
| 12095 | 12154 | // there can be an optimization where the codegen backend does a copy_file_range |
| 12096 | 12155 | // into the final binary, and never loads the data into memory. |
| 12097 | 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 | 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), | |
| 12100 | try Value.Tag.bytes.create(anon_decl.arena(), bytes_including_null), | |
| 12163 | ty, | |
| 12164 | (try mod.intern(.{ .aggregate = .{ | |
| 12165 | .ty = ty.toIntern(), | |
| 12166 | .storage = .{ .bytes = embed_file.bytes }, | |
| 12167 | } })).toValue(), | |
| 12101 | 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 | 12172 | } |
| 12106 | 12173 | |
| 12107 | 12174 | fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12175 | const mod = sema.mod; | |
| 12108 | 12176 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 12109 | const err_name = inst_data.get(sema.code); | |
| 12110 | ||
| 12111 | // Return the error code from the function. | |
| 12112 | const kv = try sema.mod.getErrorValue(err_name); | |
| 12113 | const result_inst = try sema.addConstant( | |
| 12114 | try Type.Tag.error_set_single.create(sema.arena, kv.key), | |
| 12115 | try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), | |
| 12116 | ); | |
| 12117 | return result_inst; | |
| 12177 | const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); | |
| 12178 | _ = try mod.getErrorValue(name); | |
| 12179 | const error_set_type = try mod.singleErrorSetType(name); | |
| 12180 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ | |
| 12181 | .ty = error_set_type.toIntern(), | |
| 12182 | .name = name, | |
| 12183 | } })).toValue()); | |
| 12118 | 12184 | } |
| 12119 | 12185 | |
| 12120 | 12186 | fn zirShl( |
| ... | ... | @@ -12126,6 +12192,7 @@ fn zirShl( |
| 12126 | 12192 | const tracy = trace(@src()); |
| 12127 | 12193 | defer tracy.end(); |
| 12128 | 12194 | |
| 12195 | const mod = sema.mod; | |
| 12129 | 12196 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12130 | 12197 | const src = inst_data.src(); |
| 12131 | 12198 | sema.src = src; |
| ... | ... | @@ -12136,11 +12203,10 @@ fn zirShl( |
| 12136 | 12203 | const rhs = try sema.resolveInst(extra.rhs); |
| 12137 | 12204 | const lhs_ty = sema.typeOf(lhs); |
| 12138 | 12205 | const rhs_ty = sema.typeOf(rhs); |
| 12139 | const target = sema.mod.getTarget(); | |
| 12140 | 12206 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 12141 | 12207 | |
| 12142 | const scalar_ty = lhs_ty.scalarType(); | |
| 12143 | const scalar_rhs_ty = rhs_ty.scalarType(); | |
| 12208 | const scalar_ty = lhs_ty.scalarType(mod); | |
| 12209 | const scalar_rhs_ty = rhs_ty.scalarType(mod); | |
| 12144 | 12210 | |
| 12145 | 12211 | // TODO coerce rhs if air_tag is not shl_sat |
| 12146 | 12212 | const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty); |
| ... | ... | @@ -12149,62 +12215,56 @@ fn zirShl( |
| 12149 | 12215 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs); |
| 12150 | 12216 | |
| 12151 | 12217 | if (maybe_rhs_val) |rhs_val| { |
| 12152 | if (rhs_val.isUndef()) { | |
| 12218 | if (rhs_val.isUndef(mod)) { | |
| 12153 | 12219 | return sema.addConstUndef(sema.typeOf(lhs)); |
| 12154 | 12220 | } |
| 12155 | 12221 | // If rhs is 0, return lhs without doing any calculations. |
| 12156 | 12222 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 12157 | 12223 | return lhs; |
| 12158 | 12224 | } |
| 12159 | if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) { | |
| 12160 | var bits_payload = Value.Payload.U64{ | |
| 12161 | .base = .{ .tag = .int_u64 }, | |
| 12162 | .data = scalar_ty.intInfo(target).bits, | |
| 12163 | }; | |
| 12164 | const bit_value = Value.initPayload(&bits_payload.base); | |
| 12165 | if (rhs_ty.zigTypeTag() == .Vector) { | |
| 12225 | if (scalar_ty.zigTypeTag(mod) != .ComptimeInt and air_tag != .shl_sat) { | |
| 12226 | const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits); | |
| 12227 | if (rhs_ty.zigTypeTag(mod) == .Vector) { | |
| 12166 | 12228 | var i: usize = 0; |
| 12167 | while (i < rhs_ty.vectorLen()) : (i += 1) { | |
| 12168 | var elem_value_buf: Value.ElemValueBuffer = undefined; | |
| 12169 | const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf); | |
| 12170 | if (rhs_elem.compareHetero(.gte, bit_value, target)) { | |
| 12229 | while (i < rhs_ty.vectorLen(mod)) : (i += 1) { | |
| 12230 | const rhs_elem = try rhs_val.elemValue(mod, i); | |
| 12231 | if (rhs_elem.compareHetero(.gte, bit_value, mod)) { | |
| 12171 | 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 | 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 | 12240 | return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ |
| 12180 | rhs_val.fmtValue(scalar_ty, sema.mod), | |
| 12181 | scalar_ty.fmt(sema.mod), | |
| 12241 | rhs_val.fmtValue(scalar_ty, 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 | 12247 | var i: usize = 0; |
| 12187 | while (i < rhs_ty.vectorLen()) : (i += 1) { | |
| 12188 | var elem_value_buf: Value.ElemValueBuffer = undefined; | |
| 12189 | const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf); | |
| 12190 | if (rhs_elem.compareHetero(.lt, Value.zero, target)) { | |
| 12248 | while (i < rhs_ty.vectorLen(mod)) : (i += 1) { | |
| 12249 | const rhs_elem = try rhs_val.elemValue(mod, i); | |
| 12250 | if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) { | |
| 12191 | 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 | 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 | 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 | 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 | 12266 | const rhs_val = maybe_rhs_val orelse { |
| 12207 | if (scalar_ty.zigTypeTag() == .ComptimeInt) { | |
| 12267 | if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) { | |
| 12208 | 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 | 12270 | break :rs rhs_src; |
| ... | ... | @@ -12212,25 +12272,25 @@ fn zirShl( |
| 12212 | 12272 | |
| 12213 | 12273 | const val = switch (air_tag) { |
| 12214 | 12274 | .shl_exact => val: { |
| 12215 | const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, sema.mod); | |
| 12216 | if (scalar_ty.zigTypeTag() == .ComptimeInt) { | |
| 12275 | const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, mod); | |
| 12276 | if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) { | |
| 12217 | 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 | 12280 | break :val shifted.wrapped_result; |
| 12221 | 12281 | } |
| 12222 | 12282 | return sema.fail(block, src, "operation caused overflow", .{}); |
| 12223 | 12283 | }, |
| 12224 | 12284 | |
| 12225 | .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt) | |
| 12226 | try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod) | |
| 12285 | .shl_sat => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) | |
| 12286 | try lhs_val.shl(rhs_val, lhs_ty, sema.arena, mod) | |
| 12227 | 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) | |
| 12231 | try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod) | |
| 12290 | .shl => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) | |
| 12291 | try lhs_val.shl(rhs_val, lhs_ty, sema.arena, mod) | |
| 12232 | 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 | 12295 | else => unreachable, |
| 12236 | 12296 | }; |
| ... | ... | @@ -12241,11 +12301,11 @@ fn zirShl( |
| 12241 | 12301 | const new_rhs = if (air_tag == .shl_sat) rhs: { |
| 12242 | 12302 | // Limit the RHS type for saturating shl to be an integer as small as the LHS. |
| 12243 | 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 | 12306 | const max_int = try sema.addConstant( |
| 12247 | 12307 | lhs_ty, |
| 12248 | try lhs_ty.maxInt(sema.arena, target), | |
| 12308 | try lhs_ty.maxInt(mod, lhs_ty), | |
| 12249 | 12309 | ); |
| 12250 | 12310 | const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src }); |
| 12251 | 12311 | break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false); |
| ... | ... | @@ -12256,12 +12316,11 @@ fn zirShl( |
| 12256 | 12316 | |
| 12257 | 12317 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 12258 | 12318 | if (block.wantSafety()) { |
| 12259 | const bit_count = scalar_ty.intInfo(target).bits; | |
| 12319 | const bit_count = scalar_ty.intInfo(mod).bits; | |
| 12260 | 12320 | if (!std.math.isPowerOfTwo(bit_count)) { |
| 12261 | const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); | |
| 12262 | ||
| 12263 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { | |
| 12264 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); | |
| 12321 | const bit_count_val = try mod.intValue(scalar_rhs_ty, bit_count); | |
| 12322 | const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { | |
| 12323 | const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val)); | |
| 12265 | 12324 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); |
| 12266 | 12325 | break :ok try block.addInst(.{ |
| 12267 | 12326 | .tag = .reduce, |
| ... | ... | @@ -12290,7 +12349,7 @@ fn zirShl( |
| 12290 | 12349 | } }, |
| 12291 | 12350 | }); |
| 12292 | 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 | 12353 | try block.addInst(.{ |
| 12295 | 12354 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| 12296 | 12355 | .data = .{ .reduce = .{ |
| ... | ... | @@ -12300,7 +12359,7 @@ fn zirShl( |
| 12300 | 12359 | }) |
| 12301 | 12360 | else |
| 12302 | 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 | 12363 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); |
| 12305 | 12364 | |
| 12306 | 12365 | try sema.addSafetyCheck(block, no_ov, .shl_overflow); |
| ... | ... | @@ -12319,6 +12378,7 @@ fn zirShr( |
| 12319 | 12378 | const tracy = trace(@src()); |
| 12320 | 12379 | defer tracy.end(); |
| 12321 | 12380 | |
| 12381 | const mod = sema.mod; | |
| 12322 | 12382 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12323 | 12383 | const src = inst_data.src(); |
| 12324 | 12384 | sema.src = src; |
| ... | ... | @@ -12330,94 +12390,87 @@ fn zirShr( |
| 12330 | 12390 | const lhs_ty = sema.typeOf(lhs); |
| 12331 | 12391 | const rhs_ty = sema.typeOf(rhs); |
| 12332 | 12392 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 12333 | const target = sema.mod.getTarget(); | |
| 12334 | const scalar_ty = lhs_ty.scalarType(); | |
| 12393 | const scalar_ty = lhs_ty.scalarType(mod); | |
| 12335 | 12394 | |
| 12336 | 12395 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(lhs); |
| 12337 | 12396 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs); |
| 12338 | 12397 | |
| 12339 | 12398 | const runtime_src = if (maybe_rhs_val) |rhs_val| rs: { |
| 12340 | if (rhs_val.isUndef()) { | |
| 12399 | if (rhs_val.isUndef(mod)) { | |
| 12341 | 12400 | return sema.addConstUndef(lhs_ty); |
| 12342 | 12401 | } |
| 12343 | 12402 | // If rhs is 0, return lhs without doing any calculations. |
| 12344 | 12403 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 12345 | 12404 | return lhs; |
| 12346 | 12405 | } |
| 12347 | if (scalar_ty.zigTypeTag() != .ComptimeInt) { | |
| 12348 | var bits_payload = Value.Payload.U64{ | |
| 12349 | .base = .{ .tag = .int_u64 }, | |
| 12350 | .data = scalar_ty.intInfo(target).bits, | |
| 12351 | }; | |
| 12352 | const bit_value = Value.initPayload(&bits_payload.base); | |
| 12353 | if (rhs_ty.zigTypeTag() == .Vector) { | |
| 12406 | if (scalar_ty.zigTypeTag(mod) != .ComptimeInt) { | |
| 12407 | const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits); | |
| 12408 | if (rhs_ty.zigTypeTag(mod) == .Vector) { | |
| 12354 | 12409 | var i: usize = 0; |
| 12355 | while (i < rhs_ty.vectorLen()) : (i += 1) { | |
| 12356 | var elem_value_buf: Value.ElemValueBuffer = undefined; | |
| 12357 | const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf); | |
| 12358 | if (rhs_elem.compareHetero(.gte, bit_value, target)) { | |
| 12410 | while (i < rhs_ty.vectorLen(mod)) : (i += 1) { | |
| 12411 | const rhs_elem = try rhs_val.elemValue(mod, i); | |
| 12412 | if (rhs_elem.compareHetero(.gte, bit_value, mod)) { | |
| 12359 | 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 | 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 | 12421 | return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ |
| 12368 | rhs_val.fmtValue(scalar_ty, sema.mod), | |
| 12369 | scalar_ty.fmt(sema.mod), | |
| 12422 | rhs_val.fmtValue(scalar_ty, 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 | 12428 | var i: usize = 0; |
| 12375 | while (i < rhs_ty.vectorLen()) : (i += 1) { | |
| 12376 | var elem_value_buf: Value.ElemValueBuffer = undefined; | |
| 12377 | const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf); | |
| 12378 | if (rhs_elem.compareHetero(.lt, Value.zero, target)) { | |
| 12429 | while (i < rhs_ty.vectorLen(mod)) : (i += 1) { | |
| 12430 | const rhs_elem = try rhs_val.elemValue(mod, i); | |
| 12431 | if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) { | |
| 12379 | 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 | 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 | 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 | 12443 | if (maybe_lhs_val) |lhs_val| { |
| 12391 | if (lhs_val.isUndef()) { | |
| 12444 | if (lhs_val.isUndef(mod)) { | |
| 12392 | 12445 | return sema.addConstUndef(lhs_ty); |
| 12393 | 12446 | } |
| 12394 | 12447 | if (air_tag == .shr_exact) { |
| 12395 | 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 | 12450 | if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema))) { |
| 12398 | 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 | 12455 | return sema.addConstant(lhs_ty, val); |
| 12403 | 12456 | } else { |
| 12404 | 12457 | break :rs lhs_src; |
| 12405 | 12458 | } |
| 12406 | 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 | 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 | 12465 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 12413 | 12466 | const result = try block.addBinOp(air_tag, lhs, rhs); |
| 12414 | 12467 | if (block.wantSafety()) { |
| 12415 | const bit_count = scalar_ty.intInfo(target).bits; | |
| 12468 | const bit_count = scalar_ty.intInfo(mod).bits; | |
| 12416 | 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: { | |
| 12420 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); | |
| 12472 | const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { | |
| 12473 | const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val)); | |
| 12421 | 12474 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); |
| 12422 | 12475 | break :ok try block.addInst(.{ |
| 12423 | 12476 | .tag = .reduce, |
| ... | ... | @@ -12436,7 +12489,7 @@ fn zirShr( |
| 12436 | 12489 | if (air_tag == .shr_exact) { |
| 12437 | 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 | 12493 | const eql = try block.addCmpVector(lhs, back, .eq); |
| 12441 | 12494 | break :ok try block.addInst(.{ |
| 12442 | 12495 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| ... | ... | @@ -12461,6 +12514,7 @@ fn zirBitwise( |
| 12461 | 12514 | const tracy = trace(@src()); |
| 12462 | 12515 | defer tracy.end(); |
| 12463 | 12516 | |
| 12517 | const mod = sema.mod; | |
| 12464 | 12518 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12465 | 12519 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 12466 | 12520 | sema.src = src; |
| ... | ... | @@ -12475,8 +12529,8 @@ fn zirBitwise( |
| 12475 | 12529 | |
| 12476 | 12530 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 12477 | 12531 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); |
| 12478 | const scalar_type = resolved_type.scalarType(); | |
| 12479 | const scalar_tag = scalar_type.zigTypeTag(); | |
| 12532 | const scalar_type = resolved_type.scalarType(mod); | |
| 12533 | const scalar_tag = scalar_type.zigTypeTag(mod); | |
| 12480 | 12534 | |
| 12481 | 12535 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 12482 | 12536 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| ... | ... | @@ -12484,7 +12538,7 @@ fn zirBitwise( |
| 12484 | 12538 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 12485 | 12539 | |
| 12486 | 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 | 12544 | const runtime_src = runtime: { |
| ... | ... | @@ -12493,9 +12547,9 @@ fn zirBitwise( |
| 12493 | 12547 | if (try sema.resolveMaybeUndefValIntable(casted_lhs)) |lhs_val| { |
| 12494 | 12548 | if (try sema.resolveMaybeUndefValIntable(casted_rhs)) |rhs_val| { |
| 12495 | 12549 | const result_val = switch (air_tag) { |
| 12496 | .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, sema.mod), | |
| 12497 | .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, sema.mod), | |
| 12498 | .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, sema.mod), | |
| 12550 | .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, mod), | |
| 12551 | .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, mod), | |
| 12552 | .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, mod), | |
| 12499 | 12553 | else => unreachable, |
| 12500 | 12554 | }; |
| 12501 | 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 | 12569 | const tracy = trace(@src()); |
| 12516 | 12570 | defer tracy.end(); |
| 12517 | 12571 | |
| 12572 | const mod = sema.mod; | |
| 12518 | 12573 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 12519 | 12574 | const src = inst_data.src(); |
| 12520 | 12575 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; |
| 12521 | 12576 | |
| 12522 | 12577 | const operand = try sema.resolveInst(inst_data.operand); |
| 12523 | 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 | 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 | 12587 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 12533 | if (val.isUndef()) { | |
| 12588 | if (val.isUndef(mod)) { | |
| 12534 | 12589 | return sema.addConstUndef(operand_type); |
| 12535 | } else if (operand_type.zigTypeTag() == .Vector) { | |
| 12536 | const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen()); | |
| 12537 | var elem_val_buf: Value.ElemValueBuffer = undefined; | |
| 12538 | const elems = try sema.arena.alloc(Value, vec_len); | |
| 12590 | } else if (operand_type.zigTypeTag(mod) == .Vector) { | |
| 12591 | const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen(mod)); | |
| 12592 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 12539 | 12593 | for (elems, 0..) |*elem, i| { |
| 12540 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_val_buf); | |
| 12541 | elem.* = try elem_val.bitwiseNot(scalar_type, sema.arena, sema.mod); | |
| 12594 | const elem_val = try val.elemValue(mod, i); | |
| 12595 | elem.* = try (try elem_val.bitwiseNot(scalar_type, sema.arena, mod)).intern(scalar_type, mod); | |
| 12542 | 12596 | } |
| 12543 | return sema.addConstant( | |
| 12544 | operand_type, | |
| 12545 | try Value.Tag.aggregate.create(sema.arena, elems), | |
| 12546 | ); | |
| 12597 | return sema.addConstant(operand_type, (try mod.intern(.{ .aggregate = .{ | |
| 12598 | .ty = operand_type.toIntern(), | |
| 12599 | .storage = .{ .elems = elems }, | |
| 12600 | } })).toValue()); | |
| 12547 | 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 | 12603 | return sema.addConstant(operand_type, result_val); |
| 12550 | 12604 | } |
| 12551 | 12605 | } |
| ... | ... | @@ -12561,18 +12615,19 @@ fn analyzeTupleCat( |
| 12561 | 12615 | lhs: Air.Inst.Ref, |
| 12562 | 12616 | rhs: Air.Inst.Ref, |
| 12563 | 12617 | ) CompileError!Air.Inst.Ref { |
| 12618 | const mod = sema.mod; | |
| 12564 | 12619 | const lhs_ty = sema.typeOf(lhs); |
| 12565 | 12620 | const rhs_ty = sema.typeOf(rhs); |
| 12566 | 12621 | const src = LazySrcLoc.nodeOffset(src_node); |
| 12567 | 12622 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; |
| 12568 | 12623 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; |
| 12569 | 12624 | |
| 12570 | const lhs_len = lhs_ty.structFieldCount(); | |
| 12571 | const rhs_len = rhs_ty.structFieldCount(); | |
| 12625 | const lhs_len = lhs_ty.structFieldCount(mod); | |
| 12626 | const rhs_len = rhs_ty.structFieldCount(mod); | |
| 12572 | 12627 | const dest_fields = lhs_len + rhs_len; |
| 12573 | 12628 | |
| 12574 | 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 | 12632 | if (lhs_len == 0) { |
| 12578 | 12633 | return rhs; |
| ... | ... | @@ -12582,42 +12637,48 @@ fn analyzeTupleCat( |
| 12582 | 12637 | } |
| 12583 | 12638 | const final_len = try sema.usizeCast(block, rhs_src, dest_fields); |
| 12584 | 12639 | |
| 12585 | const types = try sema.arena.alloc(Type, final_len); | |
| 12586 | const values = try sema.arena.alloc(Value, final_len); | |
| 12640 | const types = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12641 | const values = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12587 | 12642 | |
| 12588 | 12643 | const opt_runtime_src = rs: { |
| 12589 | 12644 | var runtime_src: ?LazySrcLoc = null; |
| 12590 | 12645 | var i: u32 = 0; |
| 12591 | 12646 | while (i < lhs_len) : (i += 1) { |
| 12592 | types[i] = lhs_ty.structFieldType(i); | |
| 12593 | const default_val = lhs_ty.structFieldDefaultValue(i); | |
| 12594 | values[i] = default_val; | |
| 12647 | types[i] = lhs_ty.structFieldType(i, mod).toIntern(); | |
| 12648 | const default_val = lhs_ty.structFieldDefaultValue(i, mod); | |
| 12649 | values[i] = default_val.toIntern(); | |
| 12595 | 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 | 12652 | runtime_src = operand_src; |
| 12653 | values[i] = .none; | |
| 12598 | 12654 | } |
| 12599 | 12655 | } |
| 12600 | 12656 | i = 0; |
| 12601 | 12657 | while (i < rhs_len) : (i += 1) { |
| 12602 | types[i + lhs_len] = rhs_ty.structFieldType(i); | |
| 12603 | const default_val = rhs_ty.structFieldDefaultValue(i); | |
| 12604 | values[i + lhs_len] = default_val; | |
| 12658 | types[i + lhs_len] = rhs_ty.structFieldType(i, mod).toIntern(); | |
| 12659 | const default_val = rhs_ty.structFieldDefaultValue(i, mod); | |
| 12660 | values[i + lhs_len] = default_val.toIntern(); | |
| 12605 | 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 | 12663 | runtime_src = operand_src; |
| 12664 | values[i + lhs_len] = .none; | |
| 12608 | 12665 | } |
| 12609 | 12666 | } |
| 12610 | 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 | 12671 | .types = types, |
| 12615 | 12672 | .values = values, |
| 12616 | }); | |
| 12673 | .names = &.{}, | |
| 12674 | } }); | |
| 12617 | 12675 | |
| 12618 | 12676 | const runtime_src = opt_runtime_src orelse { |
| 12619 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 12620 | return sema.addConstant(tuple_ty, tuple_val); | |
| 12677 | const tuple_val = try mod.intern(.{ .aggregate = .{ | |
| 12678 | .ty = tuple_ty, | |
| 12679 | .storage = .{ .elems = values }, | |
| 12680 | } }); | |
| 12681 | return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); | |
| 12621 | 12682 | }; |
| 12622 | 12683 | |
| 12623 | 12684 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | ... | @@ -12635,13 +12696,14 @@ fn analyzeTupleCat( |
| 12635 | 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 | 12702 | fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12642 | 12703 | const tracy = trace(@src()); |
| 12643 | 12704 | defer tracy.end(); |
| 12644 | 12705 | |
| 12706 | const mod = sema.mod; | |
| 12645 | 12707 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12646 | 12708 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 12647 | 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 | 12712 | const rhs_ty = sema.typeOf(rhs); |
| 12651 | 12713 | const src = inst_data.src(); |
| 12652 | 12714 | |
| 12653 | const lhs_is_tuple = lhs_ty.isTuple(); | |
| 12654 | const rhs_is_tuple = rhs_ty.isTuple(); | |
| 12715 | const lhs_is_tuple = lhs_ty.isTuple(mod); | |
| 12716 | const rhs_is_tuple = rhs_ty.isTuple(mod); | |
| 12655 | 12717 | if (lhs_is_tuple and rhs_is_tuple) { |
| 12656 | 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 | 12723 | |
| 12662 | 12724 | const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: { |
| 12663 | 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 | 12728 | const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse { |
| 12667 | 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 | 12733 | const resolved_elem_ty = t: { |
| ... | ... | @@ -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 | 12793 | const ptr_addrspace = p: { |
| 12732 | if (lhs_ty.zigTypeTag() == .Pointer) break :p lhs_ty.ptrAddressSpace(); | |
| 12733 | if (rhs_ty.zigTypeTag() == .Pointer) break :p rhs_ty.ptrAddressSpace(); | |
| 12794 | if (lhs_ty.zigTypeTag(mod) == .Pointer) break :p lhs_ty.ptrAddressSpace(mod); | |
| 12795 | if (rhs_ty.zigTypeTag(mod) == .Pointer) break :p rhs_ty.ptrAddressSpace(mod); | |
| 12734 | 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 | 12800 | .Array, .Struct => try sema.resolveMaybeUndefVal(lhs), |
| 12739 | 12801 | .Pointer => try sema.resolveDefinedValue(block, lhs_src, lhs), |
| 12740 | 12802 | else => unreachable, |
| 12741 | 12803 | }) |lhs_val| rs: { |
| 12742 | if (switch (rhs_ty.zigTypeTag()) { | |
| 12804 | if (switch (rhs_ty.zigTypeTag(mod)) { | |
| 12743 | 12805 | .Array, .Struct => try sema.resolveMaybeUndefVal(rhs), |
| 12744 | 12806 | .Pointer => try sema.resolveDefinedValue(block, rhs_src, rhs), |
| 12745 | 12807 | else => unreachable, |
| 12746 | 12808 | }) |rhs_val| { |
| 12747 | const lhs_sub_val = if (lhs_ty.isSinglePointer()) | |
| 12809 | const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) | |
| 12748 | 12810 | (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? |
| 12749 | 12811 | else |
| 12750 | 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 | 12815 | (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? |
| 12754 | 12816 | else |
| 12755 | 12817 | rhs_val; |
| 12756 | 12818 | |
| 12757 | const final_len_including_sent = result_len + @boolToInt(res_sent_val != null); | |
| 12758 | const element_vals = try sema.arena.alloc(Value, final_len_including_sent); | |
| 12819 | const element_vals = try sema.arena.alloc(InternPool.Index, result_len); | |
| 12759 | 12820 | var elem_i: usize = 0; |
| 12760 | 12821 | while (elem_i < lhs_len) : (elem_i += 1) { |
| 12761 | 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; | |
| 12763 | const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i) else Value.initTag(.unreachable_value); | |
| 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; | |
| 12823 | const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i, mod) else lhs_info.elem_type; | |
| 12824 | const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, mod) else Value.@"unreachable"; | |
| 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 | 12826 | const elem_val_inst = try sema.addConstant(elem_ty, elem_val); |
| 12766 | 12827 | const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); |
| 12767 | 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 | 12831 | while (elem_i < result_len) : (elem_i += 1) { |
| 12771 | 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; | |
| 12773 | const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i) else Value.initTag(.unreachable_value); | |
| 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; | |
| 12833 | const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i, mod) else rhs_info.elem_type; | |
| 12834 | const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, mod) else Value.@"unreachable"; | |
| 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 | 12836 | const elem_val_inst = try sema.addConstant(elem_ty, elem_val); |
| 12776 | 12837 | const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); |
| 12777 | 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| { | |
| 12781 | element_vals[result_len] = sent_val; | |
| 12782 | } | |
| 12783 | const val = try Value.Tag.aggregate.create(sema.arena, element_vals); | |
| 12784 | return sema.addConstantMaybeRef(block, result_ty, val, ptr_addrspace != null); | |
| 12841 | return sema.addConstantMaybeRef(block, result_ty, (try mod.intern(.{ .aggregate = .{ | |
| 12842 | .ty = result_ty.toIntern(), | |
| 12843 | .storage = .{ .elems = element_vals }, | |
| 12844 | } })).toValue(), ptr_addrspace != null); | |
| 12785 | 12845 | } else break :rs rhs_src; |
| 12786 | 12846 | } else lhs_src; |
| 12787 | 12847 | |
| 12788 | 12848 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 12789 | 12849 | |
| 12790 | 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 | 12852 | .pointee_type = result_ty, |
| 12793 | 12853 | .@"addrspace" = ptr_as, |
| 12794 | 12854 | }); |
| 12795 | 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 | 12857 | .pointee_type = resolved_elem_ty, |
| 12798 | 12858 | .@"addrspace" = ptr_as, |
| 12799 | 12859 | }); |
| ... | ... | @@ -12815,7 +12875,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12815 | 12875 | if (res_sent_val) |sent_val| { |
| 12816 | 12876 | const elem_index = try sema.addIntUnsigned(Type.usize, result_len); |
| 12817 | 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 | 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 | 12901 | } |
| 12842 | 12902 | |
| 12843 | 12903 | fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref, peer_ty: Type) !?Type.ArrayInfo { |
| 12904 | const mod = sema.mod; | |
| 12844 | 12905 | const operand_ty = sema.typeOf(operand); |
| 12845 | switch (operand_ty.zigTypeTag()) { | |
| 12846 | .Array => return operand_ty.arrayInfo(), | |
| 12906 | switch (operand_ty.zigTypeTag(mod)) { | |
| 12907 | .Array => return operand_ty.arrayInfo(mod), | |
| 12847 | 12908 | .Pointer => { |
| 12848 | const ptr_info = operand_ty.ptrInfo().data; | |
| 12909 | const ptr_info = operand_ty.ptrInfo(mod); | |
| 12849 | 12910 | switch (ptr_info.size) { |
| 12850 | 12911 | // TODO: in the Many case here this should only work if the type |
| 12851 | 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 | 12916 | return Type.ArrayInfo{ |
| 12856 | 12917 | .elem_type = ptr_info.pointee_type, |
| 12857 | 12918 | .sentinel = ptr_info.sentinel, |
| 12858 | .len = val.sliceLen(sema.mod), | |
| 12919 | .len = val.sliceLen(mod), | |
| 12859 | 12920 | }; |
| 12860 | 12921 | }, |
| 12861 | 12922 | .One => { |
| 12862 | if (ptr_info.pointee_type.zigTypeTag() == .Array) { | |
| 12863 | return ptr_info.pointee_type.arrayInfo(); | |
| 12923 | if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) { | |
| 12924 | return ptr_info.pointee_type.arrayInfo(mod); | |
| 12864 | 12925 | } |
| 12865 | 12926 | }, |
| 12866 | 12927 | .C => {}, |
| 12867 | 12928 | } |
| 12868 | 12929 | }, |
| 12869 | 12930 | .Struct => { |
| 12870 | if (operand_ty.isTuple() and peer_ty.isIndexable()) { | |
| 12871 | assert(!peer_ty.isTuple()); | |
| 12931 | if (operand_ty.isTuple(mod) and peer_ty.isIndexable(mod)) { | |
| 12932 | assert(!peer_ty.isTuple(mod)); | |
| 12872 | 12933 | return .{ |
| 12873 | .elem_type = peer_ty.elemType2(), | |
| 12934 | .elem_type = peer_ty.elemType2(mod), | |
| 12874 | 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 | 12947 | block: *Block, |
| 12887 | 12948 | src_node: i32, |
| 12888 | 12949 | operand: Air.Inst.Ref, |
| 12889 | factor: u64, | |
| 12950 | factor: usize, | |
| 12890 | 12951 | ) CompileError!Air.Inst.Ref { |
| 12952 | const mod = sema.mod; | |
| 12891 | 12953 | const operand_ty = sema.typeOf(operand); |
| 12892 | 12954 | const src = LazySrcLoc.nodeOffset(src_node); |
| 12893 | 12955 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; |
| 12894 | 12956 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; |
| 12895 | 12957 | |
| 12896 | const tuple_len = operand_ty.structFieldCount(); | |
| 12897 | const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch | |
| 12958 | const tuple_len = operand_ty.structFieldCount(mod); | |
| 12959 | const final_len = std.math.mul(usize, tuple_len, factor) catch | |
| 12898 | 12960 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); |
| 12899 | 12961 | |
| 12900 | if (final_len_u64 == 0) { | |
| 12901 | return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); | |
| 12962 | if (final_len == 0) { | |
| 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); | |
| 12904 | ||
| 12905 | const types = try sema.arena.alloc(Type, final_len); | |
| 12906 | const values = try sema.arena.alloc(Value, final_len); | |
| 12965 | const types = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12966 | const values = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12907 | 12967 | |
| 12908 | 12968 | const opt_runtime_src = rs: { |
| 12909 | 12969 | var runtime_src: ?LazySrcLoc = null; |
| 12910 | var i: u32 = 0; | |
| 12911 | while (i < tuple_len) : (i += 1) { | |
| 12912 | types[i] = operand_ty.structFieldType(i); | |
| 12913 | values[i] = operand_ty.structFieldDefaultValue(i); | |
| 12970 | for (0..tuple_len) |i| { | |
| 12971 | types[i] = operand_ty.structFieldType(i, mod).toIntern(); | |
| 12972 | values[i] = operand_ty.structFieldDefaultValue(i, mod).toIntern(); | |
| 12914 | 12973 | const operand_src = lhs_src; // TODO better source location |
| 12915 | if (values[i].tag() == .unreachable_value) { | |
| 12974 | if (values[i] == .unreachable_value) { | |
| 12916 | 12975 | runtime_src = operand_src; |
| 12976 | values[i] = .none; // TODO don't treat unreachable_value as special | |
| 12917 | 12977 | } |
| 12918 | 12978 | } |
| 12919 | i = 0; | |
| 12920 | while (i < factor) : (i += 1) { | |
| 12921 | mem.copyForwards(Type, types[tuple_len * i ..], types[0..tuple_len]); | |
| 12922 | mem.copyForwards(Value, values[tuple_len * i ..], values[0..tuple_len]); | |
| 12979 | for (0..factor) |i| { | |
| 12980 | mem.copyForwards(InternPool.Index, types[tuple_len * i ..], types[0..tuple_len]); | |
| 12981 | mem.copyForwards(InternPool.Index, values[tuple_len * i ..], values[0..tuple_len]); | |
| 12923 | 12982 | } |
| 12924 | 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 | 12987 | .types = types, |
| 12929 | 12988 | .values = values, |
| 12930 | }); | |
| 12989 | .names = &.{}, | |
| 12990 | } }); | |
| 12931 | 12991 | |
| 12932 | 12992 | const runtime_src = opt_runtime_src orelse { |
| 12933 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 12934 | return sema.addConstant(tuple_ty, tuple_val); | |
| 12993 | const tuple_val = try mod.intern(.{ .aggregate = .{ | |
| 12994 | .ty = tuple_ty, | |
| 12995 | .storage = .{ .elems = values }, | |
| 12996 | } }); | |
| 12997 | return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); | |
| 12935 | 12998 | }; |
| 12936 | 12999 | |
| 12937 | 13000 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | ... | @@ -12947,13 +13010,14 @@ fn analyzeTupleMul( |
| 12947 | 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 | 13016 | fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12954 | 13017 | const tracy = trace(@src()); |
| 12955 | 13018 | defer tracy.end(); |
| 12956 | 13019 | |
| 13020 | const mod = sema.mod; | |
| 12957 | 13021 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12958 | 13022 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 12959 | 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 | 13027 | const operator_src: LazySrcLoc = .{ .node_offset_main_token = inst_data.src_node }; |
| 12964 | 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 | 13031 | // In `**` rhs must be comptime-known, but lhs can be runtime-known |
| 12968 | 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 | 13037 | // Analyze the lhs first, to catch the case that someone tried to do exponentiation |
| 12973 | 13038 | const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse { |
| 12974 | 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 | 13041 | errdefer msg.destroy(sema.gpa); |
| 12977 | switch (lhs_ty.zigTypeTag()) { | |
| 13042 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 12978 | 13043 | .Int, .Float, .ComptimeFloat, .ComptimeInt, .Vector => { |
| 12979 | 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 | 13057 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); |
| 12993 | 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 | 13063 | const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); |
| 12999 | 13064 | |
| 13000 | 13065 | if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { |
| 13001 | const final_len_including_sent = result_len + @boolToInt(lhs_info.sentinel != null); | |
| 13002 | ||
| 13003 | const lhs_sub_val = if (lhs_ty.isSinglePointer()) | |
| 13066 | const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) | |
| 13004 | 13067 | (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? |
| 13005 | 13068 | else |
| 13006 | 13069 | lhs_val; |
| ... | ... | @@ -13008,38 +13071,41 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13008 | 13071 | const val = v: { |
| 13009 | 13072 | // Optimization for the common pattern of a single element repeated N times, such |
| 13010 | 13073 | // as zero-filling a byte array. |
| 13011 | if (lhs_len == 1) { | |
| 13012 | const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0); | |
| 13013 | break :v try Value.Tag.repeated.create(sema.arena, elem_val); | |
| 13074 | if (lhs_len == 1 and lhs_info.sentinel == null) { | |
| 13075 | const elem_val = try lhs_sub_val.elemValue(mod, 0); | |
| 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 | 13083 | var elem_i: usize = 0; |
| 13018 | 13084 | while (elem_i < result_len) { |
| 13019 | 13085 | var lhs_i: usize = 0; |
| 13020 | 13086 | while (lhs_i < lhs_len) : (lhs_i += 1) { |
| 13021 | const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_i); | |
| 13022 | element_vals[elem_i] = elem_val; | |
| 13087 | const elem_val = try lhs_sub_val.elemValue(mod, lhs_i); | |
| 13088 | element_vals[elem_i] = elem_val.toIntern(); | |
| 13023 | 13089 | elem_i += 1; |
| 13024 | 13090 | } |
| 13025 | 13091 | } |
| 13026 | if (lhs_info.sentinel) |sent_val| { | |
| 13027 | element_vals[result_len] = sent_val; | |
| 13028 | } | |
| 13029 | break :v try Value.Tag.aggregate.create(sema.arena, element_vals); | |
| 13092 | break :v try mod.intern(.{ .aggregate = .{ | |
| 13093 | .ty = result_ty.toIntern(), | |
| 13094 | .storage = .{ .elems = 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 | 13100 | try sema.requireRuntimeBlock(block, src, lhs_src); |
| 13035 | 13101 | |
| 13036 | 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 | 13104 | .pointee_type = result_ty, |
| 13039 | 13105 | .@"addrspace" = ptr_as, |
| 13040 | 13106 | }); |
| 13041 | 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 | 13109 | .pointee_type = lhs_info.elem_type, |
| 13044 | 13110 | .@"addrspace" = ptr_as, |
| 13045 | 13111 | }); |
| ... | ... | @@ -13082,6 +13148,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13082 | 13148 | } |
| 13083 | 13149 | |
| 13084 | 13150 | fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13151 | const mod = sema.mod; | |
| 13085 | 13152 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 13086 | 13153 | const src = inst_data.src(); |
| 13087 | 13154 | const lhs_src = src; |
| ... | ... | @@ -13089,34 +13156,31 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13089 | 13156 | |
| 13090 | 13157 | const rhs = try sema.resolveInst(inst_data.operand); |
| 13091 | 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 | 13162 | .Int, .ComptimeInt, .Float, .ComptimeFloat => false, |
| 13096 | 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 | 13168 | if (rhs_scalar_ty.isAnyFloat()) { |
| 13102 | 13169 | // We handle float negation here to ensure negative zero is represented in the bits. |
| 13103 | 13170 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { |
| 13104 | if (rhs_val.isUndef()) return sema.addConstUndef(rhs_ty); | |
| 13105 | return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, sema.mod)); | |
| 13171 | if (rhs_val.isUndef(mod)) return sema.addConstUndef(rhs_ty); | |
| 13172 | return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, mod)); | |
| 13106 | 13173 | } |
| 13107 | 13174 | try sema.requireRuntimeBlock(block, src, null); |
| 13108 | 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) | |
| 13112 | try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero)) | |
| 13113 | else | |
| 13114 | try sema.resolveInst(.zero); | |
| 13115 | ||
| 13178 | const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0))); | |
| 13116 | 13179 | return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true); |
| 13117 | 13180 | } |
| 13118 | 13181 | |
| 13119 | 13182 | fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13183 | const mod = sema.mod; | |
| 13120 | 13184 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 13121 | 13185 | const src = inst_data.src(); |
| 13122 | 13186 | const lhs_src = src; |
| ... | ... | @@ -13124,18 +13188,14 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 13124 | 13188 | |
| 13125 | 13189 | const rhs = try sema.resolveInst(inst_data.operand); |
| 13126 | 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 | 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) | |
| 13135 | try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero)) | |
| 13136 | else | |
| 13137 | try sema.resolveInst(.zero); | |
| 13138 | ||
| 13198 | const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0))); | |
| 13139 | 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 | 13221 | } |
| 13162 | 13222 | |
| 13163 | 13223 | fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13224 | const mod = sema.mod; | |
| 13164 | 13225 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13165 | 13226 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13166 | 13227 | sema.src = src; |
| ... | ... | @@ -13171,8 +13232,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13171 | 13232 | const rhs = try sema.resolveInst(extra.rhs); |
| 13172 | 13233 | const lhs_ty = sema.typeOf(lhs); |
| 13173 | 13234 | const rhs_ty = sema.typeOf(rhs); |
| 13174 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 13175 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 13235 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 13236 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 13176 | 13237 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13177 | 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 | 13242 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13182 | 13243 | }); |
| 13183 | 13244 | |
| 13184 | const is_vector = resolved_type.zigTypeTag() == .Vector; | |
| 13185 | ||
| 13186 | 13245 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13187 | 13246 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13188 | 13247 | |
| 13189 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 13190 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 13191 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 13248 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 13249 | const rhs_scalar_ty = rhs_ty.scalarType(mod); | |
| 13250 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); | |
| 13192 | 13251 | |
| 13193 | 13252 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13194 | 13253 | |
| 13195 | 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 | 13256 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13199 | 13257 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 13200 | 13258 | |
| 13201 | if ((lhs_ty.zigTypeTag() == .ComptimeFloat and rhs_ty.zigTypeTag() == .ComptimeInt) or | |
| 13202 | (lhs_ty.zigTypeTag() == .ComptimeInt and rhs_ty.zigTypeTag() == .ComptimeFloat)) | |
| 13259 | if ((lhs_ty.zigTypeTag(mod) == .ComptimeFloat and rhs_ty.zigTypeTag(mod) == .ComptimeInt) or | |
| 13260 | (lhs_ty.zigTypeTag(mod) == .ComptimeInt and rhs_ty.zigTypeTag(mod) == .ComptimeFloat)) | |
| 13203 | 13261 | { |
| 13204 | 13262 | // If it makes a difference whether we coerce to ints or floats before doing the division, error. |
| 13205 | 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 | 13265 | const rhs_val = maybe_rhs_val orelse unreachable; |
| 13208 | 13266 | const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod) catch unreachable; |
| 13209 | 13267 | if (!rem.compareAllWithZero(.eq, mod)) { |
| 13210 | return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{ | |
| 13211 | @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod), | |
| 13212 | }); | |
| 13268 | return sema.fail( | |
| 13269 | block, | |
| 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 | 13304 | switch (scalar_tag) { |
| 13244 | 13305 | .Int, .ComptimeInt, .ComptimeFloat => { |
| 13245 | 13306 | if (maybe_lhs_val) |lhs_val| { |
| 13246 | if (!lhs_val.isUndef()) { | |
| 13307 | if (!lhs_val.isUndef(mod)) { | |
| 13247 | 13308 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13248 | const zero_val = if (is_vector) b: { | |
| 13249 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 13250 | } else Value.zero; | |
| 13309 | const scalar_zero = switch (scalar_tag) { | |
| 13310 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), | |
| 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 | 13315 | return sema.addConstant(resolved_type, zero_val); |
| 13252 | 13316 | } |
| 13253 | 13317 | } |
| 13254 | 13318 | } |
| 13255 | 13319 | if (maybe_rhs_val) |rhs_val| { |
| 13256 | if (rhs_val.isUndef()) { | |
| 13320 | if (rhs_val.isUndef(mod)) { | |
| 13257 | 13321 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13258 | 13322 | } |
| 13259 | 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 | 13331 | |
| 13268 | 13332 | const runtime_src = rs: { |
| 13269 | 13333 | if (maybe_lhs_val) |lhs_val| { |
| 13270 | if (lhs_val.isUndef()) { | |
| 13271 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 13334 | if (lhs_val.isUndef(mod)) { | |
| 13335 | if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { | |
| 13272 | 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 | 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 | 13345 | |
| 13282 | 13346 | if (maybe_rhs_val) |rhs_val| { |
| 13283 | 13347 | if (is_int) { |
| 13284 | const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod); | |
| 13285 | var vector_index: usize = undefined; | |
| 13286 | if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { | |
| 13287 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); | |
| 13348 | var overflow_idx: ?usize = null; | |
| 13349 | const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod); | |
| 13350 | if (overflow_idx) |vec_idx| { | |
| 13351 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx); | |
| 13288 | 13352 | } |
| 13289 | 13353 | return sema.addConstant(resolved_type, res); |
| 13290 | 13354 | } else { |
| ... | ... | @@ -13309,8 +13373,13 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13309 | 13373 | } |
| 13310 | 13374 | |
| 13311 | 13375 | const air_tag = if (is_int) blk: { |
| 13312 | if (lhs_ty.isSignedInt() or rhs_ty.isSignedInt()) { | |
| 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()) }); | |
| 13376 | if (lhs_ty.isSignedInt(mod) or rhs_ty.isSignedInt(mod)) { | |
| 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 | 13384 | break :blk Air.Inst.Tag.div_trunc; |
| 13316 | 13385 | } else switch (block.float_mode) { |
| ... | ... | @@ -13321,6 +13390,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13321 | 13390 | } |
| 13322 | 13391 | |
| 13323 | 13392 | fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13393 | const mod = sema.mod; | |
| 13324 | 13394 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13325 | 13395 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13326 | 13396 | sema.src = src; |
| ... | ... | @@ -13331,8 +13401,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13331 | 13401 | const rhs = try sema.resolveInst(extra.rhs); |
| 13332 | 13402 | const lhs_ty = sema.typeOf(lhs); |
| 13333 | 13403 | const rhs_ty = sema.typeOf(rhs); |
| 13334 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 13335 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 13404 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 13405 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 13336 | 13406 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13337 | 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 | 13411 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13342 | 13412 | }); |
| 13343 | 13413 | |
| 13344 | const is_vector = resolved_type.zigTypeTag() == .Vector; | |
| 13345 | ||
| 13346 | 13414 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13347 | 13415 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13348 | 13416 | |
| 13349 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 13350 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 13417 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 13418 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); | |
| 13351 | 13419 | |
| 13352 | 13420 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13353 | 13421 | |
| 13354 | 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 | 13424 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13358 | 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 | 13442 | // If the lhs is undefined, compile error because there is a possible |
| 13376 | 13443 | // value for which the division would result in a remainder. |
| 13377 | 13444 | if (maybe_lhs_val) |lhs_val| { |
| 13378 | if (lhs_val.isUndef()) { | |
| 13445 | if (lhs_val.isUndef(mod)) { | |
| 13379 | 13446 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13380 | 13447 | } else { |
| 13381 | 13448 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13382 | const zero_val = if (is_vector) b: { | |
| 13383 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 13384 | } else Value.zero; | |
| 13449 | const scalar_zero = switch (scalar_tag) { | |
| 13450 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), | |
| 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 | 13455 | return sema.addConstant(resolved_type, zero_val); |
| 13386 | 13456 | } |
| 13387 | 13457 | } |
| 13388 | 13458 | } |
| 13389 | 13459 | if (maybe_rhs_val) |rhs_val| { |
| 13390 | if (rhs_val.isUndef()) { | |
| 13460 | if (rhs_val.isUndef(mod)) { | |
| 13391 | 13461 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13392 | 13462 | } |
| 13393 | 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 | 13472 | if (!(modulus_val.compareAllWithZero(.eq, mod))) { |
| 13403 | 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); | |
| 13406 | var vector_index: usize = undefined; | |
| 13407 | if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { | |
| 13408 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); | |
| 13475 | var overflow_idx: ?usize = null; | |
| 13476 | const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod); | |
| 13477 | if (overflow_idx) |vec_idx| { | |
| 13478 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx); | |
| 13409 | 13479 | } |
| 13410 | 13480 | return sema.addConstant(resolved_type, res); |
| 13411 | 13481 | } else { |
| ... | ... | @@ -13437,7 +13507,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13437 | 13507 | const ok = if (!is_int) ok: { |
| 13438 | 13508 | const floored = try block.addUnOp(.floor, result); |
| 13439 | 13509 | |
| 13440 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 13510 | if (resolved_type.zigTypeTag(mod) == .Vector) { | |
| 13441 | 13511 | const eql = try block.addCmpVector(result, floored, .eq); |
| 13442 | 13512 | break :ok try block.addInst(.{ |
| 13443 | 13513 | .tag = switch (block.float_mode) { |
| ... | ... | @@ -13459,8 +13529,13 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13459 | 13529 | } else ok: { |
| 13460 | 13530 | const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs); |
| 13461 | 13531 | |
| 13462 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 13463 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 13532 | const scalar_zero = switch (scalar_tag) { | |
| 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 | 13539 | const zero = try sema.addConstant(resolved_type, zero_val); |
| 13465 | 13540 | const eql = try block.addCmpVector(remainder, zero, .eq); |
| 13466 | 13541 | break :ok try block.addInst(.{ |
| ... | ... | @@ -13471,7 +13546,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13471 | 13546 | } }, |
| 13472 | 13547 | }); |
| 13473 | 13548 | } else { |
| 13474 | const zero = try sema.addConstant(resolved_type, Value.zero); | |
| 13549 | const zero = try sema.addConstant(resolved_type, scalar_zero); | |
| 13475 | 13550 | const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero); |
| 13476 | 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 | 13559 | } |
| 13485 | 13560 | |
| 13486 | 13561 | fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13562 | const mod = sema.mod; | |
| 13487 | 13563 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13488 | 13564 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13489 | 13565 | sema.src = src; |
| ... | ... | @@ -13494,8 +13570,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13494 | 13570 | const rhs = try sema.resolveInst(extra.rhs); |
| 13495 | 13571 | const lhs_ty = sema.typeOf(lhs); |
| 13496 | 13572 | const rhs_ty = sema.typeOf(rhs); |
| 13497 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 13498 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 13573 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 13574 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 13499 | 13575 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13500 | 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 | 13580 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13505 | 13581 | }); |
| 13506 | 13582 | |
| 13507 | const is_vector = resolved_type.zigTypeTag() == .Vector; | |
| 13508 | ||
| 13509 | 13583 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13510 | 13584 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13511 | 13585 | |
| 13512 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 13513 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 13514 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 13586 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 13587 | const rhs_scalar_ty = rhs_ty.scalarType(mod); | |
| 13588 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); | |
| 13515 | 13589 | |
| 13516 | 13590 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13517 | 13591 | |
| 13518 | 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 | 13594 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13522 | 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 | 13615 | // value (zero) for which the division would be illegal behavior. |
| 13543 | 13616 | // If the lhs is undefined, result is undefined. |
| 13544 | 13617 | if (maybe_lhs_val) |lhs_val| { |
| 13545 | if (!lhs_val.isUndef()) { | |
| 13618 | if (!lhs_val.isUndef(mod)) { | |
| 13546 | 13619 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13547 | const zero_val = if (is_vector) b: { | |
| 13548 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 13549 | } else Value.zero; | |
| 13620 | const scalar_zero = switch (scalar_tag) { | |
| 13621 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), | |
| 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 | 13626 | return sema.addConstant(resolved_type, zero_val); |
| 13551 | 13627 | } |
| 13552 | 13628 | } |
| 13553 | 13629 | } |
| 13554 | 13630 | if (maybe_rhs_val) |rhs_val| { |
| 13555 | if (rhs_val.isUndef()) { | |
| 13631 | if (rhs_val.isUndef(mod)) { | |
| 13556 | 13632 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13557 | 13633 | } |
| 13558 | 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 | 13637 | // TODO: if the RHS is one, return the LHS directly |
| 13562 | 13638 | } |
| 13563 | 13639 | if (maybe_lhs_val) |lhs_val| { |
| 13564 | if (lhs_val.isUndef()) { | |
| 13565 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 13640 | if (lhs_val.isUndef(mod)) { | |
| 13641 | if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { | |
| 13566 | 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 | 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 | 13676 | } |
| 13601 | 13677 | |
| 13602 | 13678 | fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13679 | const mod = sema.mod; | |
| 13603 | 13680 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13604 | 13681 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13605 | 13682 | sema.src = src; |
| ... | ... | @@ -13610,8 +13687,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13610 | 13687 | const rhs = try sema.resolveInst(extra.rhs); |
| 13611 | 13688 | const lhs_ty = sema.typeOf(lhs); |
| 13612 | 13689 | const rhs_ty = sema.typeOf(rhs); |
| 13613 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 13614 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 13690 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 13691 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 13615 | 13692 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13616 | 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 | 13697 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13621 | 13698 | }); |
| 13622 | 13699 | |
| 13623 | const is_vector = resolved_type.zigTypeTag() == .Vector; | |
| 13624 | ||
| 13625 | 13700 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13626 | 13701 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13627 | 13702 | |
| 13628 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 13629 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 13630 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 13703 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 13704 | const rhs_scalar_ty = rhs_ty.scalarType(mod); | |
| 13705 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); | |
| 13631 | 13706 | |
| 13632 | 13707 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13633 | 13708 | |
| 13634 | 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 | 13711 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13638 | 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 | 13732 | // value (zero) for which the division would be illegal behavior. |
| 13659 | 13733 | // If the lhs is undefined, result is undefined. |
| 13660 | 13734 | if (maybe_lhs_val) |lhs_val| { |
| 13661 | if (!lhs_val.isUndef()) { | |
| 13735 | if (!lhs_val.isUndef(mod)) { | |
| 13662 | 13736 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13663 | const zero_val = if (is_vector) b: { | |
| 13664 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 13665 | } else Value.zero; | |
| 13737 | const scalar_zero = switch (scalar_tag) { | |
| 13738 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), | |
| 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 | 13743 | return sema.addConstant(resolved_type, zero_val); |
| 13667 | 13744 | } |
| 13668 | 13745 | } |
| 13669 | 13746 | } |
| 13670 | 13747 | if (maybe_rhs_val) |rhs_val| { |
| 13671 | if (rhs_val.isUndef()) { | |
| 13748 | if (rhs_val.isUndef(mod)) { | |
| 13672 | 13749 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13673 | 13750 | } |
| 13674 | 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 | 13753 | } |
| 13677 | 13754 | } |
| 13678 | 13755 | if (maybe_lhs_val) |lhs_val| { |
| 13679 | if (lhs_val.isUndef()) { | |
| 13680 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 13756 | if (lhs_val.isUndef(mod)) { | |
| 13757 | if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { | |
| 13681 | 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 | 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 | 13767 | |
| 13691 | 13768 | if (maybe_rhs_val) |rhs_val| { |
| 13692 | 13769 | if (is_int) { |
| 13693 | const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod); | |
| 13694 | var vector_index: usize = undefined; | |
| 13695 | if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { | |
| 13696 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); | |
| 13770 | var overflow_idx: ?usize = null; | |
| 13771 | const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod); | |
| 13772 | if (overflow_idx) |vec_idx| { | |
| 13773 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx); | |
| 13697 | 13774 | } |
| 13698 | 13775 | return sema.addConstant(resolved_type, res); |
| 13699 | 13776 | } else { |
| ... | ... | @@ -13727,39 +13804,34 @@ fn addDivIntOverflowSafety( |
| 13727 | 13804 | casted_rhs: Air.Inst.Ref, |
| 13728 | 13805 | is_int: bool, |
| 13729 | 13806 | ) CompileError!void { |
| 13807 | const mod = sema.mod; | |
| 13730 | 13808 | if (!is_int) return; |
| 13731 | 13809 | |
| 13732 | 13810 | // If the LHS is unsigned, it cannot cause overflow. |
| 13733 | if (!lhs_scalar_ty.isSignedInt()) return; | |
| 13734 | ||
| 13735 | const mod = sema.mod; | |
| 13736 | const target = mod.getTarget(); | |
| 13811 | if (!lhs_scalar_ty.isSignedInt(mod)) return; | |
| 13737 | 13812 | |
| 13738 | 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 | 13815 | return; |
| 13741 | 13816 | } |
| 13742 | 13817 | |
| 13743 | const min_int = try resolved_type.minInt(sema.arena, target); | |
| 13744 | const neg_one_scalar = try Value.Tag.int_i64.create(sema.arena, -1); | |
| 13745 | const neg_one = if (resolved_type.zigTypeTag() == .Vector) | |
| 13746 | try Value.Tag.repeated.create(sema.arena, neg_one_scalar) | |
| 13747 | else | |
| 13748 | neg_one_scalar; | |
| 13818 | const min_int = try resolved_type.minInt(mod, resolved_type); | |
| 13819 | const neg_one_scalar = try mod.intValue(lhs_scalar_ty, -1); | |
| 13820 | const neg_one = try sema.splat(resolved_type, neg_one_scalar); | |
| 13749 | 13821 | |
| 13750 | 13822 | // If the LHS is comptime-known to be not equal to the min int, |
| 13751 | 13823 | // no overflow is possible. |
| 13752 | 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 | 13828 | // If the RHS is comptime-known to not be equal to -1, no overflow is possible. |
| 13757 | 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 | 13833 | var ok: Air.Inst.Ref = .none; |
| 13762 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 13834 | if (resolved_type.zigTypeTag(mod) == .Vector) { | |
| 13763 | 13835 | if (maybe_lhs_val == null) { |
| 13764 | 13836 | const min_int_ref = try sema.addConstant(resolved_type, min_int); |
| 13765 | 13837 | ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq); |
| ... | ... | @@ -13815,8 +13887,13 @@ fn addDivByZeroSafety( |
| 13815 | 13887 | // emitted above. |
| 13816 | 13888 | if (maybe_rhs_val != null) return; |
| 13817 | 13889 | |
| 13818 | const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { | |
| 13819 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 13890 | const mod = sema.mod; | |
| 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 | 13897 | const zero = try sema.addConstant(resolved_type, zero_val); |
| 13821 | 13898 | const ok = try block.addCmpVector(casted_rhs, zero, .neq); |
| 13822 | 13899 | break :ok try block.addInst(.{ |
| ... | ... | @@ -13827,7 +13904,7 @@ fn addDivByZeroSafety( |
| 13827 | 13904 | } }, |
| 13828 | 13905 | }); |
| 13829 | 13906 | } else ok: { |
| 13830 | const zero = try sema.addConstant(resolved_type, Value.zero); | |
| 13907 | const zero = try sema.addConstant(resolved_type, scalar_zero); | |
| 13831 | 13908 | break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero); |
| 13832 | 13909 | }; |
| 13833 | 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 | 13919 | } |
| 13843 | 13920 | |
| 13844 | 13921 | fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13922 | const mod = sema.mod; | |
| 13845 | 13923 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13846 | 13924 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13847 | 13925 | sema.src = src; |
| ... | ... | @@ -13852,8 +13930,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13852 | 13930 | const rhs = try sema.resolveInst(extra.rhs); |
| 13853 | 13931 | const lhs_ty = sema.typeOf(lhs); |
| 13854 | 13932 | const rhs_ty = sema.typeOf(rhs); |
| 13855 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 13856 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 13933 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 13934 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 13857 | 13935 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13858 | 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 | 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 | 13945 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13868 | 13946 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13869 | 13947 | |
| 13870 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 13871 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 13872 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 13948 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 13949 | const rhs_scalar_ty = rhs_ty.scalarType(mod); | |
| 13950 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); | |
| 13873 | 13951 | |
| 13874 | 13952 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13875 | 13953 | |
| 13876 | 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 | 13956 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13880 | 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 | 13972 | // then emit a compile error saying you have to pick one. |
| 13896 | 13973 | if (is_int) { |
| 13897 | 13974 | if (maybe_lhs_val) |lhs_val| { |
| 13898 | if (lhs_val.isUndef()) { | |
| 13975 | if (lhs_val.isUndef(mod)) { | |
| 13899 | 13976 | return sema.failWithUseOfUndef(block, lhs_src); |
| 13900 | 13977 | } |
| 13901 | 13978 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13902 | const zero_val = if (is_vector) b: { | |
| 13903 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 13904 | } else Value.zero; | |
| 13979 | const scalar_zero = switch (scalar_tag) { | |
| 13980 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), | |
| 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 | 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 | 13991 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); |
| 13909 | 13992 | } |
| 13910 | 13993 | if (maybe_rhs_val) |rhs_val| { |
| 13911 | if (rhs_val.isUndef()) { | |
| 13994 | if (rhs_val.isUndef(mod)) { | |
| 13912 | 13995 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13913 | 13996 | } |
| 13914 | 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 | 14012 | return sema.addConstant(resolved_type, rem_result); |
| 13930 | 14013 | } |
| 13931 | 14014 | break :rs lhs_src; |
| 13932 | } else if (rhs_scalar_ty.isSignedInt()) { | |
| 14015 | } else if (rhs_scalar_ty.isSignedInt(mod)) { | |
| 13933 | 14016 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); |
| 13934 | 14017 | } else { |
| 13935 | 14018 | break :rs rhs_src; |
| ... | ... | @@ -13937,7 +14020,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13937 | 14020 | } |
| 13938 | 14021 | // float operands |
| 13939 | 14022 | if (maybe_rhs_val) |rhs_val| { |
| 13940 | if (rhs_val.isUndef()) { | |
| 14023 | if (rhs_val.isUndef(mod)) { | |
| 13941 | 14024 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13942 | 14025 | } |
| 13943 | 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 | 14030 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); |
| 13948 | 14031 | } |
| 13949 | 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 | 14034 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); |
| 13952 | 14035 | } |
| 13953 | 14036 | return sema.addConstant( |
| ... | ... | @@ -13978,32 +14061,31 @@ fn intRem( |
| 13978 | 14061 | lhs: Value, |
| 13979 | 14062 | rhs: Value, |
| 13980 | 14063 | ) CompileError!Value { |
| 13981 | if (ty.zigTypeTag() == .Vector) { | |
| 13982 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | |
| 14064 | const mod = sema.mod; | |
| 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 | 14068 | for (result_data, 0..) |*scalar, i| { |
| 13984 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 13985 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 13986 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | |
| 13987 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | |
| 13988 | scalar.* = try sema.intRemScalar(lhs_elem, rhs_elem); | |
| 14069 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 14070 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 14071 | scalar.* = try (try sema.intRemScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod); | |
| 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( | |
| 13996 | sema: *Sema, | |
| 13997 | lhs: Value, | |
| 13998 | rhs: Value, | |
| 13999 | ) CompileError!Value { | |
| 14000 | const target = sema.mod.getTarget(); | |
| 14081 | fn intRemScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) CompileError!Value { | |
| 14082 | const mod = sema.mod; | |
| 14001 | 14083 | // TODO is this a performance issue? maybe we should try the operation without |
| 14002 | 14084 | // resorting to BigInt first. |
| 14003 | 14085 | var lhs_space: Value.BigIntSpace = undefined; |
| 14004 | 14086 | var rhs_space: Value.BigIntSpace = undefined; |
| 14005 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | |
| 14006 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | |
| 14087 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); | |
| 14088 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); | |
| 14007 | 14089 | const limbs_q = try sema.arena.alloc( |
| 14008 | 14090 | math.big.Limb, |
| 14009 | 14091 | lhs_bigint.limbs.len, |
| ... | ... | @@ -14021,10 +14103,11 @@ fn intRemScalar( |
| 14021 | 14103 | var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; |
| 14022 | 14104 | var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; |
| 14023 | 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 | 14109 | fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 14110 | const mod = sema.mod; | |
| 14028 | 14111 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 14029 | 14112 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 14030 | 14113 | sema.src = src; |
| ... | ... | @@ -14035,8 +14118,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14035 | 14118 | const rhs = try sema.resolveInst(extra.rhs); |
| 14036 | 14119 | const lhs_ty = sema.typeOf(lhs); |
| 14037 | 14120 | const rhs_ty = sema.typeOf(rhs); |
| 14038 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 14039 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 14121 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 14122 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 14040 | 14123 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 14041 | 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 | 14131 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 14049 | 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 | 14136 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 14054 | 14137 | |
| 14055 | 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 | 14140 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 14059 | 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 | 14154 | // If the lhs is undefined, result is undefined. |
| 14073 | 14155 | if (is_int) { |
| 14074 | 14156 | if (maybe_lhs_val) |lhs_val| { |
| 14075 | if (lhs_val.isUndef()) { | |
| 14157 | if (lhs_val.isUndef(mod)) { | |
| 14076 | 14158 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14077 | 14159 | } |
| 14078 | 14160 | } |
| 14079 | 14161 | if (maybe_rhs_val) |rhs_val| { |
| 14080 | if (rhs_val.isUndef()) { | |
| 14162 | if (rhs_val.isUndef(mod)) { | |
| 14081 | 14163 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14082 | 14164 | } |
| 14083 | 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 | 14178 | } |
| 14097 | 14179 | // float operands |
| 14098 | 14180 | if (maybe_rhs_val) |rhs_val| { |
| 14099 | if (rhs_val.isUndef()) { | |
| 14181 | if (rhs_val.isUndef(mod)) { | |
| 14100 | 14182 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14101 | 14183 | } |
| 14102 | 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 | 14186 | } |
| 14105 | 14187 | } |
| 14106 | 14188 | if (maybe_lhs_val) |lhs_val| { |
| 14107 | if (lhs_val.isUndef()) { | |
| 14189 | if (lhs_val.isUndef(mod)) { | |
| 14108 | 14190 | return sema.addConstUndef(resolved_type); |
| 14109 | 14191 | } |
| 14110 | 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 | 14209 | } |
| 14128 | 14210 | |
| 14129 | 14211 | fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 14212 | const mod = sema.mod; | |
| 14130 | 14213 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 14131 | 14214 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 14132 | 14215 | sema.src = src; |
| ... | ... | @@ -14137,8 +14220,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14137 | 14220 | const rhs = try sema.resolveInst(extra.rhs); |
| 14138 | 14221 | const lhs_ty = sema.typeOf(lhs); |
| 14139 | 14222 | const rhs_ty = sema.typeOf(rhs); |
| 14140 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 14141 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 14223 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 14224 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 14142 | 14225 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 14143 | 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 | 14233 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 14151 | 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 | 14238 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 14156 | 14239 | |
| 14157 | 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 | 14242 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 14161 | 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 | 14256 | // If the lhs is undefined, result is undefined. |
| 14175 | 14257 | if (is_int) { |
| 14176 | 14258 | if (maybe_lhs_val) |lhs_val| { |
| 14177 | if (lhs_val.isUndef()) { | |
| 14259 | if (lhs_val.isUndef(mod)) { | |
| 14178 | 14260 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14179 | 14261 | } |
| 14180 | 14262 | } |
| 14181 | 14263 | if (maybe_rhs_val) |rhs_val| { |
| 14182 | if (rhs_val.isUndef()) { | |
| 14264 | if (rhs_val.isUndef(mod)) { | |
| 14183 | 14265 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14184 | 14266 | } |
| 14185 | 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 | 14280 | } |
| 14199 | 14281 | // float operands |
| 14200 | 14282 | if (maybe_rhs_val) |rhs_val| { |
| 14201 | if (rhs_val.isUndef()) { | |
| 14283 | if (rhs_val.isUndef(mod)) { | |
| 14202 | 14284 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14203 | 14285 | } |
| 14204 | 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 | 14288 | } |
| 14207 | 14289 | } |
| 14208 | 14290 | if (maybe_lhs_val) |lhs_val| { |
| 14209 | if (lhs_val.isUndef()) { | |
| 14291 | if (lhs_val.isUndef(mod)) { | |
| 14210 | 14292 | return sema.addConstUndef(resolved_type); |
| 14211 | 14293 | } |
| 14212 | 14294 | if (maybe_rhs_val) |rhs_val| { |
| ... | ... | @@ -14268,7 +14350,7 @@ fn zirOverflowArithmetic( |
| 14268 | 14350 | const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src); |
| 14269 | 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 | 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 | 14358 | const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs); |
| 14277 | 14359 | |
| 14278 | 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 | 14363 | var result: struct { |
| 14281 | 14364 | inst: Air.Inst.Ref = .none, |
| 14282 | wrapped: Value = Value.initTag(.unreachable_value), | |
| 14365 | wrapped: Value = Value.@"unreachable", | |
| 14283 | 14366 | overflow_bit: Value, |
| 14284 | 14367 | } = result: { |
| 14368 | const zero_bit = try mod.intValue(Type.u1, 0); | |
| 14285 | 14369 | switch (zir_tag) { |
| 14286 | 14370 | .add_with_overflow => { |
| 14287 | 14371 | // If either of the arguments is zero, `false` is returned and the other is stored |
| 14288 | 14372 | // to the result, even if it is undefined.. |
| 14289 | 14373 | // Otherwise, if either of the argument is undefined, undefined is returned. |
| 14290 | 14374 | if (maybe_lhs_val) |lhs_val| { |
| 14291 | if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | |
| 14292 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; | |
| 14375 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | |
| 14376 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; | |
| 14293 | 14377 | } |
| 14294 | 14378 | } |
| 14295 | 14379 | if (maybe_rhs_val) |rhs_val| { |
| 14296 | if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | |
| 14297 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | |
| 14380 | if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | |
| 14381 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; | |
| 14298 | 14382 | } |
| 14299 | 14383 | } |
| 14300 | 14384 | if (maybe_lhs_val) |lhs_val| { |
| 14301 | 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 | 14387 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14304 | 14388 | } |
| 14305 | 14389 | |
| ... | ... | @@ -14312,12 +14396,12 @@ fn zirOverflowArithmetic( |
| 14312 | 14396 | // If the rhs is zero, then the result is lhs and no overflow occured. |
| 14313 | 14397 | // Otherwise, if either result is undefined, both results are undefined. |
| 14314 | 14398 | if (maybe_rhs_val) |rhs_val| { |
| 14315 | if (rhs_val.isUndef()) { | |
| 14399 | if (rhs_val.isUndef(mod)) { | |
| 14316 | 14400 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14317 | 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 | 14403 | } else if (maybe_lhs_val) |lhs_val| { |
| 14320 | if (lhs_val.isUndef()) { | |
| 14404 | if (lhs_val.isUndef(mod)) { | |
| 14321 | 14405 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14322 | 14406 | } |
| 14323 | 14407 | |
| ... | ... | @@ -14330,29 +14414,30 @@ fn zirOverflowArithmetic( |
| 14330 | 14414 | // If either of the arguments is zero, the result is zero and no overflow occured. |
| 14331 | 14415 | // If either of the arguments is one, the result is the other and no overflow occured. |
| 14332 | 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 | 14418 | if (maybe_lhs_val) |lhs_val| { |
| 14334 | if (!lhs_val.isUndef()) { | |
| 14419 | if (!lhs_val.isUndef(mod)) { | |
| 14335 | 14420 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14336 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | |
| 14337 | } else if (try sema.compareAll(lhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) { | |
| 14338 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; | |
| 14421 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; | |
| 14422 | } else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { | |
| 14423 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; | |
| 14339 | 14424 | } |
| 14340 | 14425 | } |
| 14341 | 14426 | } |
| 14342 | 14427 | |
| 14343 | 14428 | if (maybe_rhs_val) |rhs_val| { |
| 14344 | if (!rhs_val.isUndef()) { | |
| 14429 | if (!rhs_val.isUndef(mod)) { | |
| 14345 | 14430 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14346 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; | |
| 14347 | } else if (try sema.compareAll(rhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) { | |
| 14348 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | |
| 14431 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; | |
| 14432 | } else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { | |
| 14433 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; | |
| 14349 | 14434 | } |
| 14350 | 14435 | } |
| 14351 | 14436 | } |
| 14352 | 14437 | |
| 14353 | 14438 | if (maybe_lhs_val) |lhs_val| { |
| 14354 | 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 | 14441 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14357 | 14442 | } |
| 14358 | 14443 | |
| ... | ... | @@ -14366,22 +14451,22 @@ fn zirOverflowArithmetic( |
| 14366 | 14451 | // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. |
| 14367 | 14452 | // Oterhwise if either of the arguments is undefined, both results are undefined. |
| 14368 | 14453 | if (maybe_lhs_val) |lhs_val| { |
| 14369 | if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | |
| 14370 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | |
| 14454 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | |
| 14455 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; | |
| 14371 | 14456 | } |
| 14372 | 14457 | } |
| 14373 | 14458 | if (maybe_rhs_val) |rhs_val| { |
| 14374 | if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | |
| 14375 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | |
| 14459 | if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | |
| 14460 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; | |
| 14376 | 14461 | } |
| 14377 | 14462 | } |
| 14378 | 14463 | if (maybe_lhs_val) |lhs_val| { |
| 14379 | 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 | 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 | 14470 | break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; |
| 14386 | 14471 | } |
| 14387 | 14472 | } |
| ... | ... | @@ -14420,40 +14505,46 @@ fn zirOverflowArithmetic( |
| 14420 | 14505 | } |
| 14421 | 14506 | |
| 14422 | 14507 | if (result.inst == .none) { |
| 14423 | const values = try sema.arena.alloc(Value, 2); | |
| 14424 | values[0] = result.wrapped; | |
| 14425 | values[1] = result.overflow_bit; | |
| 14426 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 14427 | return sema.addConstant(tuple_ty, tuple_val); | |
| 14508 | return sema.addConstant(tuple_ty, (try mod.intern(.{ .aggregate = .{ | |
| 14509 | .ty = tuple_ty.toIntern(), | |
| 14510 | .storage = .{ .elems = &.{ | |
| 14511 | result.wrapped.toIntern(), | |
| 14512 | result.overflow_bit.toIntern(), | |
| 14513 | } }, | |
| 14514 | } })).toValue()); | |
| 14428 | 14515 | } |
| 14429 | 14516 | |
| 14430 | 14517 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2); |
| 14431 | 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 | 14520 | return block.addAggregateInit(tuple_ty, element_refs); |
| 14434 | 14521 | } |
| 14435 | 14522 | |
| 14436 | fn maybeRepeated(sema: *Sema, ty: Type, val: Value) !Value { | |
| 14437 | if (ty.zigTypeTag() != .Vector) return val; | |
| 14438 | return Value.Tag.repeated.create(sema.arena, val); | |
| 14523 | fn splat(sema: *Sema, ty: Type, val: Value) !Value { | |
| 14524 | const mod = sema.mod; | |
| 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 | 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; | |
| 14443 | ||
| 14444 | const types = try sema.arena.alloc(Type, 2); | |
| 14445 | const values = try sema.arena.alloc(Value, 2); | |
| 14446 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | |
| 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); | |
| 14534 | const mod = sema.mod; | |
| 14535 | const ov_ty = if (ty.zigTypeTag(mod) == .Vector) try mod.vectorType(.{ | |
| 14536 | .len = ty.vectorLen(mod), | |
| 14537 | .child = .u1_type, | |
| 14538 | }) else Type.u1; | |
| 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 | 14550 | fn analyzeArithmetic( |
| ... | ... | @@ -14468,13 +14559,14 @@ fn analyzeArithmetic( |
| 14468 | 14559 | rhs_src: LazySrcLoc, |
| 14469 | 14560 | want_safety: bool, |
| 14470 | 14561 | ) CompileError!Air.Inst.Ref { |
| 14562 | const mod = sema.mod; | |
| 14471 | 14563 | const lhs_ty = sema.typeOf(lhs); |
| 14472 | 14564 | const rhs_ty = sema.typeOf(rhs); |
| 14473 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 14474 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 14565 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 14566 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 14475 | 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 | 14570 | .One, .Slice => {}, |
| 14479 | 14571 | .Many, .C => { |
| 14480 | 14572 | const air_tag: Air.Inst.Tag = switch (zir_tag) { |
| ... | ... | @@ -14491,18 +14583,16 @@ fn analyzeArithmetic( |
| 14491 | 14583 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 14492 | 14584 | }); |
| 14493 | 14585 | |
| 14494 | const is_vector = resolved_type.zigTypeTag() == .Vector; | |
| 14495 | ||
| 14496 | 14586 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 14497 | 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 | 14592 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 14502 | 14593 | |
| 14503 | 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 | 14596 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 14507 | 14597 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 14508 | 14598 | const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: { |
| ... | ... | @@ -14516,12 +14606,12 @@ fn analyzeArithmetic( |
| 14516 | 14606 | // overflow (max_int), causing illegal behavior. |
| 14517 | 14607 | // For floats: either operand being undef makes the result undef. |
| 14518 | 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 | 14610 | return casted_rhs; |
| 14521 | 14611 | } |
| 14522 | 14612 | } |
| 14523 | 14613 | if (maybe_rhs_val) |rhs_val| { |
| 14524 | if (rhs_val.isUndef()) { | |
| 14614 | if (rhs_val.isUndef(mod)) { | |
| 14525 | 14615 | if (is_int) { |
| 14526 | 14616 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14527 | 14617 | } else { |
| ... | ... | @@ -14534,7 +14624,7 @@ fn analyzeArithmetic( |
| 14534 | 14624 | } |
| 14535 | 14625 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add; |
| 14536 | 14626 | if (maybe_lhs_val) |lhs_val| { |
| 14537 | if (lhs_val.isUndef()) { | |
| 14627 | if (lhs_val.isUndef(mod)) { | |
| 14538 | 14628 | if (is_int) { |
| 14539 | 14629 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14540 | 14630 | } else { |
| ... | ... | @@ -14543,16 +14633,16 @@ fn analyzeArithmetic( |
| 14543 | 14633 | } |
| 14544 | 14634 | if (maybe_rhs_val) |rhs_val| { |
| 14545 | 14635 | if (is_int) { |
| 14546 | const sum = try sema.intAdd(lhs_val, rhs_val, resolved_type); | |
| 14547 | var vector_index: usize = undefined; | |
| 14548 | if (!(try sema.intFitsInType(sum, resolved_type, &vector_index))) { | |
| 14549 | return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index); | |
| 14636 | var overflow_idx: ?usize = null; | |
| 14637 | const sum = try sema.intAdd(lhs_val, rhs_val, resolved_type, &overflow_idx); | |
| 14638 | if (overflow_idx) |vec_idx| { | |
| 14639 | return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vec_idx); | |
| 14550 | 14640 | } |
| 14551 | 14641 | return sema.addConstant(resolved_type, sum); |
| 14552 | 14642 | } else { |
| 14553 | 14643 | return sema.addConstant( |
| 14554 | 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 | 14648 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; |
| ... | ... | @@ -14563,13 +14653,13 @@ fn analyzeArithmetic( |
| 14563 | 14653 | // If either of the operands are zero, the other operand is returned. |
| 14564 | 14654 | // If either of the operands are undefined, the result is undefined. |
| 14565 | 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 | 14657 | return casted_rhs; |
| 14568 | 14658 | } |
| 14569 | 14659 | } |
| 14570 | 14660 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap; |
| 14571 | 14661 | if (maybe_rhs_val) |rhs_val| { |
| 14572 | if (rhs_val.isUndef()) { | |
| 14662 | if (rhs_val.isUndef(mod)) { | |
| 14573 | 14663 | return sema.addConstUndef(resolved_type); |
| 14574 | 14664 | } |
| 14575 | 14665 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| ... | ... | @@ -14588,12 +14678,12 @@ fn analyzeArithmetic( |
| 14588 | 14678 | // If either of the operands are zero, then the other operand is returned. |
| 14589 | 14679 | // If either of the operands are undefined, the result is undefined. |
| 14590 | 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 | 14682 | return casted_rhs; |
| 14593 | 14683 | } |
| 14594 | 14684 | } |
| 14595 | 14685 | if (maybe_rhs_val) |rhs_val| { |
| 14596 | if (rhs_val.isUndef()) { | |
| 14686 | if (rhs_val.isUndef(mod)) { | |
| 14597 | 14687 | return sema.addConstUndef(resolved_type); |
| 14598 | 14688 | } |
| 14599 | 14689 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| ... | ... | @@ -14601,7 +14691,7 @@ fn analyzeArithmetic( |
| 14601 | 14691 | } |
| 14602 | 14692 | if (maybe_lhs_val) |lhs_val| { |
| 14603 | 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 | 14695 | else |
| 14606 | 14696 | try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod); |
| 14607 | 14697 | |
| ... | ... | @@ -14618,7 +14708,7 @@ fn analyzeArithmetic( |
| 14618 | 14708 | // overflow, causing illegal behavior. |
| 14619 | 14709 | // For floats: either operand being undef makes the result undef. |
| 14620 | 14710 | if (maybe_rhs_val) |rhs_val| { |
| 14621 | if (rhs_val.isUndef()) { | |
| 14711 | if (rhs_val.isUndef(mod)) { | |
| 14622 | 14712 | if (is_int) { |
| 14623 | 14713 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14624 | 14714 | } else { |
| ... | ... | @@ -14631,7 +14721,7 @@ fn analyzeArithmetic( |
| 14631 | 14721 | } |
| 14632 | 14722 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub; |
| 14633 | 14723 | if (maybe_lhs_val) |lhs_val| { |
| 14634 | if (lhs_val.isUndef()) { | |
| 14724 | if (lhs_val.isUndef(mod)) { | |
| 14635 | 14725 | if (is_int) { |
| 14636 | 14726 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14637 | 14727 | } else { |
| ... | ... | @@ -14640,16 +14730,16 @@ fn analyzeArithmetic( |
| 14640 | 14730 | } |
| 14641 | 14731 | if (maybe_rhs_val) |rhs_val| { |
| 14642 | 14732 | if (is_int) { |
| 14643 | const diff = try sema.intSub(lhs_val, rhs_val, resolved_type); | |
| 14644 | var vector_index: usize = undefined; | |
| 14645 | if (!(try sema.intFitsInType(diff, resolved_type, &vector_index))) { | |
| 14646 | return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index); | |
| 14733 | var overflow_idx: ?usize = null; | |
| 14734 | const diff = try sema.intSub(lhs_val, rhs_val, resolved_type, &overflow_idx); | |
| 14735 | if (overflow_idx) |vec_idx| { | |
| 14736 | return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vec_idx); | |
| 14647 | 14737 | } |
| 14648 | 14738 | return sema.addConstant(resolved_type, diff); |
| 14649 | 14739 | } else { |
| 14650 | 14740 | return sema.addConstant( |
| 14651 | 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 | 14745 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; |
| ... | ... | @@ -14660,7 +14750,7 @@ fn analyzeArithmetic( |
| 14660 | 14750 | // If the RHS is zero, then the other operand is returned, even if it is undefined. |
| 14661 | 14751 | // If either of the operands are undefined, the result is undefined. |
| 14662 | 14752 | if (maybe_rhs_val) |rhs_val| { |
| 14663 | if (rhs_val.isUndef()) { | |
| 14753 | if (rhs_val.isUndef(mod)) { | |
| 14664 | 14754 | return sema.addConstUndef(resolved_type); |
| 14665 | 14755 | } |
| 14666 | 14756 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| ... | ... | @@ -14669,7 +14759,7 @@ fn analyzeArithmetic( |
| 14669 | 14759 | } |
| 14670 | 14760 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap; |
| 14671 | 14761 | if (maybe_lhs_val) |lhs_val| { |
| 14672 | if (lhs_val.isUndef()) { | |
| 14762 | if (lhs_val.isUndef(mod)) { | |
| 14673 | 14763 | return sema.addConstUndef(resolved_type); |
| 14674 | 14764 | } |
| 14675 | 14765 | if (maybe_rhs_val) |rhs_val| { |
| ... | ... | @@ -14685,7 +14775,7 @@ fn analyzeArithmetic( |
| 14685 | 14775 | // If the RHS is zero, result is LHS. |
| 14686 | 14776 | // If either of the operands are undefined, result is undefined. |
| 14687 | 14777 | if (maybe_rhs_val) |rhs_val| { |
| 14688 | if (rhs_val.isUndef()) { | |
| 14778 | if (rhs_val.isUndef(mod)) { | |
| 14689 | 14779 | return sema.addConstUndef(resolved_type); |
| 14690 | 14780 | } |
| 14691 | 14781 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| ... | ... | @@ -14693,12 +14783,12 @@ fn analyzeArithmetic( |
| 14693 | 14783 | } |
| 14694 | 14784 | } |
| 14695 | 14785 | if (maybe_lhs_val) |lhs_val| { |
| 14696 | if (lhs_val.isUndef()) { | |
| 14786 | if (lhs_val.isUndef(mod)) { | |
| 14697 | 14787 | return sema.addConstUndef(resolved_type); |
| 14698 | 14788 | } |
| 14699 | 14789 | if (maybe_rhs_val) |rhs_val| { |
| 14700 | 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 | 14792 | else |
| 14703 | 14793 | try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod); |
| 14704 | 14794 | |
| ... | ... | @@ -14718,62 +14808,74 @@ fn analyzeArithmetic( |
| 14718 | 14808 | // If either of the operands are inf, and the other operand is zero, |
| 14719 | 14809 | // the result is nan. |
| 14720 | 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 | 14821 | if (maybe_lhs_val) |lhs_val| { |
| 14722 | if (!lhs_val.isUndef()) { | |
| 14723 | if (lhs_val.isNan()) { | |
| 14822 | if (!lhs_val.isUndef(mod)) { | |
| 14823 | if (lhs_val.isNan(mod)) { | |
| 14724 | 14824 | return sema.addConstant(resolved_type, lhs_val); |
| 14725 | 14825 | } |
| 14726 | 14826 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: { |
| 14727 | 14827 | if (maybe_rhs_val) |rhs_val| { |
| 14728 | if (rhs_val.isNan()) { | |
| 14828 | if (rhs_val.isNan(mod)) { | |
| 14729 | 14829 | return sema.addConstant(resolved_type, rhs_val); |
| 14730 | 14830 | } |
| 14731 | if (rhs_val.isInf()) { | |
| 14732 | return sema.addConstant(resolved_type, try Value.Tag.float_32.create(sema.arena, std.math.nan_f32)); | |
| 14831 | if (rhs_val.isInf(mod)) { | |
| 14832 | return sema.addConstant( | |
| 14833 | resolved_type, | |
| 14834 | try mod.floatValue(resolved_type, std.math.nan_f128), | |
| 14835 | ); | |
| 14733 | 14836 | } |
| 14734 | 14837 | } else if (resolved_type.isAnyFloat()) { |
| 14735 | 14838 | break :lz; |
| 14736 | 14839 | } |
| 14737 | const zero_val = if (is_vector) b: { | |
| 14738 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 14739 | } else Value.zero; | |
| 14840 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14740 | 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 | 14844 | return casted_rhs; |
| 14744 | 14845 | } |
| 14745 | 14846 | } |
| 14746 | 14847 | } |
| 14747 | 14848 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul; |
| 14748 | 14849 | if (maybe_rhs_val) |rhs_val| { |
| 14749 | if (rhs_val.isUndef()) { | |
| 14850 | if (rhs_val.isUndef(mod)) { | |
| 14750 | 14851 | if (is_int) { |
| 14751 | 14852 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14752 | 14853 | } else { |
| 14753 | 14854 | return sema.addConstUndef(resolved_type); |
| 14754 | 14855 | } |
| 14755 | 14856 | } |
| 14756 | if (rhs_val.isNan()) { | |
| 14857 | if (rhs_val.isNan(mod)) { | |
| 14757 | 14858 | return sema.addConstant(resolved_type, rhs_val); |
| 14758 | 14859 | } |
| 14759 | 14860 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: { |
| 14760 | 14861 | if (maybe_lhs_val) |lhs_val| { |
| 14761 | if (lhs_val.isInf()) { | |
| 14762 | return sema.addConstant(resolved_type, try Value.Tag.float_32.create(sema.arena, std.math.nan_f32)); | |
| 14862 | if (lhs_val.isInf(mod)) { | |
| 14863 | return sema.addConstant( | |
| 14864 | resolved_type, | |
| 14865 | try mod.floatValue(resolved_type, std.math.nan_f128), | |
| 14866 | ); | |
| 14763 | 14867 | } |
| 14764 | 14868 | } else if (resolved_type.isAnyFloat()) { |
| 14765 | 14869 | break :rz; |
| 14766 | 14870 | } |
| 14767 | const zero_val = if (is_vector) b: { | |
| 14768 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 14769 | } else Value.zero; | |
| 14871 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14770 | 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 | 14875 | return casted_lhs; |
| 14774 | 14876 | } |
| 14775 | 14877 | if (maybe_lhs_val) |lhs_val| { |
| 14776 | if (lhs_val.isUndef()) { | |
| 14878 | if (lhs_val.isUndef(mod)) { | |
| 14777 | 14879 | if (is_int) { |
| 14778 | 14880 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14779 | 14881 | } else { |
| ... | ... | @@ -14781,16 +14883,16 @@ fn analyzeArithmetic( |
| 14781 | 14883 | } |
| 14782 | 14884 | } |
| 14783 | 14885 | if (is_int) { |
| 14784 | const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod); | |
| 14785 | var vector_index: usize = undefined; | |
| 14786 | if (!(try sema.intFitsInType(product, resolved_type, &vector_index))) { | |
| 14787 | return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index); | |
| 14886 | var overflow_idx: ?usize = null; | |
| 14887 | const product = try lhs_val.intMul(rhs_val, resolved_type, &overflow_idx, sema.arena, mod); | |
| 14888 | if (overflow_idx) |vec_idx| { | |
| 14889 | return sema.failWithIntegerOverflow(block, src, resolved_type, product, vec_idx); | |
| 14788 | 14890 | } |
| 14789 | 14891 | return sema.addConstant(resolved_type, product); |
| 14790 | 14892 | } else { |
| 14791 | 14893 | return sema.addConstant( |
| 14792 | 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 | 14898 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; |
| ... | ... | @@ -14801,40 +14903,46 @@ fn analyzeArithmetic( |
| 14801 | 14903 | // If either of the operands are zero, result is zero. |
| 14802 | 14904 | // If either of the operands are one, result is the other operand. |
| 14803 | 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 | 14916 | if (maybe_lhs_val) |lhs_val| { |
| 14805 | if (!lhs_val.isUndef()) { | |
| 14917 | if (!lhs_val.isUndef(mod)) { | |
| 14806 | 14918 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14807 | const zero_val = if (is_vector) b: { | |
| 14808 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 14809 | } else Value.zero; | |
| 14919 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14810 | 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 | 14923 | return casted_rhs; |
| 14814 | 14924 | } |
| 14815 | 14925 | } |
| 14816 | 14926 | } |
| 14817 | 14927 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap; |
| 14818 | 14928 | if (maybe_rhs_val) |rhs_val| { |
| 14819 | if (rhs_val.isUndef()) { | |
| 14929 | if (rhs_val.isUndef(mod)) { | |
| 14820 | 14930 | return sema.addConstUndef(resolved_type); |
| 14821 | 14931 | } |
| 14822 | 14932 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14823 | const zero_val = if (is_vector) b: { | |
| 14824 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 14825 | } else Value.zero; | |
| 14933 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14826 | 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 | 14937 | return casted_lhs; |
| 14830 | 14938 | } |
| 14831 | 14939 | if (maybe_lhs_val) |lhs_val| { |
| 14832 | if (lhs_val.isUndef()) { | |
| 14940 | if (lhs_val.isUndef(mod)) { | |
| 14833 | 14941 | return sema.addConstUndef(resolved_type); |
| 14834 | 14942 | } |
| 14835 | 14943 | return sema.addConstant( |
| 14836 | 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 | 14947 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; |
| 14840 | 14948 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; |
| ... | ... | @@ -14844,41 +14952,47 @@ fn analyzeArithmetic( |
| 14844 | 14952 | // If either of the operands are zero, result is zero. |
| 14845 | 14953 | // If either of the operands are one, result is the other operand. |
| 14846 | 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 | 14965 | if (maybe_lhs_val) |lhs_val| { |
| 14848 | if (!lhs_val.isUndef()) { | |
| 14966 | if (!lhs_val.isUndef(mod)) { | |
| 14849 | 14967 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14850 | const zero_val = if (is_vector) b: { | |
| 14851 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 14852 | } else Value.zero; | |
| 14968 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14853 | 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 | 14972 | return casted_rhs; |
| 14857 | 14973 | } |
| 14858 | 14974 | } |
| 14859 | 14975 | } |
| 14860 | 14976 | if (maybe_rhs_val) |rhs_val| { |
| 14861 | if (rhs_val.isUndef()) { | |
| 14977 | if (rhs_val.isUndef(mod)) { | |
| 14862 | 14978 | return sema.addConstUndef(resolved_type); |
| 14863 | 14979 | } |
| 14864 | 14980 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14865 | const zero_val = if (is_vector) b: { | |
| 14866 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 14867 | } else Value.zero; | |
| 14981 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14868 | 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 | 14985 | return casted_lhs; |
| 14872 | 14986 | } |
| 14873 | 14987 | if (maybe_lhs_val) |lhs_val| { |
| 14874 | if (lhs_val.isUndef()) { | |
| 14988 | if (lhs_val.isUndef(mod)) { | |
| 14875 | 14989 | return sema.addConstUndef(resolved_type); |
| 14876 | 14990 | } |
| 14877 | 14991 | |
| 14878 | 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 | 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 | 14997 | return sema.addConstant(resolved_type, val); |
| 14884 | 14998 | } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat }; |
| ... | ... | @@ -14910,7 +15024,7 @@ fn analyzeArithmetic( |
| 14910 | 15024 | } }, |
| 14911 | 15025 | }); |
| 14912 | 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 | 15028 | try block.addInst(.{ |
| 14915 | 15029 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| 14916 | 15030 | .data = .{ .reduce = .{ |
| ... | ... | @@ -14920,7 +15034,7 @@ fn analyzeArithmetic( |
| 14920 | 15034 | }) |
| 14921 | 15035 | else |
| 14922 | 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 | 15038 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); |
| 14925 | 15039 | |
| 14926 | 15040 | try sema.addSafetyCheck(block, no_ov, .integer_overflow); |
| ... | ... | @@ -14944,15 +15058,12 @@ fn analyzePtrArithmetic( |
| 14944 | 15058 | // TODO if the operand is comptime-known to be negative, or is a negative int, |
| 14945 | 15059 | // coerce to isize instead of usize. |
| 14946 | 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 | 15062 | const opt_ptr_val = try sema.resolveMaybeUndefVal(ptr); |
| 14949 | 15063 | const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset); |
| 14950 | 15064 | const ptr_ty = sema.typeOf(ptr); |
| 14951 | const ptr_info = ptr_ty.ptrInfo().data; | |
| 14952 | const elem_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Array) | |
| 14953 | ptr_info.pointee_type.childType() | |
| 14954 | else | |
| 14955 | ptr_info.pointee_type; | |
| 15065 | const ptr_info = ptr_ty.ptrInfo(mod); | |
| 15066 | assert(ptr_info.size == .Many or ptr_info.size == .C); | |
| 14956 | 15067 | |
| 14957 | 15068 | const new_ptr_ty = t: { |
| 14958 | 15069 | // Calculate the new pointer alignment. |
| ... | ... | @@ -14963,9 +15074,9 @@ fn analyzePtrArithmetic( |
| 14963 | 15074 | } |
| 14964 | 15075 | // If the addend is not a comptime-known value we can still count on |
| 14965 | 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 | 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 | 15080 | break :a elem_size * off_int; |
| 14970 | 15081 | } else elem_size; |
| 14971 | 15082 | |
| ... | ... | @@ -14974,7 +15085,7 @@ fn analyzePtrArithmetic( |
| 14974 | 15085 | // non zero). |
| 14975 | 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 | 15089 | .pointee_type = ptr_info.pointee_type, |
| 14979 | 15090 | .sentinel = ptr_info.sentinel, |
| 14980 | 15091 | .@"align" = new_align, |
| ... | ... | @@ -14989,24 +15100,24 @@ fn analyzePtrArithmetic( |
| 14989 | 15100 | const runtime_src = rs: { |
| 14990 | 15101 | if (opt_ptr_val) |ptr_val| { |
| 14991 | 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 | 15106 | if (offset_int == 0) return ptr; |
| 14996 | if (try ptr_val.getUnsignedIntAdvanced(target, sema)) |addr| { | |
| 14997 | const elem_size = elem_ty.abiSize(target); | |
| 15107 | if (try ptr_val.getUnsignedIntAdvanced(mod, sema)) |addr| { | |
| 15108 | const elem_size = ptr_info.pointee_type.abiSize(mod); | |
| 14998 | 15109 | const new_addr = switch (air_tag) { |
| 14999 | 15110 | .ptr_add => addr + elem_size * offset_int, |
| 15000 | 15111 | .ptr_sub => addr - elem_size * offset_int, |
| 15001 | 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 | 15115 | return sema.addConstant(new_ptr_ty, new_ptr_val); |
| 15005 | 15116 | } |
| 15006 | 15117 | if (air_tag == .ptr_sub) { |
| 15007 | 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 | 15121 | return sema.addConstant(new_ptr_ty, new_ptr_val); |
| 15011 | 15122 | } else break :rs offset_src; |
| 15012 | 15123 | } else break :rs ptr_src; |
| ... | ... | @@ -15052,7 +15163,7 @@ fn zirAsm( |
| 15052 | 15163 | const inputs_len = @truncate(u5, extended.small >> 5); |
| 15053 | 15164 | const clobbers_len = @truncate(u5, extended.small >> 10); |
| 15054 | 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 | 15168 | const asm_source: []const u8 = if (tmpl_is_expr) blk: { |
| 15058 | 15169 | const tmpl = @intToEnum(Zir.Inst.Ref, extra.data.asm_source); |
| ... | ... | @@ -15116,6 +15227,7 @@ fn zirAsm( |
| 15116 | 15227 | |
| 15117 | 15228 | const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len); |
| 15118 | 15229 | const inputs = try sema.arena.alloc(ConstraintName, inputs_len); |
| 15230 | const mod = sema.mod; | |
| 15119 | 15231 | |
| 15120 | 15232 | for (args, 0..) |*arg, arg_i| { |
| 15121 | 15233 | const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i); |
| ... | ... | @@ -15123,9 +15235,9 @@ fn zirAsm( |
| 15123 | 15235 | |
| 15124 | 15236 | const uncasted_arg = try sema.resolveInst(input.data.operand); |
| 15125 | 15237 | const uncasted_arg_ty = sema.typeOf(uncasted_arg); |
| 15126 | switch (uncasted_arg_ty.zigTypeTag()) { | |
| 15127 | .ComptimeInt => arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted_arg, src), | |
| 15128 | .ComptimeFloat => arg.* = try sema.coerce(block, Type.initTag(.f64), uncasted_arg, src), | |
| 15238 | switch (uncasted_arg_ty.zigTypeTag(mod)) { | |
| 15239 | .ComptimeInt => arg.* = try sema.coerce(block, Type.usize, uncasted_arg, src), | |
| 15240 | .ComptimeFloat => arg.* = try sema.coerce(block, Type.f64, uncasted_arg, src), | |
| 15129 | 15241 | else => { |
| 15130 | 15242 | arg.* = uncasted_arg; |
| 15131 | 15243 | try sema.queueFullTypeResolution(uncasted_arg_ty); |
| ... | ... | @@ -15205,6 +15317,7 @@ fn zirCmpEq( |
| 15205 | 15317 | const tracy = trace(@src()); |
| 15206 | 15318 | defer tracy.end(); |
| 15207 | 15319 | |
| 15320 | const mod = sema.mod; | |
| 15208 | 15321 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 15209 | 15322 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 15210 | 15323 | const src: LazySrcLoc = inst_data.src(); |
| ... | ... | @@ -15215,8 +15328,8 @@ fn zirCmpEq( |
| 15215 | 15328 | |
| 15216 | 15329 | const lhs_ty = sema.typeOf(lhs); |
| 15217 | 15330 | const rhs_ty = sema.typeOf(rhs); |
| 15218 | const lhs_ty_tag = lhs_ty.zigTypeTag(); | |
| 15219 | const rhs_ty_tag = rhs_ty.zigTypeTag(); | |
| 15331 | const lhs_ty_tag = lhs_ty.zigTypeTag(mod); | |
| 15332 | const rhs_ty_tag = rhs_ty.zigTypeTag(mod); | |
| 15220 | 15333 | if (lhs_ty_tag == .Null and rhs_ty_tag == .Null) { |
| 15221 | 15334 | // null == null, null != null |
| 15222 | 15335 | if (op == .eq) { |
| ... | ... | @@ -15227,16 +15340,16 @@ fn zirCmpEq( |
| 15227 | 15340 | } |
| 15228 | 15341 | |
| 15229 | 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 | 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 | 15347 | return sema.analyzeIsNull(block, src, lhs, op == .neq); |
| 15235 | 15348 | } |
| 15236 | 15349 | |
| 15237 | 15350 | if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) { |
| 15238 | 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 | 15355 | if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) { |
| ... | ... | @@ -15250,15 +15363,12 @@ fn zirCmpEq( |
| 15250 | 15363 | const runtime_src: LazySrcLoc = src: { |
| 15251 | 15364 | if (try sema.resolveMaybeUndefVal(lhs)) |lval| { |
| 15252 | 15365 | if (try sema.resolveMaybeUndefVal(rhs)) |rval| { |
| 15253 | if (lval.isUndef() or rval.isUndef()) { | |
| 15366 | if (lval.isUndef(mod) or rval.isUndef(mod)) { | |
| 15254 | 15367 | return sema.addConstUndef(Type.bool); |
| 15255 | 15368 | } |
| 15256 | // TODO optimisation opportunity: evaluate if mem.eql is faster with the names, | |
| 15257 | // or calling to Module.getErrorValue to get the values and then compare them is | |
| 15258 | // faster. | |
| 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)) { | |
| 15369 | const lkey = mod.intern_pool.indexToKey(lval.toIntern()); | |
| 15370 | const rkey = mod.intern_pool.indexToKey(rval.toIntern()); | |
| 15371 | if ((lkey.err.name == rkey.err.name) == (op == .eq)) { | |
| 15262 | 15372 | return Air.Inst.Ref.bool_true; |
| 15263 | 15373 | } else { |
| 15264 | 15374 | return Air.Inst.Ref.bool_false; |
| ... | ... | @@ -15276,7 +15386,7 @@ fn zirCmpEq( |
| 15276 | 15386 | if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) { |
| 15277 | 15387 | const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs); |
| 15278 | 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 | 15390 | return Air.Inst.Ref.bool_true; |
| 15281 | 15391 | } else { |
| 15282 | 15392 | return Air.Inst.Ref.bool_false; |
| ... | ... | @@ -15295,12 +15405,13 @@ fn analyzeCmpUnionTag( |
| 15295 | 15405 | tag_src: LazySrcLoc, |
| 15296 | 15406 | op: std.math.CompareOperator, |
| 15297 | 15407 | ) CompileError!Air.Inst.Ref { |
| 15408 | const mod = sema.mod; | |
| 15298 | 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 | 15411 | const msg = msg: { |
| 15301 | 15412 | const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); |
| 15302 | 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 | 15415 | break :msg msg; |
| 15305 | 15416 | }; |
| 15306 | 15417 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -15311,9 +15422,9 @@ fn analyzeCmpUnionTag( |
| 15311 | 15422 | const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src); |
| 15312 | 15423 | |
| 15313 | 15424 | if (try sema.resolveMaybeUndefVal(coerced_tag)) |enum_val| { |
| 15314 | if (enum_val.isUndef()) return sema.addConstUndef(Type.bool); | |
| 15315 | const field_ty = union_ty.unionFieldType(enum_val, sema.mod); | |
| 15316 | if (field_ty.zigTypeTag() == .NoReturn) { | |
| 15425 | if (enum_val.isUndef(mod)) return sema.addConstUndef(Type.bool); | |
| 15426 | const field_ty = union_ty.unionFieldType(enum_val, mod); | |
| 15427 | if (field_ty.zigTypeTag(mod) == .NoReturn) { | |
| 15317 | 15428 | return Air.Inst.Ref.bool_false; |
| 15318 | 15429 | } |
| 15319 | 15430 | } |
| ... | ... | @@ -15352,34 +15463,35 @@ fn analyzeCmp( |
| 15352 | 15463 | rhs_src: LazySrcLoc, |
| 15353 | 15464 | is_equality_cmp: bool, |
| 15354 | 15465 | ) CompileError!Air.Inst.Ref { |
| 15466 | const mod = sema.mod; | |
| 15355 | 15467 | const lhs_ty = sema.typeOf(lhs); |
| 15356 | 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 | 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 | 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 | 15477 | // This operation allows any combination of integer and float types, regardless of the |
| 15366 | 15478 | // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for |
| 15367 | 15479 | // numeric types. |
| 15368 | 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 | 15483 | const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs); |
| 15372 | 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 | 15487 | const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs); |
| 15376 | 15488 | return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src); |
| 15377 | 15489 | } |
| 15378 | 15490 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 15379 | 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 | 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 | 15497 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| ... | ... | @@ -15408,15 +15520,19 @@ fn cmpSelf( |
| 15408 | 15520 | lhs_src: LazySrcLoc, |
| 15409 | 15521 | rhs_src: LazySrcLoc, |
| 15410 | 15522 | ) CompileError!Air.Inst.Ref { |
| 15523 | const mod = sema.mod; | |
| 15411 | 15524 | const resolved_type = sema.typeOf(casted_lhs); |
| 15412 | 15525 | const runtime_src: LazySrcLoc = src: { |
| 15413 | 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 | 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) { | |
| 15419 | const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.bool); | |
| 15531 | if (resolved_type.zigTypeTag(mod) == .Vector) { | |
| 15532 | const result_ty = try mod.vectorType(.{ | |
| 15533 | .len = resolved_type.vectorLen(mod), | |
| 15534 | .child = .bool_type, | |
| 15535 | }); | |
| 15420 | 15536 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_type); |
| 15421 | 15537 | return sema.addConstant(result_ty, cmp_val); |
| 15422 | 15538 | } |
| ... | ... | @@ -15427,7 +15543,7 @@ fn cmpSelf( |
| 15427 | 15543 | return Air.Inst.Ref.bool_false; |
| 15428 | 15544 | } |
| 15429 | 15545 | } else { |
| 15430 | if (resolved_type.zigTypeTag() == .Bool) { | |
| 15546 | if (resolved_type.zigTypeTag(mod) == .Bool) { | |
| 15431 | 15547 | // We can lower bool eq/neq more efficiently. |
| 15432 | 15548 | return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src); |
| 15433 | 15549 | } |
| ... | ... | @@ -15436,9 +15552,9 @@ fn cmpSelf( |
| 15436 | 15552 | } else { |
| 15437 | 15553 | // For bools, we still check the other operand, because we can lower |
| 15438 | 15554 | // bool eq/neq more efficiently. |
| 15439 | if (resolved_type.zigTypeTag() == .Bool) { | |
| 15555 | if (resolved_type.zigTypeTag(mod) == .Bool) { | |
| 15440 | 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 | 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 | 15562 | } |
| 15447 | 15563 | }; |
| 15448 | 15564 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 15449 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 15565 | if (resolved_type.zigTypeTag(mod) == .Vector) { | |
| 15450 | 15566 | return block.addCmpVector(casted_lhs, casted_rhs, op); |
| 15451 | 15567 | } |
| 15452 | 15568 | const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized); |
| ... | ... | @@ -15475,16 +15591,17 @@ fn runtimeBoolCmp( |
| 15475 | 15591 | } |
| 15476 | 15592 | |
| 15477 | 15593 | fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 15594 | const mod = sema.mod; | |
| 15478 | 15595 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 15479 | 15596 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15480 | 15597 | const ty = try sema.resolveType(block, operand_src, inst_data.operand); |
| 15481 | switch (ty.zigTypeTag()) { | |
| 15598 | switch (ty.zigTypeTag(mod)) { | |
| 15482 | 15599 | .Fn, |
| 15483 | 15600 | .NoReturn, |
| 15484 | 15601 | .Undefined, |
| 15485 | 15602 | .Null, |
| 15486 | 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 | 15606 | .Type, |
| 15490 | 15607 | .EnumLiteral, |
| ... | ... | @@ -15509,25 +15626,25 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 15509 | 15626 | .AnyFrame, |
| 15510 | 15627 | => {}, |
| 15511 | 15628 | } |
| 15512 | const target = sema.mod.getTarget(); | |
| 15513 | const val = try ty.lazyAbiSize(target, sema.arena); | |
| 15514 | if (val.tag() == .lazy_size) { | |
| 15629 | const val = try ty.lazyAbiSize(mod); | |
| 15630 | if (val.isLazySize(mod)) { | |
| 15515 | 15631 | try sema.queueFullTypeResolution(ty); |
| 15516 | 15632 | } |
| 15517 | 15633 | return sema.addConstant(Type.comptime_int, val); |
| 15518 | 15634 | } |
| 15519 | 15635 | |
| 15520 | 15636 | fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 15637 | const mod = sema.mod; | |
| 15521 | 15638 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 15522 | 15639 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15523 | 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 | 15642 | .Fn, |
| 15526 | 15643 | .NoReturn, |
| 15527 | 15644 | .Undefined, |
| 15528 | 15645 | .Null, |
| 15529 | 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 | 15649 | .Type, |
| 15533 | 15650 | .EnumLiteral, |
| ... | ... | @@ -15552,8 +15669,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 15552 | 15669 | .AnyFrame, |
| 15553 | 15670 | => {}, |
| 15554 | 15671 | } |
| 15555 | const target = sema.mod.getTarget(); | |
| 15556 | const bit_size = try operand_ty.bitSizeAdvanced(target, sema); | |
| 15672 | const bit_size = try operand_ty.bitSizeAdvanced(mod, sema); | |
| 15557 | 15673 | return sema.addIntUnsigned(Type.comptime_int, bit_size); |
| 15558 | 15674 | } |
| 15559 | 15675 | |
| ... | ... | @@ -15562,17 +15678,13 @@ fn zirThis( |
| 15562 | 15678 | block: *Block, |
| 15563 | 15679 | extended: Zir.Inst.Extended.InstData, |
| 15564 | 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 | 15683 | const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); |
| 15567 | 15684 | return sema.analyzeDeclVal(block, src, this_decl_index); |
| 15568 | 15685 | } |
| 15569 | 15686 | |
| 15570 | fn zirClosureCapture( | |
| 15571 | sema: *Sema, | |
| 15572 | block: *Block, | |
| 15573 | inst: Zir.Inst.Index, | |
| 15574 | ) CompileError!void { | |
| 15575 | // TODO: Compile error when closed over values are modified | |
| 15687 | fn zirClosureCapture(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | |
| 15576 | 15688 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; |
| 15577 | 15689 | // Closures are not necessarily constant values. For example, the |
| 15578 | 15690 | // code might do something like this: |
| ... | ... | @@ -15580,26 +15692,24 @@ fn zirClosureCapture( |
| 15580 | 15692 | // ...in which case the closure_capture instruction has access to a runtime |
| 15581 | 15693 | // value only. In such case we preserve the type and use a dummy runtime value. |
| 15582 | 15694 | const operand = try sema.resolveInst(inst_data.operand); |
| 15583 | const val = (try sema.resolveMaybeUndefValAllowVariables(operand)) orelse | |
| 15584 | Value.initTag(.unreachable_value); | |
| 15585 | ||
| 15586 | try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{ | |
| 15587 | .ty = try sema.typeOf(operand).copy(sema.perm_arena), | |
| 15588 | .val = try val.copy(sema.perm_arena), | |
| 15589 | }); | |
| 15695 | const ty = sema.typeOf(operand); | |
| 15696 | const capture: CaptureScope.Capture = blk: { | |
| 15697 | if (try sema.resolveMaybeUndefValAllowVariables(operand)) |val| { | |
| 15698 | const ip_index = try val.intern(ty, sema.mod); | |
| 15699 | break :blk .{ .comptime_val = ip_index }; | |
| 15700 | } | |
| 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( | |
| 15593 | sema: *Sema, | |
| 15594 | block: *Block, | |
| 15595 | inst: Zir.Inst.Index, | |
| 15596 | ) CompileError!Air.Inst.Ref { | |
| 15597 | // TODO CLOSURE: Test this with inline functions | |
| 15706 | fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 15707 | const mod = sema.mod; | |
| 15598 | 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 | 15710 | // Note: The target closure must be in this scope list. |
| 15601 | 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 | 15713 | // Note: We don't need to add a dependency here, because |
| 15604 | 15714 | // decls always depend on their lexical parents. |
| 15605 | 15715 | |
| ... | ... | @@ -15612,17 +15722,17 @@ fn zirClosureGet( |
| 15612 | 15722 | } |
| 15613 | 15723 | return error.AnalysisFail; |
| 15614 | 15724 | } |
| 15615 | if (scope.captures.getPtr(inst_data.inst)) |tv| { | |
| 15616 | break tv; | |
| 15725 | if (scope.captures.get(inst_data.inst)) |capture| { | |
| 15726 | break capture; | |
| 15617 | 15727 | } |
| 15618 | 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 | 15732 | const msg = msg: { |
| 15623 | 15733 | const name = name: { |
| 15624 | const file = sema.owner_decl.getFileScope(); | |
| 15625 | const tree = file.getTree(sema.mod.gpa) catch |err| { | |
| 15734 | const file = sema.owner_decl.getFileScope(mod); | |
| 15735 | const tree = file.getTree(sema.gpa) catch |err| { | |
| 15626 | 15736 | // In this case we emit a warning + a less precise source location. |
| 15627 | 15737 | log.warn("unable to load {s}: {s}", .{ |
| 15628 | 15738 | file.sub_file_path, @errorName(err), |
| ... | ... | @@ -15646,11 +15756,11 @@ fn zirClosureGet( |
| 15646 | 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 | 15760 | const msg = msg: { |
| 15651 | 15761 | const name = name: { |
| 15652 | const file = sema.owner_decl.getFileScope(); | |
| 15653 | const tree = file.getTree(sema.mod.gpa) catch |err| { | |
| 15762 | const file = sema.owner_decl.getFileScope(mod); | |
| 15763 | const tree = file.getTree(sema.gpa) catch |err| { | |
| 15654 | 15764 | // In this case we emit a warning + a less precise source location. |
| 15655 | 15765 | log.warn("unable to load {s}: {s}", .{ |
| 15656 | 15766 | file.sub_file_path, @errorName(err), |
| ... | ... | @@ -15676,13 +15786,17 @@ fn zirClosureGet( |
| 15676 | 15786 | return sema.failWithOwnedErrorMsg(msg); |
| 15677 | 15787 | } |
| 15678 | 15788 | |
| 15679 | if (tv.val.tag() == .unreachable_value) { | |
| 15680 | assert(block.is_typeof); | |
| 15681 | // We need a dummy runtime instruction with the correct type. | |
| 15682 | return block.addTy(.alloc, tv.ty); | |
| 15789 | switch (capture) { | |
| 15790 | .runtime_val => |ty_ip_index| { | |
| 15791 | assert(block.is_typeof); | |
| 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 | 15802 | fn zirRetAddr( |
| ... | ... | @@ -15717,345 +15831,422 @@ fn zirBuiltinSrc( |
| 15717 | 15831 | const tracy = trace(@src()); |
| 15718 | 15832 | defer tracy.end(); |
| 15719 | 15833 | |
| 15834 | const mod = sema.mod; | |
| 15720 | 15835 | const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data; |
| 15721 | 15836 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 15722 | 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 | 15840 | const func_name_val = blk: { |
| 15726 | 15841 | var anon_decl = try block.startAnonDecl(); |
| 15727 | 15842 | defer anon_decl.deinit(); |
| 15728 | const name = std.mem.span(fn_owner_decl.name); | |
| 15729 | const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]); | |
| 15843 | // TODO: write something like getCoercedInts to avoid needing to dupe | |
| 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 | 15850 | const new_decl = try anon_decl.finish( |
| 15731 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len - 1), | |
| 15732 | try Value.Tag.bytes.create(anon_decl.arena(), bytes), | |
| 15851 | new_decl_ty, | |
| 15852 | (try mod.intern(.{ .aggregate = .{ | |
| 15853 | .ty = new_decl_ty.toIntern(), | |
| 15854 | .storage = .{ .bytes = name }, | |
| 15855 | } })).toValue(), | |
| 15733 | 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 | 15865 | const file_name_val = blk: { |
| 15739 | 15866 | var anon_decl = try block.startAnonDecl(); |
| 15740 | 15867 | defer anon_decl.deinit(); |
| 15741 | 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 | 15875 | const new_decl = try anon_decl.finish( |
| 15744 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), name.len), | |
| 15745 | try Value.Tag.bytes.create(anon_decl.arena(), name[0 .. name.len + 1]), | |
| 15876 | new_decl_ty, | |
| 15877 | (try mod.intern(.{ .aggregate = .{ | |
| 15878 | .ty = new_decl_ty.toIntern(), | |
| 15879 | .storage = .{ .bytes = name }, | |
| 15880 | } })).toValue(), | |
| 15746 | 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); | |
| 15752 | // file: [:0]const u8, | |
| 15753 | field_values[0] = file_name_val; | |
| 15754 | // fn_name: [:0]const u8, | |
| 15755 | field_values[1] = func_name_val; | |
| 15756 | // line: u32 | |
| 15757 | field_values[2] = try Value.Tag.runtime_value.create(sema.arena, try Value.Tag.int_u64.create(sema.arena, extra.line + 1)); | |
| 15758 | // column: u32, | |
| 15759 | field_values[3] = try Value.Tag.int_u64.create(sema.arena, extra.column + 1); | |
| 15760 | ||
| 15761 | return sema.addConstant( | |
| 15762 | try sema.getBuiltinType("SourceLocation"), | |
| 15763 | try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 15764 | ); | |
| 15890 | const src_loc_ty = try sema.getBuiltinType("SourceLocation"); | |
| 15891 | const fields = .{ | |
| 15892 | // file: [:0]const u8, | |
| 15893 | file_name_val, | |
| 15894 | // fn_name: [:0]const u8, | |
| 15895 | func_name_val, | |
| 15896 | // line: u32, | |
| 15897 | try mod.intern(.{ .runtime_value = .{ | |
| 15898 | .ty = .u32_type, | |
| 15899 | .val = (try mod.intValue(Type.u32, extra.line + 1)).toIntern(), | |
| 15900 | } }), | |
| 15901 | // column: u32, | |
| 15902 | (try mod.intValue(Type.u32, extra.column + 1)).toIntern(), | |
| 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 | 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 | 15914 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 15769 | 15915 | const src = inst_data.src(); |
| 15770 | 15916 | const ty = try sema.resolveType(block, src, inst_data.operand); |
| 15771 | 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()) { | |
| 15775 | .Type => return sema.addConstant( | |
| 15776 | type_info_ty, | |
| 15777 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15778 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Type)), | |
| 15779 | .val = Value.void, | |
| 15780 | }), | |
| 15781 | ), | |
| 15782 | .Void => return sema.addConstant( | |
| 15783 | type_info_ty, | |
| 15784 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15785 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Void)), | |
| 15786 | .val = Value.void, | |
| 15787 | }), | |
| 15788 | ), | |
| 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 | ), | |
| 15920 | switch (ty.zigTypeTag(mod)) { | |
| 15921 | .Type, | |
| 15922 | .Void, | |
| 15923 | .Bool, | |
| 15924 | .NoReturn, | |
| 15925 | .ComptimeFloat, | |
| 15926 | .ComptimeInt, | |
| 15927 | .Undefined, | |
| 15928 | .Null, | |
| 15929 | .EnumLiteral, | |
| 15930 | => |type_info_tag| return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 15931 | .ty = type_info_ty.toIntern(), | |
| 15932 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(type_info_tag))).toIntern(), | |
| 15933 | .val = .void_value, | |
| 15934 | } })).toValue()), | |
| 15838 | 15935 | .Fn => { |
| 15839 | 15936 | // TODO: look into memoizing this result. |
| 15840 | const info = ty.fnInfo(); | |
| 15841 | ||
| 15842 | 15937 | var params_anon_decl = try block.startAnonDecl(); |
| 15843 | 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 | 15963 | for (param_vals, 0..) |*param_val, i| { |
| 15964 | const info = mod.typeToFunc(ty).?; | |
| 15847 | 15965 | const param_ty = info.param_types[i]; |
| 15848 | const is_generic = param_ty.tag() == .generic_poison; | |
| 15849 | const param_ty_val = if (is_generic) | |
| 15850 | Value.null | |
| 15851 | else | |
| 15852 | try Value.Tag.opt_payload.create( | |
| 15853 | params_anon_decl.arena(), | |
| 15854 | try Value.Tag.ty.create(params_anon_decl.arena(), try param_ty.copy(params_anon_decl.arena())), | |
| 15855 | ); | |
| 15966 | const is_generic = param_ty == .generic_poison_type; | |
| 15967 | const param_ty_val = try ip.get(gpa, .{ .opt = .{ | |
| 15968 | .ty = try ip.get(gpa, .{ .opt_type = .type_type }), | |
| 15969 | .val = if (is_generic) .none else param_ty, | |
| 15970 | } }); | |
| 15856 | 15971 | |
| 15857 | 15972 | const is_noalias = blk: { |
| 15858 | 15973 | const index = std.math.cast(u5, i) orelse break :blk false; |
| 15859 | 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); | |
| 15863 | param_fields.* = .{ | |
| 15977 | const param_fields = .{ | |
| 15864 | 15978 | // is_generic: bool, |
| 15865 | Value.makeBool(is_generic), | |
| 15979 | Value.makeBool(is_generic).toIntern(), | |
| 15866 | 15980 | // is_noalias: bool, |
| 15867 | Value.makeBool(is_noalias), | |
| 15981 | Value.makeBool(is_noalias).toIntern(), | |
| 15868 | 15982 | // type: ?type, |
| 15869 | 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 | 15991 | const args_val = v: { |
| 15875 | const fn_info_decl_index = (try sema.namespaceLookup( | |
| 15876 | block, | |
| 15877 | src, | |
| 15878 | type_info_ty.getNamespace().?, | |
| 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); | |
| 15992 | const new_decl_ty = try mod.arrayType(.{ | |
| 15993 | .len = param_vals.len, | |
| 15994 | .child = param_info_ty.toIntern(), | |
| 15995 | }); | |
| 15897 | 15996 | const new_decl = try params_anon_decl.finish( |
| 15898 | try Type.Tag.array.create(params_anon_decl.arena(), .{ | |
| 15899 | .len = param_vals.len, | |
| 15900 | .elem_type = try param_ty.copy(params_anon_decl.arena()), | |
| 15901 | }), | |
| 15902 | try Value.Tag.aggregate.create( | |
| 15903 | params_anon_decl.arena(), | |
| 15904 | param_vals, | |
| 15905 | ), | |
| 15997 | new_decl_ty, | |
| 15998 | (try mod.intern(.{ .aggregate = .{ | |
| 15999 | .ty = new_decl_ty.toIntern(), | |
| 16000 | .storage = .{ .elems = param_vals }, | |
| 16001 | } })).toValue(), | |
| 15906 | 16002 | 0, // default alignment |
| 15907 | 16003 | ); |
| 15908 | break :v try Value.Tag.slice.create(sema.arena, .{ | |
| 15909 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 15910 | .len = try Value.Tag.int_u64.create(sema.arena, param_vals.len), | |
| 15911 | }); | |
| 16004 | break :v try mod.intern(.{ .ptr = .{ | |
| 16005 | .ty = (try mod.ptrType(.{ | |
| 16006 | .child = param_info_ty.toIntern(), | |
| 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) | |
| 15915 | try Value.Tag.opt_payload.create( | |
| 15916 | sema.arena, | |
| 15917 | try Value.Tag.ty.create(sema.arena, info.return_type), | |
| 15918 | ) | |
| 15919 | else | |
| 15920 | Value.null; | |
| 16017 | const info = mod.typeToFunc(ty).?; | |
| 16018 | const ret_ty_opt = try mod.intern(.{ .opt = .{ | |
| 16019 | .ty = try ip.get(gpa, .{ .opt_type = .type_type }), | |
| 16020 | .val = if (info.return_type == .generic_poison_type) .none else info.return_type, | |
| 16021 | } }); | |
| 16022 | ||
| 16023 | const callconv_ty = try sema.getBuiltinType("CallingConvention"); | |
| 15921 | 16024 | |
| 15922 | const field_values = try sema.arena.create([6]Value); | |
| 15923 | field_values.* = .{ | |
| 16025 | const field_values = .{ | |
| 15924 | 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 | 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 | 16030 | // is_generic: bool, |
| 15929 | Value.makeBool(info.is_generic), | |
| 16031 | Value.makeBool(info.is_generic).toIntern(), | |
| 15930 | 16032 | // is_var_args: bool, |
| 15931 | Value.makeBool(info.is_var_args), | |
| 16033 | Value.makeBool(info.is_var_args).toIntern(), | |
| 15932 | 16034 | // return_type: ?type, |
| 15933 | 16035 | ret_ty_opt, |
| 15934 | 16036 | // args: []const Fn.Param, |
| 15935 | 16037 | args_val, |
| 15936 | 16038 | }; |
| 15937 | ||
| 15938 | return sema.addConstant( | |
| 15939 | type_info_ty, | |
| 15940 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15941 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Fn)), | |
| 15942 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 15943 | }), | |
| 15944 | ); | |
| 16039 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16040 | .ty = type_info_ty.toIntern(), | |
| 16041 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Fn))).toIntern(), | |
| 16042 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16043 | .ty = fn_info_ty.toIntern(), | |
| 16044 | .storage = .{ .elems = &field_values }, | |
| 16045 | } }), | |
| 16046 | } })).toValue()); | |
| 15945 | 16047 | }, |
| 15946 | 16048 | .Int => { |
| 15947 | const info = ty.intInfo(target); | |
| 15948 | const field_values = try sema.arena.alloc(Value, 2); | |
| 15949 | // signedness: Signedness, | |
| 15950 | field_values[0] = try Value.Tag.enum_field_index.create( | |
| 15951 | sema.arena, | |
| 15952 | @enumToInt(info.signedness), | |
| 15953 | ); | |
| 15954 | // bits: comptime_int, | |
| 15955 | field_values[1] = try Value.Tag.int_u64.create(sema.arena, info.bits); | |
| 15956 | ||
| 15957 | return sema.addConstant( | |
| 15958 | type_info_ty, | |
| 15959 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15960 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Int)), | |
| 15961 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 15962 | }), | |
| 15963 | ); | |
| 16049 | const int_info_decl_index = (try sema.namespaceLookup( | |
| 16050 | block, | |
| 16051 | src, | |
| 16052 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16053 | try ip.getOrPutString(gpa, "Int"), | |
| 16054 | )).?; | |
| 16055 | try mod.declareDeclDependency(sema.owner_decl_index, int_info_decl_index); | |
| 16056 | try sema.ensureDeclAnalyzed(int_info_decl_index); | |
| 16057 | const int_info_decl = mod.declPtr(int_info_decl_index); | |
| 16058 | const int_info_ty = int_info_decl.val.toType(); | |
| 16059 | ||
| 16060 | const signedness_ty = try sema.getBuiltinType("Signedness"); | |
| 16061 | const info = ty.intInfo(mod); | |
| 16062 | const field_values = .{ | |
| 16063 | // signedness: Signedness, | |
| 16064 | try (try mod.enumValueFieldIndex(signedness_ty, @enumToInt(info.signedness))).intern(signedness_ty, mod), | |
| 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 | 16077 | .Float => { |
| 15966 | const field_values = try sema.arena.alloc(Value, 1); | |
| 15967 | // bits: comptime_int, | |
| 15968 | field_values[0] = try Value.Tag.int_u64.create(sema.arena, ty.bitSize(target)); | |
| 15969 | ||
| 15970 | return sema.addConstant( | |
| 15971 | type_info_ty, | |
| 15972 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15973 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Float)), | |
| 15974 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 15975 | }), | |
| 15976 | ); | |
| 16078 | const float_info_decl_index = (try sema.namespaceLookup( | |
| 16079 | block, | |
| 16080 | src, | |
| 16081 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16082 | try ip.getOrPutString(gpa, "Float"), | |
| 16083 | )).?; | |
| 16084 | try mod.declareDeclDependency(sema.owner_decl_index, float_info_decl_index); | |
| 16085 | try sema.ensureDeclAnalyzed(float_info_decl_index); | |
| 16086 | const float_info_decl = mod.declPtr(float_info_decl_index); | |
| 16087 | const float_info_ty = float_info_decl.val.toType(); | |
| 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 | 16102 | .Pointer => { |
| 15979 | const info = ty.ptrInfo().data; | |
| 16103 | const info = ty.ptrInfo(mod); | |
| 15980 | 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 | 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); | |
| 15986 | field_values.* = .{ | |
| 16109 | const addrspace_ty = try sema.getBuiltinType("AddressSpace"); | |
| 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 | 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 | 16138 | // is_const: bool, |
| 15990 | Value.makeBool(!info.mutable), | |
| 16139 | Value.makeBool(!info.mutable).toIntern(), | |
| 15991 | 16140 | // is_volatile: bool, |
| 15992 | Value.makeBool(info.@"volatile"), | |
| 16141 | Value.makeBool(info.@"volatile").toIntern(), | |
| 15993 | 16142 | // alignment: comptime_int, |
| 15994 | alignment, | |
| 16143 | alignment.toIntern(), | |
| 15995 | 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 | 16146 | // child: type, |
| 15998 | try Value.Tag.ty.create(sema.arena, info.pointee_type), | |
| 16147 | info.pointee_type.toIntern(), | |
| 15999 | 16148 | // is_allowzero: bool, |
| 16000 | Value.makeBool(info.@"allowzero"), | |
| 16149 | Value.makeBool(info.@"allowzero").toIntern(), | |
| 16001 | 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 | ||
| 16005 | return sema.addConstant( | |
| 16006 | type_info_ty, | |
| 16007 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16008 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Pointer)), | |
| 16009 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16010 | }), | |
| 16011 | ); | |
| 16153 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16154 | .ty = type_info_ty.toIntern(), | |
| 16155 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Pointer))).toIntern(), | |
| 16156 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16157 | .ty = pointer_ty.toIntern(), | |
| 16158 | .storage = .{ .elems = &field_values }, | |
| 16159 | } }), | |
| 16160 | } })).toValue()); | |
| 16012 | 16161 | }, |
| 16013 | 16162 | .Array => { |
| 16014 | const info = ty.arrayInfo(); | |
| 16015 | const field_values = try sema.arena.alloc(Value, 3); | |
| 16016 | // len: comptime_int, | |
| 16017 | field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len); | |
| 16018 | // child: type, | |
| 16019 | field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type); | |
| 16020 | // sentinel: ?*const anyopaque, | |
| 16021 | field_values[2] = try sema.optRefValue(block, info.elem_type, info.sentinel); | |
| 16022 | ||
| 16023 | return sema.addConstant( | |
| 16024 | type_info_ty, | |
| 16025 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16026 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Array)), | |
| 16027 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16028 | }), | |
| 16029 | ); | |
| 16163 | const array_field_ty = t: { | |
| 16164 | const array_field_ty_decl_index = (try sema.namespaceLookup( | |
| 16165 | block, | |
| 16166 | src, | |
| 16167 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16168 | try ip.getOrPutString(gpa, "Array"), | |
| 16169 | )).?; | |
| 16170 | try mod.declareDeclDependency(sema.owner_decl_index, array_field_ty_decl_index); | |
| 16171 | try sema.ensureDeclAnalyzed(array_field_ty_decl_index); | |
| 16172 | const array_field_ty_decl = mod.declPtr(array_field_ty_decl_index); | |
| 16173 | break :t array_field_ty_decl.val.toType(); | |
| 16174 | }; | |
| 16175 | ||
| 16176 | const info = ty.arrayInfo(mod); | |
| 16177 | const field_values = .{ | |
| 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 | 16194 | .Vector => { |
| 16032 | const info = ty.arrayInfo(); | |
| 16033 | const field_values = try sema.arena.alloc(Value, 2); | |
| 16034 | // len: comptime_int, | |
| 16035 | field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len); | |
| 16036 | // child: type, | |
| 16037 | field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type); | |
| 16038 | ||
| 16039 | return sema.addConstant( | |
| 16040 | type_info_ty, | |
| 16041 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16042 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Vector)), | |
| 16043 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16044 | }), | |
| 16045 | ); | |
| 16195 | const vector_field_ty = t: { | |
| 16196 | const vector_field_ty_decl_index = (try sema.namespaceLookup( | |
| 16197 | block, | |
| 16198 | src, | |
| 16199 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16200 | try ip.getOrPutString(gpa, "Vector"), | |
| 16201 | )).?; | |
| 16202 | try mod.declareDeclDependency(sema.owner_decl_index, vector_field_ty_decl_index); | |
| 16203 | try sema.ensureDeclAnalyzed(vector_field_ty_decl_index); | |
| 16204 | const vector_field_ty_decl = mod.declPtr(vector_field_ty_decl_index); | |
| 16205 | break :t vector_field_ty_decl.val.toType(); | |
| 16206 | }; | |
| 16207 | ||
| 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 | 16224 | .Optional => { |
| 16048 | const field_values = try sema.arena.alloc(Value, 1); | |
| 16049 | // child: type, | |
| 16050 | field_values[0] = try Value.Tag.ty.create(sema.arena, try ty.optionalChildAlloc(sema.arena)); | |
| 16051 | ||
| 16052 | return sema.addConstant( | |
| 16053 | type_info_ty, | |
| 16054 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16055 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Optional)), | |
| 16056 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16057 | }), | |
| 16058 | ); | |
| 16225 | const optional_field_ty = t: { | |
| 16226 | const optional_field_ty_decl_index = (try sema.namespaceLookup( | |
| 16227 | block, | |
| 16228 | src, | |
| 16229 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16230 | try ip.getOrPutString(gpa, "Optional"), | |
| 16231 | )).?; | |
| 16232 | try mod.declareDeclDependency(sema.owner_decl_index, optional_field_ty_decl_index); | |
| 16233 | try sema.ensureDeclAnalyzed(optional_field_ty_decl_index); | |
| 16234 | const optional_field_ty_decl = mod.declPtr(optional_field_ty_decl_index); | |
| 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 | 16251 | .ErrorSet => { |
| 16061 | 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 | 16257 | const set_field_ty_decl_index = (try sema.namespaceLookup( |
| 16067 | 16258 | block, |
| 16068 | 16259 | src, |
| 16069 | type_info_ty.getNamespace().?, | |
| 16070 | "Error", | |
| 16260 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 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 | 16264 | try sema.ensureDeclAnalyzed(set_field_ty_decl_index); |
| 16074 | const set_field_ty_decl = sema.mod.declPtr(set_field_ty_decl_index); | |
| 16075 | var buffer: Value.ToTypeBuffer = undefined; | |
| 16076 | break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); | |
| 16265 | const set_field_ty_decl = mod.declPtr(set_field_ty_decl_index); | |
| 16266 | break :t set_field_ty_decl.val.toType(); | |
| 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 | 16271 | // If the error set is inferred it must be resolved at this point |
| 16082 | 16272 | try sema.resolveInferredErrorSetTy(block, src, ty); |
| ... | ... | @@ -16084,90 +16274,119 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16084 | 16274 | // Build our list of Error values |
| 16085 | 16275 | // Optional value is only null if anyerror |
| 16086 | 16276 | // Value can be zero-length slice otherwise |
| 16087 | const error_field_vals: ?[]Value = if (ty.isAnyError()) null else blk: { | |
| 16088 | const names = ty.errorSetNames(); | |
| 16089 | const vals = try fields_anon_decl.arena().alloc(Value, names.len); | |
| 16277 | const error_field_vals = if (ty.isAnyError(mod)) null else blk: { | |
| 16278 | const vals = try sema.arena.alloc(InternPool.Index, ty.errorSetNames(mod).len); | |
| 16090 | 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 | 16282 | const name_val = v: { |
| 16093 | 16283 | var anon_decl = try block.startAnonDecl(); |
| 16094 | 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 | 16289 | const new_decl = try anon_decl.finish( |
| 16097 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | |
| 16098 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 16290 | new_decl_ty, | |
| 16291 | (try mod.intern(.{ .aggregate = .{ | |
| 16292 | .ty = new_decl_ty.toIntern(), | |
| 16293 | .storage = .{ .bytes = name }, | |
| 16294 | } })).toValue(), | |
| 16099 | 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); | |
| 16105 | error_field_fields.* = .{ | |
| 16304 | const error_field_fields = .{ | |
| 16106 | 16305 | // name: []const u8, |
| 16107 | 16306 | name_val, |
| 16108 | 16307 | }; |
| 16109 | ||
| 16110 | field_val.* = try Value.Tag.aggregate.create( | |
| 16111 | fields_anon_decl.arena(), | |
| 16112 | error_field_fields, | |
| 16113 | ); | |
| 16308 | field_val.* = try mod.intern(.{ .aggregate = .{ | |
| 16309 | .ty = error_field_ty.toIntern(), | |
| 16310 | .storage = .{ .elems = &error_field_fields }, | |
| 16311 | } }); | |
| 16114 | 16312 | } |
| 16115 | 16313 | |
| 16116 | 16314 | break :blk vals; |
| 16117 | 16315 | }; |
| 16118 | 16316 | |
| 16119 | 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 | 16332 | const new_decl = try fields_anon_decl.finish( |
| 16122 | try Type.Tag.array.create(fields_anon_decl.arena(), .{ | |
| 16123 | .len = vals.len, | |
| 16124 | .elem_type = error_field_ty, | |
| 16125 | }), | |
| 16126 | try Value.Tag.aggregate.create( | |
| 16127 | fields_anon_decl.arena(), | |
| 16128 | vals, | |
| 16129 | ), | |
| 16333 | array_errors_ty, | |
| 16334 | (try mod.intern(.{ .aggregate = .{ | |
| 16335 | .ty = array_errors_ty.toIntern(), | |
| 16336 | .storage = .{ .elems = vals }, | |
| 16337 | } })).toValue(), | |
| 16130 | 16338 | 0, // default alignment |
| 16131 | 16339 | ); |
| 16132 | ||
| 16133 | const new_decl_val = try Value.Tag.decl_ref.create(sema.arena, new_decl); | |
| 16134 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | |
| 16135 | .ptr = new_decl_val, | |
| 16136 | .len = try Value.Tag.int_u64.create(sema.arena, vals.len), | |
| 16137 | }); | |
| 16138 | break :v try Value.Tag.opt_payload.create(sema.arena, slice_val); | |
| 16139 | } else Value.null; | |
| 16340 | break :v try mod.intern(.{ .ptr = .{ | |
| 16341 | .ty = slice_errors_ty.toIntern(), | |
| 16342 | .addr = .{ .decl = new_decl }, | |
| 16343 | .len = (try mod.intValue(Type.usize, vals.len)).toIntern(), | |
| 16344 | } }); | |
| 16345 | } else .none; | |
| 16346 | const errors_val = try mod.intern(.{ .opt = .{ | |
| 16347 | .ty = opt_slice_errors_ty.toIntern(), | |
| 16348 | .val = errors_payload_val, | |
| 16349 | } }); | |
| 16140 | 16350 | |
| 16141 | 16351 | // Construct Type{ .ErrorSet = errors_val } |
| 16142 | return sema.addConstant( | |
| 16143 | type_info_ty, | |
| 16144 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16145 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorSet)), | |
| 16146 | .val = errors_val, | |
| 16147 | }), | |
| 16148 | ); | |
| 16352 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16353 | .ty = type_info_ty.toIntern(), | |
| 16354 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorSet))).toIntern(), | |
| 16355 | .val = errors_val, | |
| 16356 | } })).toValue()); | |
| 16149 | 16357 | }, |
| 16150 | 16358 | .ErrorUnion => { |
| 16151 | const field_values = try sema.arena.alloc(Value, 2); | |
| 16152 | // error_set: type, | |
| 16153 | field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet()); | |
| 16154 | // payload: type, | |
| 16155 | field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload()); | |
| 16156 | ||
| 16157 | return sema.addConstant( | |
| 16158 | type_info_ty, | |
| 16159 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16160 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorUnion)), | |
| 16161 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16162 | }), | |
| 16163 | ); | |
| 16359 | const error_union_field_ty = t: { | |
| 16360 | const error_union_field_ty_decl_index = (try sema.namespaceLookup( | |
| 16361 | block, | |
| 16362 | src, | |
| 16363 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16364 | try ip.getOrPutString(gpa, "ErrorUnion"), | |
| 16365 | )).?; | |
| 16366 | try mod.declareDeclDependency(sema.owner_decl_index, error_union_field_ty_decl_index); | |
| 16367 | try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index); | |
| 16368 | const error_union_field_ty_decl = mod.declPtr(error_union_field_ty_decl_index); | |
| 16369 | break :t error_union_field_ty_decl.val.toType(); | |
| 16370 | }; | |
| 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 | 16387 | .Enum => { |
| 16166 | 16388 | // TODO: look into memoizing this result. |
| 16167 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | |
| 16168 | const int_tag_ty = try ty.intTagType(&int_tag_type_buffer).copy(sema.arena); | |
| 16169 | ||
| 16170 | const is_exhaustive = Value.makeBool(!ty.isNonexhaustiveEnum()); | |
| 16389 | const is_exhaustive = Value.makeBool(ip.indexToKey(ty.toIntern()).enum_type.tag_mode != .nonexhaustive); | |
| 16171 | 16390 | |
| 16172 | 16391 | var fields_anon_decl = try block.startAnonDecl(); |
| 16173 | 16392 | defer fields_anon_decl.deinit(); |
| ... | ... | @@ -16176,88 +16395,121 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16176 | 16395 | const enum_field_ty_decl_index = (try sema.namespaceLookup( |
| 16177 | 16396 | block, |
| 16178 | 16397 | src, |
| 16179 | type_info_ty.getNamespace().?, | |
| 16180 | "EnumField", | |
| 16398 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 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 | 16402 | try sema.ensureDeclAnalyzed(enum_field_ty_decl_index); |
| 16184 | const enum_field_ty_decl = sema.mod.declPtr(enum_field_ty_decl_index); | |
| 16185 | var buffer: Value.ToTypeBuffer = undefined; | |
| 16186 | break :t try enum_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); | |
| 16403 | const enum_field_ty_decl = mod.declPtr(enum_field_ty_decl_index); | |
| 16404 | break :t enum_field_ty_decl.val.toType(); | |
| 16187 | 16405 | }; |
| 16188 | 16406 | |
| 16189 | const enum_fields = ty.enumFields(); | |
| 16190 | const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_fields.count()); | |
| 16191 | ||
| 16407 | const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.indexToKey(ty.toIntern()).enum_type.names.len); | |
| 16192 | 16408 | for (enum_field_vals, 0..) |*field_val, i| { |
| 16193 | var tag_val_payload: Value.Payload.U32 = .{ | |
| 16194 | .base = .{ .tag = .enum_field_index }, | |
| 16195 | .data = @intCast(u32, i), | |
| 16196 | }; | |
| 16197 | const tag_val = Value.initPayload(&tag_val_payload.base); | |
| 16198 | ||
| 16199 | var buffer: Value.Payload.U64 = undefined; | |
| 16200 | const int_val = try tag_val.enumToInt(ty, &buffer).copy(fields_anon_decl.arena()); | |
| 16201 | ||
| 16202 | const name = enum_fields.keys()[i]; | |
| 16409 | const enum_type = ip.indexToKey(ty.toIntern()).enum_type; | |
| 16410 | const value_val = if (enum_type.values.len > 0) | |
| 16411 | try mod.intern_pool.getCoerced(gpa, enum_type.values[i], .comptime_int_type) | |
| 16412 | else | |
| 16413 | try mod.intern(.{ .int = .{ | |
| 16414 | .ty = .comptime_int_type, | |
| 16415 | .storage = .{ .u64 = @intCast(u64, i) }, | |
| 16416 | } }); | |
| 16417 | // TODO: write something like getCoercedInts to avoid needing to dupe | |
| 16418 | const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names[i])); | |
| 16203 | 16419 | const name_val = v: { |
| 16204 | 16420 | var anon_decl = try block.startAnonDecl(); |
| 16205 | 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 | 16426 | const new_decl = try anon_decl.finish( |
| 16208 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | |
| 16209 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 16427 | new_decl_ty, | |
| 16428 | (try mod.intern(.{ .aggregate = .{ | |
| 16429 | .ty = new_decl_ty.toIntern(), | |
| 16430 | .storage = .{ .bytes = name }, | |
| 16431 | } })).toValue(), | |
| 16210 | 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); | |
| 16216 | enum_field_fields.* = .{ | |
| 16441 | const enum_field_fields = .{ | |
| 16217 | 16442 | // name: []const u8, |
| 16218 | 16443 | name_val, |
| 16219 | 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 | 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 | 16459 | const new_decl = try fields_anon_decl.finish( |
| 16227 | try Type.Tag.array.create(fields_anon_decl.arena(), .{ | |
| 16228 | .len = enum_field_vals.len, | |
| 16229 | .elem_type = enum_field_ty, | |
| 16230 | }), | |
| 16231 | try Value.Tag.aggregate.create( | |
| 16232 | fields_anon_decl.arena(), | |
| 16233 | enum_field_vals, | |
| 16234 | ), | |
| 16460 | fields_array_ty, | |
| 16461 | (try mod.intern(.{ .aggregate = .{ | |
| 16462 | .ty = fields_array_ty.toIntern(), | |
| 16463 | .storage = .{ .elems = enum_field_vals }, | |
| 16464 | } })).toValue(), | |
| 16235 | 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); | |
| 16243 | field_values.* = .{ | |
| 16495 | const field_values = .{ | |
| 16244 | 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 | 16498 | // fields: []const EnumField, |
| 16247 | 16499 | fields_val, |
| 16248 | 16500 | // decls: []const Declaration, |
| 16249 | 16501 | decls_val, |
| 16250 | 16502 | // is_exhaustive: bool, |
| 16251 | is_exhaustive, | |
| 16503 | is_exhaustive.toIntern(), | |
| 16252 | 16504 | }; |
| 16253 | ||
| 16254 | return sema.addConstant( | |
| 16255 | type_info_ty, | |
| 16256 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16257 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Enum)), | |
| 16258 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16259 | }), | |
| 16260 | ); | |
| 16505 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16506 | .ty = type_info_ty.toIntern(), | |
| 16507 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Enum))).toIntern(), | |
| 16508 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16509 | .ty = type_enum_ty.toIntern(), | |
| 16510 | .storage = .{ .elems = &field_values }, | |
| 16511 | } }), | |
| 16512 | } })).toValue()); | |
| 16261 | 16513 | }, |
| 16262 | 16514 | .Union => { |
| 16263 | 16515 | // TODO: look into memoizing this result. |
| ... | ... | @@ -16265,91 +16517,135 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16265 | 16517 | var fields_anon_decl = try block.startAnonDecl(); |
| 16266 | 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 | 16533 | const union_field_ty = t: { |
| 16269 | 16534 | const union_field_ty_decl_index = (try sema.namespaceLookup( |
| 16270 | 16535 | block, |
| 16271 | 16536 | src, |
| 16272 | type_info_ty.getNamespace().?, | |
| 16273 | "UnionField", | |
| 16537 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 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 | 16541 | try sema.ensureDeclAnalyzed(union_field_ty_decl_index); |
| 16277 | const union_field_ty_decl = sema.mod.declPtr(union_field_ty_decl_index); | |
| 16278 | var buffer: Value.ToTypeBuffer = undefined; | |
| 16279 | break :t try union_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); | |
| 16542 | const union_field_ty_decl = mod.declPtr(union_field_ty_decl_index); | |
| 16543 | break :t union_field_ty_decl.val.toType(); | |
| 16280 | 16544 | }; |
| 16281 | 16545 | |
| 16282 | 16546 | const union_ty = try sema.resolveTypeFields(ty); |
| 16283 | 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(); | |
| 16287 | const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count()); | |
| 16550 | const union_fields = union_ty.unionFields(mod); | |
| 16551 | const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count()); | |
| 16552 | defer gpa.free(union_field_vals); | |
| 16288 | 16553 | |
| 16289 | 16554 | for (union_field_vals, 0..) |*field_val, i| { |
| 16290 | 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 | 16558 | const name_val = v: { |
| 16293 | 16559 | var anon_decl = try block.startAnonDecl(); |
| 16294 | 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 | 16565 | const new_decl = try anon_decl.finish( |
| 16297 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | |
| 16298 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 16566 | new_decl_ty, | |
| 16567 | (try mod.intern(.{ .aggregate = .{ | |
| 16568 | .ty = new_decl_ty.toIntern(), | |
| 16569 | .storage = .{ .bytes = name }, | |
| 16570 | } })).toValue(), | |
| 16299 | 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 | 16580 | const alignment = switch (layout) { |
| 16306 | 16581 | .Auto, .Extern => try sema.unionFieldAlignment(field), |
| 16307 | 16582 | .Packed => 0, |
| 16308 | 16583 | }; |
| 16309 | 16584 | |
| 16310 | union_field_fields.* = .{ | |
| 16585 | const union_field_fields = .{ | |
| 16311 | 16586 | // name: []const u8, |
| 16312 | 16587 | name_val, |
| 16313 | 16588 | // type: type, |
| 16314 | try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty), | |
| 16589 | field.ty.toIntern(), | |
| 16315 | 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 | 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 | 16605 | const new_decl = try fields_anon_decl.finish( |
| 16323 | try Type.Tag.array.create(fields_anon_decl.arena(), .{ | |
| 16324 | .len = union_field_vals.len, | |
| 16325 | .elem_type = union_field_ty, | |
| 16326 | }), | |
| 16327 | try Value.Tag.aggregate.create( | |
| 16328 | fields_anon_decl.arena(), | |
| 16329 | try fields_anon_decl.arena().dupe(Value, union_field_vals), | |
| 16330 | ), | |
| 16606 | array_fields_ty, | |
| 16607 | (try mod.intern(.{ .aggregate = .{ | |
| 16608 | .ty = array_fields_ty.toIntern(), | |
| 16609 | .storage = .{ .elems = union_field_vals }, | |
| 16610 | } })).toValue(), | |
| 16331 | 16611 | 0, // default alignment |
| 16332 | 16612 | ); |
| 16333 | break :v try Value.Tag.slice.create(sema.arena, .{ | |
| 16334 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16335 | .len = try Value.Tag.int_u64.create(sema.arena, union_field_vals.len), | |
| 16336 | }); | |
| 16613 | break :v try mod.intern(.{ .ptr = .{ | |
| 16614 | .ty = (try mod.ptrType(.{ | |
| 16615 | .child = union_field_ty.toIntern(), | |
| 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: { | |
| 16342 | const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty); | |
| 16343 | break :v try Value.Tag.opt_payload.create(sema.arena, ty_val); | |
| 16344 | } else Value.null; | |
| 16628 | const enum_tag_ty_val = try mod.intern(.{ .opt = .{ | |
| 16629 | .ty = (try mod.optionalType(.type_type)).toIntern(), | |
| 16630 | .val = if (union_ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none, | |
| 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); | |
| 16347 | field_values.* = .{ | |
| 16646 | const field_values = .{ | |
| 16348 | 16647 | // layout: ContainerLayout, |
| 16349 | try Value.Tag.enum_field_index.create( | |
| 16350 | sema.arena, | |
| 16351 | @enumToInt(layout), | |
| 16352 | ), | |
| 16648 | (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(), | |
| 16353 | 16649 | |
| 16354 | 16650 | // tag_type: ?type, |
| 16355 | 16651 | enum_tag_ty_val, |
| ... | ... | @@ -16358,14 +16654,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16358 | 16654 | // decls: []const Declaration, |
| 16359 | 16655 | decls_val, |
| 16360 | 16656 | }; |
| 16361 | ||
| 16362 | return sema.addConstant( | |
| 16363 | type_info_ty, | |
| 16364 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16365 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Union)), | |
| 16366 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16367 | }), | |
| 16368 | ); | |
| 16657 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16658 | .ty = type_info_ty.toIntern(), | |
| 16659 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Union))).toIntern(), | |
| 16660 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16661 | .ty = type_union_ty.toIntern(), | |
| 16662 | .storage = .{ .elems = &field_values }, | |
| 16663 | } }), | |
| 16664 | } })).toValue()); | |
| 16369 | 16665 | }, |
| 16370 | 16666 | .Struct => { |
| 16371 | 16667 | // TODO: look into memoizing this result. |
| ... | ... | @@ -16373,154 +16669,212 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16373 | 16669 | var fields_anon_decl = try block.startAnonDecl(); |
| 16374 | 16670 | defer fields_anon_decl.deinit(); |
| 16375 | 16671 | |
| 16376 | const struct_field_ty = t: { | |
| 16377 | const struct_field_ty_decl_index = (try sema.namespaceLookup( | |
| 16672 | const type_struct_ty = t: { | |
| 16673 | const type_struct_ty_decl_index = (try sema.namespaceLookup( | |
| 16378 | 16674 | block, |
| 16379 | 16675 | src, |
| 16380 | type_info_ty.getNamespace().?, | |
| 16381 | "StructField", | |
| 16676 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16677 | try ip.getOrPutString(gpa, "Struct"), | |
| 16382 | 16678 | )).?; |
| 16383 | try sema.mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index); | |
| 16384 | try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); | |
| 16385 | const struct_field_ty_decl = sema.mod.declPtr(struct_field_ty_decl_index); | |
| 16386 | var buffer: Value.ToTypeBuffer = undefined; | |
| 16387 | break :t try struct_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); | |
| 16679 | try mod.declareDeclDependency(sema.owner_decl_index, type_struct_ty_decl_index); | |
| 16680 | try sema.ensureDeclAnalyzed(type_struct_ty_decl_index); | |
| 16681 | const type_struct_ty_decl = mod.declPtr(type_struct_ty_decl_index); | |
| 16682 | break :t type_struct_ty_decl.val.toType(); | |
| 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); | |
| 16419 | const field_val = tuple.values[i]; | |
| 16420 | const is_comptime = field_val.tag() != .unreachable_value; | |
| 16421 | const opt_default_val = if (is_comptime) field_val else null; | |
| 16422 | const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val); | |
| 16423 | struct_field_fields.* = .{ | |
| 16424 | // name: []const u8, | |
| 16425 | name_val, | |
| 16426 | // type: type, | |
| 16427 | try Value.Tag.ty.create(fields_anon_decl.arena(), field_ty), | |
| 16428 | // default_value: ?*const anyopaque, | |
| 16429 | try default_val_ptr.copy(fields_anon_decl.arena()), | |
| 16430 | // is_comptime: bool, | |
| 16431 | Value.makeBool(is_comptime), | |
| 16432 | // alignment: comptime_int, | |
| 16433 | try field_ty.lazyAbiAlignment(target, fields_anon_decl.arena()), | |
| 16434 | }; | |
| 16435 | struct_field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); | |
| 16436 | } | |
| 16437 | break :fv struct_field_vals; | |
| 16438 | } | |
| 16439 | const struct_fields = struct_ty.structFields(); | |
| 16440 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count()); | |
| 16685 | const struct_field_ty = t: { | |
| 16686 | const struct_field_ty_decl_index = (try sema.namespaceLookup( | |
| 16687 | block, | |
| 16688 | src, | |
| 16689 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16690 | try ip.getOrPutString(gpa, "StructField"), | |
| 16691 | )).?; | |
| 16692 | try mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index); | |
| 16693 | try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); | |
| 16694 | const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index); | |
| 16695 | break :t struct_field_ty_decl.val.toType(); | |
| 16696 | }; | |
| 16697 | ||
| 16698 | const struct_ty = try sema.resolveTypeFields(ty); | |
| 16699 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout | |
| 16700 | const layout = struct_ty.containerLayout(mod); | |
| 16701 | ||
| 16702 | var struct_field_vals: []InternPool.Index = &.{}; | |
| 16703 | defer gpa.free(struct_field_vals); | |
| 16704 | fv: { | |
| 16705 | const struct_type = switch (ip.indexToKey(struct_ty.toIntern())) { | |
| 16706 | .anon_struct_type => |tuple| { | |
| 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| { | |
| 16443 | const field = struct_fields.values()[i]; | |
| 16444 | const name = struct_fields.keys()[i]; | |
| 16740 | const is_comptime = field_val != .none; | |
| 16741 | const opt_default_val = if (is_comptime) field_val.toValue() else null; | |
| 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 | 16775 | const name_val = v: { |
| 16446 | 16776 | var anon_decl = try block.startAnonDecl(); |
| 16447 | 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 | 16782 | const new_decl = try anon_decl.finish( |
| 16450 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | |
| 16451 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 16783 | new_decl_ty, | |
| 16784 | (try mod.intern(.{ .aggregate = .{ | |
| 16785 | .ty = new_decl_ty.toIntern(), | |
| 16786 | .storage = .{ .bytes = name }, | |
| 16787 | } })).toValue(), | |
| 16452 | 16788 | 0, // default alignment |
| 16453 | 16789 | ); |
| 16454 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ | |
| 16455 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | |
| 16456 | .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len), | |
| 16457 | }); | |
| 16790 | break :v try mod.intern(.{ .ptr = .{ | |
| 16791 | .ty = .slice_const_u8_type, | |
| 16792 | .addr = .{ .decl = new_decl }, | |
| 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); | |
| 16461 | const opt_default_val = if (field.default_val.tag() == .unreachable_value) | |
| 16797 | const opt_default_val = if (field.default_val == .none) | |
| 16462 | 16798 | null |
| 16463 | 16799 | else |
| 16464 | field.default_val; | |
| 16800 | field.default_val.toValue(); | |
| 16465 | 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 | 16805 | // name: []const u8, |
| 16470 | 16806 | name_val, |
| 16471 | 16807 | // type: type, |
| 16472 | try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty), | |
| 16808 | field.ty.toIntern(), | |
| 16473 | 16809 | // default_value: ?*const anyopaque, |
| 16474 | try default_val_ptr.copy(fields_anon_decl.arena()), | |
| 16810 | default_val_ptr.toIntern(), | |
| 16475 | 16811 | // is_comptime: bool, |
| 16476 | Value.makeBool(field.is_comptime), | |
| 16812 | Value.makeBool(field.is_comptime).toIntern(), | |
| 16477 | 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; | |
| 16483 | }; | |
| 16821 | } | |
| 16484 | 16822 | |
| 16485 | 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 | 16829 | const new_decl = try fields_anon_decl.finish( |
| 16487 | try Type.Tag.array.create(fields_anon_decl.arena(), .{ | |
| 16488 | .len = struct_field_vals.len, | |
| 16489 | .elem_type = struct_field_ty, | |
| 16490 | }), | |
| 16491 | try Value.Tag.aggregate.create( | |
| 16492 | fields_anon_decl.arena(), | |
| 16493 | try fields_anon_decl.arena().dupe(Value, struct_field_vals), | |
| 16494 | ), | |
| 16830 | array_fields_ty, | |
| 16831 | (try mod.intern(.{ .aggregate = .{ | |
| 16832 | .ty = array_fields_ty.toIntern(), | |
| 16833 | .storage = .{ .elems = struct_field_vals }, | |
| 16834 | } })).toValue(), | |
| 16495 | 16835 | 0, // default alignment |
| 16496 | 16836 | ); |
| 16497 | break :v try Value.Tag.slice.create(sema.arena, .{ | |
| 16498 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16499 | .len = try Value.Tag.int_u64.create(sema.arena, struct_field_vals.len), | |
| 16500 | }); | |
| 16837 | break :v try mod.intern(.{ .ptr = .{ | |
| 16838 | .ty = (try mod.ptrType(.{ | |
| 16839 | .child = struct_field_ty.toIntern(), | |
| 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: { | |
| 16506 | if (layout == .Packed) { | |
| 16507 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | |
| 16852 | const backing_integer_val = try mod.intern(.{ .opt = .{ | |
| 16853 | .ty = (try mod.optionalType(.type_type)).toIntern(), | |
| 16854 | .val = if (layout == .Packed) val: { | |
| 16855 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 16508 | 16856 | assert(struct_obj.haveLayout()); |
| 16509 | assert(struct_obj.backing_int_ty.isInt()); | |
| 16510 | const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty); | |
| 16511 | break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val); | |
| 16512 | } else { | |
| 16513 | break :blk Value.initTag(.null_value); | |
| 16514 | } | |
| 16857 | assert(struct_obj.backing_int_ty.isInt(mod)); | |
| 16858 | break :val struct_obj.backing_int_ty.toIntern(); | |
| 16859 | } else .none, | |
| 16860 | } }); | |
| 16861 | ||
| 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); | |
| 16518 | field_values.* = .{ | |
| 16875 | const field_values = [_]InternPool.Index{ | |
| 16519 | 16876 | // layout: ContainerLayout, |
| 16520 | try Value.Tag.enum_field_index.create( | |
| 16521 | sema.arena, | |
| 16522 | @enumToInt(layout), | |
| 16523 | ), | |
| 16877 | (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(), | |
| 16524 | 16878 | // backing_integer: ?type, |
| 16525 | 16879 | backing_integer_val, |
| 16526 | 16880 | // fields: []const StructField, |
| ... | ... | @@ -16528,36 +16882,48 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16528 | 16882 | // decls: []const Declaration, |
| 16529 | 16883 | decls_val, |
| 16530 | 16884 | // is_tuple: bool, |
| 16531 | Value.makeBool(struct_ty.isTuple()), | |
| 16885 | Value.makeBool(struct_ty.isTuple(mod)).toIntern(), | |
| 16532 | 16886 | }; |
| 16533 | ||
| 16534 | return sema.addConstant( | |
| 16535 | type_info_ty, | |
| 16536 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16537 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Struct)), | |
| 16538 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16539 | }), | |
| 16540 | ); | |
| 16887 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16888 | .ty = type_info_ty.toIntern(), | |
| 16889 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Struct))).toIntern(), | |
| 16890 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16891 | .ty = type_struct_ty.toIntern(), | |
| 16892 | .storage = .{ .elems = &field_values }, | |
| 16893 | } }), | |
| 16894 | } })).toValue()); | |
| 16541 | 16895 | }, |
| 16542 | 16896 | .Opaque => { |
| 16543 | 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 | 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); | |
| 16549 | field_values.* = .{ | |
| 16915 | const field_values = .{ | |
| 16550 | 16916 | // decls: []const Declaration, |
| 16551 | 16917 | decls_val, |
| 16552 | 16918 | }; |
| 16553 | ||
| 16554 | return sema.addConstant( | |
| 16555 | type_info_ty, | |
| 16556 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16557 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Opaque)), | |
| 16558 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16559 | }), | |
| 16560 | ); | |
| 16919 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16920 | .ty = type_info_ty.toIntern(), | |
| 16921 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Opaque))).toIntern(), | |
| 16922 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16923 | .ty = type_opaque_ty.toIntern(), | |
| 16924 | .storage = .{ .elems = &field_values }, | |
| 16925 | } }), | |
| 16926 | } })).toValue()); | |
| 16561 | 16927 | }, |
| 16562 | 16928 | .Frame => return sema.failWithUseOfAsync(block, src), |
| 16563 | 16929 | .AnyFrame => return sema.failWithUseOfAsync(block, src), |
| ... | ... | @@ -16569,8 +16935,11 @@ fn typeInfoDecls( |
| 16569 | 16935 | block: *Block, |
| 16570 | 16936 | src: LazySrcLoc, |
| 16571 | 16937 | type_info_ty: Type, |
| 16572 | opt_namespace: ?*Module.Namespace, | |
| 16573 | ) CompileError!Value { | |
| 16938 | opt_namespace: Module.Namespace.OptionalIndex, | |
| 16939 | ) CompileError!InternPool.Index { | |
| 16940 | const mod = sema.mod; | |
| 16941 | const gpa = sema.gpa; | |
| 16942 | ||
| 16574 | 16943 | var decls_anon_decl = try block.startAnonDecl(); |
| 16575 | 16944 | defer decls_anon_decl.deinit(); |
| 16576 | 16945 | |
| ... | ... | @@ -16578,89 +16947,110 @@ fn typeInfoDecls( |
| 16578 | 16947 | const declaration_ty_decl_index = (try sema.namespaceLookup( |
| 16579 | 16948 | block, |
| 16580 | 16949 | src, |
| 16581 | type_info_ty.getNamespace().?, | |
| 16582 | "Declaration", | |
| 16950 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 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 | 16954 | try sema.ensureDeclAnalyzed(declaration_ty_decl_index); |
| 16586 | const declaration_ty_decl = sema.mod.declPtr(declaration_ty_decl_index); | |
| 16587 | var buffer: Value.ToTypeBuffer = undefined; | |
| 16588 | break :t try declaration_ty_decl.val.toType(&buffer).copy(decls_anon_decl.arena()); | |
| 16955 | const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index); | |
| 16956 | break :t declaration_ty_decl.val.toType(); | |
| 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 | 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 | 16964 | defer seen_namespaces.deinit(); |
| 16597 | 16965 | |
| 16598 | if (opt_namespace) |some| { | |
| 16599 | try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), some, &decl_vals, &seen_namespaces); | |
| 16966 | if (opt_namespace.unwrap()) |namespace_index| { | |
| 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 | 16976 | const new_decl = try decls_anon_decl.finish( |
| 16603 | try Type.Tag.array.create(decls_anon_decl.arena(), .{ | |
| 16604 | .len = decl_vals.items.len, | |
| 16605 | .elem_type = declaration_ty, | |
| 16606 | }), | |
| 16607 | try Value.Tag.aggregate.create( | |
| 16608 | decls_anon_decl.arena(), | |
| 16609 | try decls_anon_decl.arena().dupe(Value, decl_vals.items), | |
| 16610 | ), | |
| 16977 | array_decl_ty, | |
| 16978 | (try mod.intern(.{ .aggregate = .{ | |
| 16979 | .ty = array_decl_ty.toIntern(), | |
| 16980 | .storage = .{ .elems = decl_vals.items }, | |
| 16981 | } })).toValue(), | |
| 16611 | 16982 | 0, // default alignment |
| 16612 | 16983 | ); |
| 16613 | return try Value.Tag.slice.create(sema.arena, .{ | |
| 16614 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16615 | .len = try Value.Tag.int_u64.create(sema.arena, decl_vals.items.len), | |
| 16616 | }); | |
| 16984 | return try mod.intern(.{ .ptr = .{ | |
| 16985 | .ty = (try mod.ptrType(.{ | |
| 16986 | .child = declaration_ty.toIntern(), | |
| 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 | 16997 | fn typeInfoNamespaceDecls( |
| 16620 | 16998 | sema: *Sema, |
| 16621 | 16999 | block: *Block, |
| 16622 | decls_anon_decl: Allocator, | |
| 16623 | 17000 | namespace: *Namespace, |
| 16624 | decl_vals: *std.ArrayList(Value), | |
| 17001 | declaration_ty: Type, | |
| 17002 | decl_vals: *std.ArrayList(InternPool.Index), | |
| 16625 | 17003 | seen_namespaces: *std.AutoHashMap(*Namespace, void), |
| 16626 | 17004 | ) !void { |
| 17005 | const mod = sema.mod; | |
| 17006 | const ip = &mod.intern_pool; | |
| 16627 | 17007 | const gop = try seen_namespaces.getOrPut(namespace); |
| 16628 | 17008 | if (gop.found_existing) return; |
| 16629 | 17009 | const decls = namespace.decls.keys(); |
| 16630 | 17010 | for (decls) |decl_index| { |
| 16631 | const decl = sema.mod.declPtr(decl_index); | |
| 17011 | const decl = mod.declPtr(decl_index); | |
| 16632 | 17012 | if (decl.kind == .@"usingnamespace") { |
| 16633 | 17013 | if (decl.analysis == .in_progress) continue; |
| 16634 | try sema.mod.ensureDeclAnalyzed(decl_index); | |
| 16635 | var buf: Value.ToTypeBuffer = undefined; | |
| 16636 | const new_ns = decl.val.toType(&buf).getNamespace().?; | |
| 16637 | try sema.typeInfoNamespaceDecls(block, decls_anon_decl, new_ns, decl_vals, seen_namespaces); | |
| 17014 | try mod.ensureDeclAnalyzed(decl_index); | |
| 17015 | const new_ns = decl.val.toType().getNamespace(mod).?; | |
| 17016 | try sema.typeInfoNamespaceDecls(block, new_ns, declaration_ty, decl_vals, seen_namespaces); | |
| 16638 | 17017 | continue; |
| 16639 | 17018 | } |
| 16640 | 17019 | if (decl.kind != .named) continue; |
| 16641 | 17020 | const name_val = v: { |
| 16642 | 17021 | var anon_decl = try block.startAnonDecl(); |
| 16643 | 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 | 17029 | const new_decl = try anon_decl.finish( |
| 16646 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | |
| 16647 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 17030 | new_decl_ty, | |
| 17031 | (try mod.intern(.{ .aggregate = .{ | |
| 17032 | .ty = new_decl_ty.toIntern(), | |
| 17033 | .storage = .{ .bytes = name }, | |
| 17034 | } })).toValue(), | |
| 16648 | 17035 | 0, // default alignment |
| 16649 | 17036 | ); |
| 16650 | break :v try Value.Tag.slice.create(decls_anon_decl, .{ | |
| 16651 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl, new_decl), | |
| 16652 | .len = try Value.Tag.int_u64.create(decls_anon_decl, bytes.len), | |
| 16653 | }); | |
| 17037 | break :v try mod.intern(.{ .ptr = .{ | |
| 17038 | .ty = .slice_const_u8_type, | |
| 17039 | .addr = .{ .decl = new_decl }, | |
| 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); | |
| 16657 | fields.* = .{ | |
| 17044 | const fields = .{ | |
| 16658 | 17045 | //name: []const u8, |
| 16659 | 17046 | name_val, |
| 16660 | 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 | 17085 | |
| 16696 | 17086 | const operand = try sema.resolveBody(&child_block, body, inst); |
| 16697 | 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 | 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 | 17099 | } |
| 16710 | 17100 | |
| 16711 | 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 | 17104 | .ComptimeInt => return Type.comptime_int, |
| 16714 | 17105 | .Int => { |
| 16715 | const bits = operand.bitSize(sema.mod.getTarget()); | |
| 17106 | const bits = operand.bitSize(mod); | |
| 16716 | 17107 | const count = if (bits == 0) |
| 16717 | 17108 | 0 |
| 16718 | 17109 | else blk: { |
| ... | ... | @@ -16723,14 +17114,14 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi |
| 16723 | 17114 | } |
| 16724 | 17115 | break :blk count; |
| 16725 | 17116 | }; |
| 16726 | return Module.makeIntType(sema.arena, .unsigned, count); | |
| 17117 | return mod.intType(.unsigned, count); | |
| 16727 | 17118 | }, |
| 16728 | 17119 | .Vector => { |
| 16729 | const elem_ty = operand.elemType2(); | |
| 17120 | const elem_ty = operand.elemType2(mod); | |
| 16730 | 17121 | const log2_elem_ty = try sema.log2IntType(block, elem_ty, src); |
| 16731 | return Type.Tag.vector.create(sema.arena, .{ | |
| 16732 | .len = operand.vectorLen(), | |
| 16733 | .elem_type = log2_elem_ty, | |
| 17122 | return mod.vectorType(.{ | |
| 17123 | .len = operand.vectorLen(mod), | |
| 17124 | .child = log2_elem_ty.toIntern(), | |
| 16734 | 17125 | }); |
| 16735 | 17126 | }, |
| 16736 | 17127 | else => {}, |
| ... | ... | @@ -16739,7 +17130,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi |
| 16739 | 17130 | block, |
| 16740 | 17131 | src, |
| 16741 | 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 | 17181 | const tracy = trace(@src()); |
| 16791 | 17182 | defer tracy.end(); |
| 16792 | 17183 | |
| 17184 | const mod = sema.mod; | |
| 16793 | 17185 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16794 | 17186 | const src = inst_data.src(); |
| 16795 | 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 | 17189 | |
| 16798 | 17190 | const operand = try sema.coerce(block, Type.bool, uncasted_operand, operand_src); |
| 16799 | 17191 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 16800 | return if (val.isUndef()) | |
| 17192 | return if (val.isUndef(mod)) | |
| 16801 | 17193 | sema.addConstUndef(Type.bool) |
| 16802 | 17194 | else if (val.toBool()) |
| 16803 | 17195 | Air.Inst.Ref.bool_false |
| ... | ... | @@ -16817,6 +17209,7 @@ fn zirBoolBr( |
| 16817 | 17209 | const tracy = trace(@src()); |
| 16818 | 17210 | defer tracy.end(); |
| 16819 | 17211 | |
| 17212 | const mod = sema.mod; | |
| 16820 | 17213 | const datas = sema.code.instructions.items(.data); |
| 16821 | 17214 | const inst_data = datas[inst].bool_br; |
| 16822 | 17215 | const lhs = try sema.resolveInst(inst_data.lhs); |
| ... | ... | @@ -16865,12 +17258,12 @@ fn zirBoolBr( |
| 16865 | 17258 | _ = try lhs_block.addBr(block_inst, lhs_result); |
| 16866 | 17259 | |
| 16867 | 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 | 17262 | _ = try rhs_block.addBr(block_inst, rhs_result); |
| 16870 | 17263 | } |
| 16871 | 17264 | |
| 16872 | 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 | 17267 | if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| { |
| 16875 | 17268 | if (is_bool_or and rhs_val.toBool()) { |
| 16876 | 17269 | return Air.Inst.Ref.bool_true; |
| ... | ... | @@ -16920,9 +17313,10 @@ fn finishCondBr( |
| 16920 | 17313 | } |
| 16921 | 17314 | |
| 16922 | 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 | 17318 | .Optional, .Null, .Undefined => return, |
| 16925 | .Pointer => if (ty.isPtrLikeOptional()) return, | |
| 17319 | .Pointer => if (ty.isPtrLikeOptional(mod)) return, | |
| 16926 | 17320 | else => {}, |
| 16927 | 17321 | } |
| 16928 | 17322 | return sema.failWithExpectedOptionalType(block, src, ty); |
| ... | ... | @@ -16951,10 +17345,11 @@ fn zirIsNonNullPtr( |
| 16951 | 17345 | const tracy = trace(@src()); |
| 16952 | 17346 | defer tracy.end(); |
| 16953 | 17347 | |
| 17348 | const mod = sema.mod; | |
| 16954 | 17349 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16955 | 17350 | const src = inst_data.src(); |
| 16956 | 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 | 17353 | if ((try sema.resolveMaybeUndefVal(ptr)) == null) { |
| 16959 | 17354 | return block.addUnOp(.is_non_null_ptr, ptr); |
| 16960 | 17355 | } |
| ... | ... | @@ -16963,10 +17358,11 @@ fn zirIsNonNullPtr( |
| 16963 | 17358 | } |
| 16964 | 17359 | |
| 16965 | 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 | 17363 | .ErrorSet, .ErrorUnion, .Undefined => return, |
| 16968 | 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 | 17382 | const tracy = trace(@src()); |
| 16987 | 17383 | defer tracy.end(); |
| 16988 | 17384 | |
| 17385 | const mod = sema.mod; | |
| 16989 | 17386 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16990 | 17387 | const src = inst_data.src(); |
| 16991 | 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 | 17390 | const loaded = try sema.analyzeLoad(block, src, ptr, src); |
| 16994 | 17391 | return sema.analyzeIsNonErr(block, src, loaded); |
| 16995 | 17392 | } |
| ... | ... | @@ -17012,6 +17409,7 @@ fn zirCondbr( |
| 17012 | 17409 | const tracy = trace(@src()); |
| 17013 | 17410 | defer tracy.end(); |
| 17014 | 17411 | |
| 17412 | const mod = sema.mod; | |
| 17015 | 17413 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17016 | 17414 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; |
| 17017 | 17415 | const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); |
| ... | ... | @@ -17052,8 +17450,8 @@ fn zirCondbr( |
| 17052 | 17450 | const err_inst_data = sema.code.instructions.items(.data)[index].un_node; |
| 17053 | 17451 | const err_operand = try sema.resolveInst(err_inst_data.operand); |
| 17054 | 17452 | const operand_ty = sema.typeOf(err_operand); |
| 17055 | assert(operand_ty.zigTypeTag() == .ErrorUnion); | |
| 17056 | const result_ty = operand_ty.errorUnionSet(); | |
| 17453 | assert(operand_ty.zigTypeTag(mod) == .ErrorUnion); | |
| 17454 | const result_ty = operand_ty.errorUnionSet(mod); | |
| 17057 | 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 | 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 | 17481 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17084 | 17482 | const src = inst_data.src(); |
| 17085 | 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 | 17485 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 17088 | 17486 | const err_union = try sema.resolveInst(extra.data.operand); |
| 17089 | 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 | 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 | 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 | 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 | 17527 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17129 | 17528 | const src = inst_data.src(); |
| 17130 | 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 | 17532 | const operand = try sema.resolveInst(extra.data.operand); |
| 17134 | 17533 | const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src); |
| 17135 | 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 | 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 | 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 | 17556 | _ = try sema.analyzeBodyInner(&sub_block, body); |
| 17157 | 17557 | |
| 17158 | 17558 | const operand_ty = sema.typeOf(operand); |
| 17159 | const ptr_info = operand_ty.ptrInfo().data; | |
| 17160 | const res_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 17161 | .pointee_type = err_union_ty.errorUnionPayload(), | |
| 17559 | const ptr_info = operand_ty.ptrInfo(mod); | |
| 17560 | const res_ty = try Type.ptr(sema.arena, mod, .{ | |
| 17561 | .pointee_type = err_union_ty.errorUnionPayload(mod), | |
| 17162 | 17562 | .@"addrspace" = ptr_info.@"addrspace", |
| 17163 | 17563 | .mutable = ptr_info.mutable, |
| 17164 | 17564 | .@"allowzero" = ptr_info.@"allowzero", |
| ... | ... | @@ -17254,16 +17654,17 @@ fn zirRetErrValue( |
| 17254 | 17654 | block: *Block, |
| 17255 | 17655 | inst: Zir.Inst.Index, |
| 17256 | 17656 | ) CompileError!Zir.Inst.Index { |
| 17657 | const mod = sema.mod; | |
| 17257 | 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 | 17661 | const src = inst_data.src(); |
| 17260 | ||
| 17261 | 17662 | // Return the error code from the function. |
| 17262 | const kv = try sema.mod.getErrorValue(err_name); | |
| 17263 | const result_inst = try sema.addConstant( | |
| 17264 | try Type.Tag.error_set_single.create(sema.arena, kv.key), | |
| 17265 | try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), | |
| 17266 | ); | |
| 17663 | const error_set_type = try mod.singleErrorSetType(err_name); | |
| 17664 | const result_inst = try sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ | |
| 17665 | .ty = error_set_type.toIntern(), | |
| 17666 | .name = err_name, | |
| 17667 | } })).toValue()); | |
| 17267 | 17668 | return sema.analyzeRet(block, result_inst, src); |
| 17268 | 17669 | } |
| 17269 | 17670 | |
| ... | ... | @@ -17275,16 +17676,17 @@ fn zirRetImplicit( |
| 17275 | 17676 | const tracy = trace(@src()); |
| 17276 | 17677 | defer tracy.end(); |
| 17277 | 17678 | |
| 17679 | const mod = sema.mod; | |
| 17278 | 17680 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; |
| 17279 | 17681 | const operand = try sema.resolveInst(inst_data.operand); |
| 17280 | 17682 | |
| 17281 | 17683 | const r_brace_src = inst_data.src(); |
| 17282 | 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 | 17686 | if (base_tag == .NoReturn) { |
| 17285 | 17687 | const msg = msg: { |
| 17286 | 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 | 17691 | errdefer msg.destroy(sema.gpa); |
| 17290 | 17692 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); |
| ... | ... | @@ -17294,7 +17696,7 @@ fn zirRetImplicit( |
| 17294 | 17696 | } else if (base_tag != .Void) { |
| 17295 | 17697 | const msg = msg: { |
| 17296 | 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 | 17701 | errdefer msg.destroy(sema.gpa); |
| 17300 | 17702 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); |
| ... | ... | @@ -17346,6 +17748,7 @@ fn retWithErrTracing( |
| 17346 | 17748 | ret_tag: Air.Inst.Tag, |
| 17347 | 17749 | operand: Air.Inst.Ref, |
| 17348 | 17750 | ) CompileError!Zir.Inst.Index { |
| 17751 | const mod = sema.mod; | |
| 17349 | 17752 | const need_check = switch (is_non_err) { |
| 17350 | 17753 | .bool_true => { |
| 17351 | 17754 | _ = try block.addUnOp(ret_tag, operand); |
| ... | ... | @@ -17357,7 +17760,7 @@ fn retWithErrTracing( |
| 17357 | 17760 | const gpa = sema.gpa; |
| 17358 | 17761 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 17359 | 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 | 17764 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 17362 | 17765 | const return_err_fn = try sema.getBuiltin("returnError"); |
| 17363 | 17766 | const args: [1]Air.Inst.Ref = .{err_return_trace}; |
| ... | ... | @@ -17397,17 +17800,19 @@ fn retWithErrTracing( |
| 17397 | 17800 | } |
| 17398 | 17801 | |
| 17399 | 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 | |
| 17403 | sema.mod.comp.bin_file.options.error_return_tracing; | |
| 17806 | return fn_ret_ty.isError(mod) and | |
| 17807 | mod.comp.bin_file.options.error_return_tracing; | |
| 17404 | 17808 | } |
| 17405 | 17809 | |
| 17406 | 17810 | fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 17811 | const mod = sema.mod; | |
| 17407 | 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; | |
| 17410 | if (!sema.mod.comp.bin_file.options.error_return_tracing) return; | |
| 17814 | if (!mod.backendSupportsFeature(.error_return_trace)) return; | |
| 17815 | if (!mod.comp.bin_file.options.error_return_tracing) return; | |
| 17411 | 17816 | |
| 17412 | 17817 | // This is only relevant at runtime. |
| 17413 | 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 | 17820 | const save_index = inst_data.operand == .none or b: { |
| 17416 | 17821 | const operand = try sema.resolveInst(inst_data.operand); |
| 17417 | 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 | 17826 | if (save_index) |
| ... | ... | @@ -17436,7 +17841,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) |
| 17436 | 17841 | const tracy = trace(@src()); |
| 17437 | 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 | 17845 | var block = start_block; |
| 17441 | 17846 | while (true) { |
| 17442 | 17847 | if (block.label) |label| { |
| ... | ... | @@ -17462,22 +17867,21 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) |
| 17462 | 17867 | |
| 17463 | 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 | 17871 | return sema.popErrorReturnTrace(start_block, src, operand, saved_index); |
| 17467 | 17872 | } |
| 17468 | 17873 | |
| 17469 | 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 | 17881 | const op_ty = sema.typeOf(uncasted_operand); |
| 17474 | switch (op_ty.zigTypeTag()) { | |
| 17475 | .ErrorSet => { | |
| 17476 | try payload.data.addErrorSet(sema.gpa, op_ty); | |
| 17477 | }, | |
| 17478 | .ErrorUnion => { | |
| 17479 | try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet()); | |
| 17480 | }, | |
| 17882 | switch (op_ty.zigTypeTag(mod)) { | |
| 17883 | .ErrorSet => try ies.addErrorSet(op_ty, ip, gpa), | |
| 17884 | .ErrorUnion => try ies.addErrorSet(op_ty.errorUnionSet(mod), ip, gpa), | |
| 17481 | 17885 | else => {}, |
| 17482 | 17886 | } |
| 17483 | 17887 | } |
| ... | ... | @@ -17492,7 +17896,8 @@ fn analyzeRet( |
| 17492 | 17896 | // Special case for returning an error to an inferred error set; we need to |
| 17493 | 17897 | // add the error tag to the inferred error set of the in-scope function, so |
| 17494 | 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 | 17901 | try sema.addToInferredErrorSet(uncasted_operand); |
| 17497 | 17902 | } |
| 17498 | 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 | 17945 | const tracy = trace(@src()); |
| 17541 | 17946 | defer tracy.end(); |
| 17542 | 17947 | |
| 17948 | const mod = sema.mod; | |
| 17543 | 17949 | const inst_data = sema.code.instructions.items(.data)[inst].ptr_type; |
| 17544 | 17950 | const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); |
| 17545 | 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 | 17958 | const elem_ty = blk: { |
| 17553 | 17959 | const air_inst = try sema.resolveInst(extra.data.elem_type); |
| 17554 | 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 | 17962 | try sema.errNote(block, elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); |
| 17557 | 17963 | } |
| 17558 | 17964 | return err; |
| 17559 | 17965 | }; |
| 17560 | if (ty.tag() == .generic_poison) return error.GenericPoison; | |
| 17966 | if (ty.isGenericPoison()) return error.GenericPoison; | |
| 17561 | 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 | 17975 | var extra_i = extra.end; |
| 17566 | 17976 | |
| 17567 | 17977 | const sentinel = if (inst_data.flags.has_sentinel) blk: { |
| 17568 | 17978 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); |
| 17569 | 17979 | extra_i += 1; |
| 17570 | break :blk (try sema.resolveInstConst(block, sentinel_src, ref, "pointer sentinel value must be comptime-known")).val; | |
| 17571 | } else null; | |
| 17980 | const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src); | |
| 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 | 17986 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); |
| 17575 | 17987 | extra_i += 1; |
| 17576 | 17988 | const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src); |
| 17577 | 17989 | const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime-known"); |
| 17578 | 17990 | // Check if this happens to be the lazy alignment of our element type, in |
| 17579 | 17991 | // which case we can make this 0 without resolving it. |
| 17580 | if (val.castTag(.lazy_align)) |payload| { | |
| 17581 | if (payload.data.eql(elem_ty, sema.mod)) { | |
| 17582 | break :blk 0; | |
| 17583 | } | |
| 17992 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 17993 | .int => |int| switch (int.storage) { | |
| 17994 | .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.toIntern()) break :blk .none, | |
| 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 | 18000 | try sema.validateAlign(block, align_src, abi_align); |
| 17587 | break :blk abi_align; | |
| 17588 | } else 0; | |
| 18001 | break :blk InternPool.Alignment.fromByteUnits(abi_align); | |
| 18002 | } else .none; | |
| 17589 | 18003 | |
| 17590 | 18004 | const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: { |
| 17591 | 18005 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); |
| 17592 | 18006 | extra_i += 1; |
| 17593 | 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 | 18010 | const bit_offset = if (inst_data.flags.has_bit_range) blk: { |
| 17597 | 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 | 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) { | |
| 17615 | return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); | |
| 17616 | } else if (elem_ty.zigTypeTag() == .Fn) { | |
| 18028 | if (elem_ty.zigTypeTag(mod) == .Fn) { | |
| 17617 | 18029 | if (inst_data.size != .One) { |
| 17618 | 18030 | return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); |
| 17619 | 18031 | } |
| 17620 | const fn_align = elem_ty.fnInfo().alignment; | |
| 17621 | if (inst_data.flags.has_align and abi_align != 0 and fn_align != 0 and | |
| 18032 | const fn_align = mod.typeToFunc(elem_ty).?.alignment; | |
| 18033 | if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and | |
| 17622 | 18034 | abi_align != fn_align) |
| 17623 | 18035 | { |
| 17624 | 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 | 18039 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); |
| 17628 | 18040 | } else if (inst_data.size == .C) { |
| 17629 | 18041 | if (!try sema.validateExternType(elem_ty, .other)) { |
| 17630 | 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 | 18044 | errdefer msg.destroy(sema.gpa); |
| 17633 | 18045 | |
| 17634 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 17635 | try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl), elem_ty, .other); | |
| 18046 | const src_decl = mod.declPtr(block.src_decl); | |
| 18047 | try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl, mod), elem_ty, .other); | |
| 17636 | 18048 | |
| 17637 | 18049 | try sema.addDeclaredHereNote(msg, elem_ty); |
| 17638 | 18050 | break :msg msg; |
| 17639 | 18051 | }; |
| 17640 | 18052 | return sema.failWithOwnedErrorMsg(msg); |
| 17641 | 18053 | } |
| 17642 | if (elem_ty.zigTypeTag() == .Opaque) { | |
| 18054 | if (elem_ty.zigTypeTag(mod) == .Opaque) { | |
| 17643 | 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, .{ | |
| 17648 | .pointee_type = elem_ty, | |
| 18059 | const ty = try mod.ptrType(.{ | |
| 18060 | .child = elem_ty.toIntern(), | |
| 17649 | 18061 | .sentinel = sentinel, |
| 17650 | .@"align" = abi_align, | |
| 17651 | .@"addrspace" = address_space, | |
| 17652 | .bit_offset = bit_offset, | |
| 17653 | .host_size = host_size, | |
| 17654 | .mutable = inst_data.flags.is_mutable, | |
| 17655 | .@"allowzero" = inst_data.flags.is_allowzero, | |
| 17656 | .@"volatile" = inst_data.flags.is_volatile, | |
| 17657 | .size = inst_data.size, | |
| 18062 | .flags = .{ | |
| 18063 | .alignment = abi_align, | |
| 18064 | .address_space = address_space, | |
| 18065 | .is_const = !inst_data.flags.is_mutable, | |
| 18066 | .is_allowzero = inst_data.flags.is_allowzero, | |
| 18067 | .is_volatile = inst_data.flags.is_volatile, | |
| 18068 | .size = inst_data.size, | |
| 18069 | }, | |
| 18070 | .packed_offset = .{ | |
| 18071 | .bit_offset = bit_offset, | |
| 18072 | .host_size = host_size, | |
| 18073 | }, | |
| 17658 | 18074 | }); |
| 17659 | 18075 | return sema.addType(ty); |
| 17660 | 18076 | } |
| ... | ... | @@ -17666,8 +18082,9 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 17666 | 18082 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 17667 | 18083 | const src = inst_data.src(); |
| 17668 | 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 | 18088 | .Struct => return sema.structInitEmpty(block, obj_ty, src, src), |
| 17672 | 18089 | .Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty), |
| 17673 | 18090 | .Void => return sema.addConstant(obj_ty, Value.void), |
| ... | ... | @@ -17683,12 +18100,13 @@ fn structInitEmpty( |
| 17683 | 18100 | dest_src: LazySrcLoc, |
| 17684 | 18101 | init_src: LazySrcLoc, |
| 17685 | 18102 | ) CompileError!Air.Inst.Ref { |
| 18103 | const mod = sema.mod; | |
| 17686 | 18104 | const gpa = sema.gpa; |
| 17687 | 18105 | // This logic must be synchronized with that in `zirStructInit`. |
| 17688 | 18106 | const struct_ty = try sema.resolveTypeFields(obj_ty); |
| 17689 | 18107 | |
| 17690 | 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 | 18110 | defer gpa.free(field_inits); |
| 17693 | 18111 | @memset(field_inits, .none); |
| 17694 | 18112 | |
| ... | ... | @@ -17696,20 +18114,19 @@ fn structInitEmpty( |
| 17696 | 18114 | } |
| 17697 | 18115 | |
| 17698 | 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 | 18119 | if (arr_len != 0) { |
| 17701 | if (obj_ty.zigTypeTag() == .Array) { | |
| 18120 | if (obj_ty.zigTypeTag(mod) == .Array) { | |
| 17702 | 18121 | return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len}); |
| 17703 | 18122 | } else { |
| 17704 | 18123 | return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len}); |
| 17705 | 18124 | } |
| 17706 | 18125 | } |
| 17707 | if (obj_ty.sentinel()) |sentinel| { | |
| 17708 | const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel); | |
| 17709 | return sema.addConstant(obj_ty, val); | |
| 17710 | } else { | |
| 17711 | return sema.addConstant(obj_ty, Value.initTag(.empty_array)); | |
| 17712 | } | |
| 18126 | return sema.addConstant(obj_ty, (try mod.intern(.{ .aggregate = .{ | |
| 18127 | .ty = obj_ty.toIntern(), | |
| 18128 | .storage = .{ .elems = &.{} }, | |
| 18129 | } })).toValue()); | |
| 17713 | 18130 | } |
| 17714 | 18131 | |
| 17715 | 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 | 18136 | const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 17720 | 18137 | const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; |
| 17721 | 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 | 18140 | const init = try sema.resolveInst(extra.init); |
| 17724 | 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 | 18148 | init_src: LazySrcLoc, |
| 17732 | 18149 | union_ty: Type, |
| 17733 | 18150 | union_ty_src: LazySrcLoc, |
| 17734 | field_name: []const u8, | |
| 18151 | field_name: InternPool.NullTerminatedString, | |
| 17735 | 18152 | field_src: LazySrcLoc, |
| 17736 | 18153 | ) CompileError!Air.Inst.Ref { |
| 18154 | const mod = sema.mod; | |
| 17737 | 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 | 18157 | const init = try sema.coerce(block, field.ty, uncasted_init, init_src); |
| 17740 | 18158 | |
| 17741 | 18159 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { |
| 17742 | const tag_ty = union_ty.unionTagTypeHypothetical(); | |
| 17743 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); | |
| 17744 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | |
| 17745 | return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{ | |
| 17746 | .tag = tag_val, | |
| 17747 | .val = init_val, | |
| 17748 | })); | |
| 18160 | const tag_ty = union_ty.unionTagTypeHypothetical(mod); | |
| 18161 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); | |
| 18162 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); | |
| 18163 | return sema.addConstant(union_ty, (try mod.intern(.{ .un = .{ | |
| 18164 | .ty = union_ty.toIntern(), | |
| 18165 | .tag = try tag_val.intern(tag_ty, mod), | |
| 18166 | .val = try init_val.intern(field.ty, mod), | |
| 18167 | } })).toValue()); | |
| 17749 | 18168 | } |
| 17750 | 18169 | |
| 17751 | 18170 | try sema.requireRuntimeBlock(block, init_src, null); |
| ... | ... | @@ -17766,29 +18185,30 @@ fn zirStructInit( |
| 17766 | 18185 | const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); |
| 17767 | 18186 | const src = inst_data.src(); |
| 17768 | 18187 | |
| 18188 | const mod = sema.mod; | |
| 17769 | 18189 | const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; |
| 17770 | 18190 | const first_field_type_data = zir_datas[first_item.field_type].pl_node; |
| 17771 | 18191 | const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; |
| 17772 | 18192 | const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type); |
| 17773 | 18193 | try sema.resolveTypeLayout(resolved_ty); |
| 17774 | 18194 | |
| 17775 | if (resolved_ty.zigTypeTag() == .Struct) { | |
| 18195 | if (resolved_ty.zigTypeTag(mod) == .Struct) { | |
| 17776 | 18196 | // This logic must be synchronized with that in `zirStructInitEmpty`. |
| 17777 | 18197 | |
| 17778 | 18198 | // Maps field index to field_type index of where it was already initialized. |
| 17779 | 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 | 18201 | defer gpa.free(found_fields); |
| 17782 | 18202 | |
| 17783 | 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 | 18205 | defer gpa.free(field_inits); |
| 17786 | 18206 | @memset(field_inits, .none); |
| 17787 | 18207 | |
| 17788 | 18208 | var field_i: u32 = 0; |
| 17789 | 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 | 18212 | while (field_i < extra.data.fields_len) : (field_i += 1) { |
| 17793 | 18213 | const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index); |
| 17794 | 18214 | extra_index = item.end; |
| ... | ... | @@ -17796,8 +18216,8 @@ fn zirStructInit( |
| 17796 | 18216 | const field_type_data = zir_datas[item.data.field_type].pl_node; |
| 17797 | 18217 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; |
| 17798 | 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); | |
| 17800 | const field_index = if (resolved_ty.isTuple()) | |
| 18219 | const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start)); | |
| 18220 | const field_index = if (resolved_ty.isTuple(mod)) | |
| 17801 | 18221 | try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src) |
| 17802 | 18222 | else |
| 17803 | 18223 | try sema.structFieldIndex(block, resolved_ty, field_name, field_src); |
| ... | ... | @@ -17815,19 +18235,19 @@ fn zirStructInit( |
| 17815 | 18235 | } |
| 17816 | 18236 | found_fields[field_index] = item.data.field_type; |
| 17817 | 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 | 18239 | const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse { |
| 17820 | 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 | 18244 | return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index); |
| 17825 | 18245 | } |
| 17826 | 18246 | }; |
| 17827 | 18247 | } |
| 17828 | 18248 | |
| 17829 | 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 | 18251 | if (extra.data.fields_len != 1) { |
| 17832 | 18252 | return sema.fail(block, src, "union initialization expects exactly one field", .{}); |
| 17833 | 18253 | } |
| ... | ... | @@ -17837,32 +18257,32 @@ fn zirStructInit( |
| 17837 | 18257 | const field_type_data = zir_datas[item.data.field_type].pl_node; |
| 17838 | 18258 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; |
| 17839 | 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 | 18261 | const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src); |
| 17842 | const tag_ty = resolved_ty.unionTagTypeHypothetical(); | |
| 17843 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); | |
| 17844 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | |
| 18262 | const tag_ty = resolved_ty.unionTagTypeHypothetical(mod); | |
| 18263 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); | |
| 18264 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); | |
| 17845 | 18265 | |
| 17846 | 18266 | const init_inst = try sema.resolveInst(item.data.init); |
| 17847 | 18267 | if (try sema.resolveMaybeUndefVal(init_inst)) |val| { |
| 17848 | return sema.addConstantMaybeRef( | |
| 17849 | block, | |
| 17850 | resolved_ty, | |
| 17851 | try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = val }), | |
| 17852 | is_ref, | |
| 17853 | ); | |
| 18268 | const field = resolved_ty.unionFields(mod).values()[field_index]; | |
| 18269 | return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{ | |
| 18270 | .ty = resolved_ty.toIntern(), | |
| 18271 | .tag = try tag_val.intern(tag_ty, mod), | |
| 18272 | .val = try val.intern(field.ty, mod), | |
| 18273 | } })).toValue(), is_ref); | |
| 17854 | 18274 | } |
| 17855 | 18275 | |
| 17856 | 18276 | if (is_ref) { |
| 17857 | const target = sema.mod.getTarget(); | |
| 17858 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 18277 | const target = mod.getTarget(); | |
| 18278 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ | |
| 17859 | 18279 | .pointee_type = resolved_ty, |
| 17860 | 18280 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 17861 | 18281 | }); |
| 17862 | 18282 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 17863 | 18283 | const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true); |
| 17864 | 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 | 18286 | _ = try block.addBinOp(.set_union_tag, alloc, new_tag); |
| 17867 | 18287 | return sema.makePtrConst(block, alloc); |
| 17868 | 18288 | } |
| ... | ... | @@ -17870,7 +18290,7 @@ fn zirStructInit( |
| 17870 | 18290 | try sema.requireRuntimeBlock(block, src, null); |
| 17871 | 18291 | try sema.queueFullTypeResolution(resolved_ty); |
| 17872 | 18292 | return block.addUnionInit(resolved_ty, field_index, init_inst); |
| 17873 | } else if (resolved_ty.isAnonStruct()) { | |
| 18293 | } else if (resolved_ty.isAnonStruct(mod)) { | |
| 17874 | 18294 | return sema.fail(block, src, "TODO anon struct init validation", .{}); |
| 17875 | 18295 | } |
| 17876 | 18296 | unreachable; |
| ... | ... | @@ -17885,76 +18305,70 @@ fn finishStructInit( |
| 17885 | 18305 | struct_ty: Type, |
| 17886 | 18306 | is_ref: bool, |
| 17887 | 18307 | ) CompileError!Air.Inst.Ref { |
| 17888 | const gpa = sema.gpa; | |
| 18308 | const mod = sema.mod; | |
| 18309 | const ip = &mod.intern_pool; | |
| 17889 | 18310 | |
| 17890 | 18311 | var root_msg: ?*Module.ErrorMsg = null; |
| 17891 | 18312 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 17892 | 18313 | |
| 17893 | if (struct_ty.isAnonStruct()) { | |
| 17894 | const struct_obj = struct_ty.castTag(.anon_struct).?.data; | |
| 17895 | for (struct_obj.values, 0..) |default_val, i| { | |
| 17896 | 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; | |
| 18314 | switch (ip.indexToKey(struct_ty.toIntern())) { | |
| 18315 | .anon_struct_type => |anon_struct| { | |
| 18316 | for (anon_struct.types, anon_struct.values, 0..) |field_ty, default_val, i| { | |
| 18317 | if (field_inits[i] != .none) continue; | |
| 17916 | 18318 | |
| 17917 | const default_val = struct_ty.structFieldDefaultValue(i); | |
| 17918 | if (default_val.tag() == .unreachable_value) { | |
| 17919 | const template = "missing tuple field with index {d}"; | |
| 17920 | if (root_msg) |msg| { | |
| 17921 | try sema.errNote(block, init_src, msg, template, .{i}); | |
| 18319 | if (default_val == .none) { | |
| 18320 | if (anon_struct.names.len == 0) { | |
| 18321 | const template = "missing tuple field with index {d}"; | |
| 18322 | if (root_msg) |msg| { | |
| 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 | 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 | } | |
| 17929 | } else { | |
| 17930 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | |
| 17931 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 17932 | if (field_inits[i] != .none) continue; | |
| 18341 | }, | |
| 18342 | .struct_type => |struct_type| { | |
| 18343 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 18344 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 18345 | if (field_inits[i] != .none) continue; | |
| 17933 | 18346 | |
| 17934 | if (field.default_val.tag() == .unreachable_value) { | |
| 17935 | const field_name = struct_obj.fields.keys()[i]; | |
| 17936 | const template = "missing struct field: {s}"; | |
| 17937 | const args = .{field_name}; | |
| 17938 | if (root_msg) |msg| { | |
| 17939 | try sema.errNote(block, init_src, msg, template, args); | |
| 18347 | if (field.default_val == .none) { | |
| 18348 | const field_name = struct_obj.fields.keys()[i]; | |
| 18349 | const template = "missing struct field: {}"; | |
| 18350 | const args = .{field_name.fmt(ip)}; | |
| 18351 | if (root_msg) |msg| { | |
| 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 | 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 | 18364 | if (root_msg) |msg| { |
| 17950 | if (struct_ty.castTag(.@"struct")) |struct_obj| { | |
| 17951 | const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); | |
| 17952 | defer gpa.free(fqn); | |
| 17953 | try sema.mod.errNoteNonLazy( | |
| 17954 | struct_obj.data.srcLoc(sema.mod), | |
| 18365 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | |
| 18366 | const fqn = try struct_obj.getFullyQualifiedName(mod); | |
| 18367 | try mod.errNoteNonLazy( | |
| 18368 | struct_obj.srcLoc(mod), | |
| 17955 | 18369 | msg, |
| 17956 | "struct '{s}' declared here", | |
| 17957 | .{fqn}, | |
| 18370 | "struct '{}' declared here", | |
| 18371 | .{fqn.fmt(ip)}, | |
| 17958 | 18372 | ); |
| 17959 | 18373 | } |
| 17960 | 18374 | root_msg = null; |
| ... | ... | @@ -17969,18 +18383,22 @@ fn finishStructInit( |
| 17969 | 18383 | } else null; |
| 17970 | 18384 | |
| 17971 | 18385 | const runtime_index = opt_runtime_index orelse { |
| 17972 | const values = try sema.arena.alloc(Value, field_inits.len); | |
| 17973 | for (field_inits, 0..) |field_init, i| { | |
| 17974 | values[i] = (sema.resolveMaybeUndefVal(field_init) catch unreachable).?; | |
| 17975 | } | |
| 17976 | const struct_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 17977 | return sema.addConstantMaybeRef(block, struct_ty, struct_val, is_ref); | |
| 18386 | const elems = try sema.arena.alloc(InternPool.Index, field_inits.len); | |
| 18387 | for (elems, field_inits, 0..) |*elem, field_init, field_i| { | |
| 18388 | elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).? | |
| 18389 | .intern(struct_ty.structFieldType(field_i, mod), mod); | |
| 18390 | } | |
| 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 | 18398 | if (is_ref) { |
| 17981 | 18399 | try sema.resolveStructLayout(struct_ty); |
| 17982 | 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 | 18402 | .pointee_type = struct_ty, |
| 17985 | 18403 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 17986 | 18404 | }); |
| ... | ... | @@ -17997,8 +18415,8 @@ fn finishStructInit( |
| 17997 | 18415 | |
| 17998 | 18416 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| 17999 | 18417 | error.NeededSourceLocation => { |
| 18000 | const decl = sema.mod.declPtr(block.src_decl); | |
| 18001 | const field_src = Module.initSrc(dest_src.node_offset.x, sema.gpa, decl, runtime_index); | |
| 18418 | const decl = mod.declPtr(block.src_decl); | |
| 18419 | const field_src = mod.initSrc(dest_src.node_offset.x, decl, runtime_index); | |
| 18002 | 18420 | try sema.requireRuntimeBlock(block, dest_src, field_src); |
| 18003 | 18421 | unreachable; |
| 18004 | 18422 | }, |
| ... | ... | @@ -18014,79 +18432,85 @@ fn zirStructInitAnon( |
| 18014 | 18432 | inst: Zir.Inst.Index, |
| 18015 | 18433 | is_ref: bool, |
| 18016 | 18434 | ) CompileError!Air.Inst.Ref { |
| 18435 | const mod = sema.mod; | |
| 18436 | const gpa = sema.gpa; | |
| 18017 | 18437 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 18018 | 18438 | const src = inst_data.src(); |
| 18019 | 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); | |
| 18021 | const values = try sema.arena.alloc(Value, types.len); | |
| 18022 | var fields = std.StringArrayHashMapUnmanaged(u32){}; | |
| 18023 | defer fields.deinit(sema.gpa); | |
| 18024 | try fields.ensureUnusedCapacity(sema.gpa, types.len); | |
| 18440 | const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len); | |
| 18441 | const values = try sema.arena.alloc(InternPool.Index, types.len); | |
| 18442 | var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); | |
| 18443 | try fields.ensureUnusedCapacity(types.len); | |
| 18025 | 18444 | |
| 18026 | 18445 | // Find which field forces the expression to be runtime, if any. |
| 18027 | 18446 | const opt_runtime_index = rs: { |
| 18028 | 18447 | var runtime_index: ?usize = null; |
| 18029 | 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 | 18451 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 18032 | 18452 | extra_index = item.end; |
| 18033 | 18453 | |
| 18034 | 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 | 18457 | if (gop.found_existing) { |
| 18037 | 18458 | const msg = msg: { |
| 18038 | const decl = sema.mod.declPtr(block.src_decl); | |
| 18039 | const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i); | |
| 18459 | const decl = mod.declPtr(block.src_decl); | |
| 18460 | const field_src = mod.initSrc(src.node_offset.x, decl, i); | |
| 18040 | 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 | 18465 | try sema.errNote(block, prev_source, msg, "other field here", .{}); |
| 18045 | 18466 | break :msg msg; |
| 18046 | 18467 | }; |
| 18047 | 18468 | return sema.failWithOwnedErrorMsg(msg); |
| 18048 | 18469 | } |
| 18049 | gop.value_ptr.* = @intCast(u32, i); | |
| 18470 | gop.value_ptr.* = i; | |
| 18050 | 18471 | |
| 18051 | 18472 | const init = try sema.resolveInst(item.data.init); |
| 18052 | field_ty.* = sema.typeOf(init); | |
| 18053 | if (types[i].zigTypeTag() == .Opaque) { | |
| 18473 | field_ty.* = sema.typeOf(init).toIntern(); | |
| 18474 | if (field_ty.toType().zigTypeTag(mod) == .Opaque) { | |
| 18054 | 18475 | const msg = msg: { |
| 18055 | const decl = sema.mod.declPtr(block.src_decl); | |
| 18056 | const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i); | |
| 18476 | const decl = mod.declPtr(block.src_decl); | |
| 18477 | const field_src = mod.initSrc(src.node_offset.x, decl, i); | |
| 18057 | 18478 | const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18058 | 18479 | errdefer msg.destroy(sema.gpa); |
| 18059 | 18480 | |
| 18060 | try sema.addDeclaredHereNote(msg, types[i]); | |
| 18481 | try sema.addDeclaredHereNote(msg, field_ty.toType()); | |
| 18061 | 18482 | break :msg msg; |
| 18062 | 18483 | }; |
| 18063 | 18484 | return sema.failWithOwnedErrorMsg(msg); |
| 18064 | 18485 | } |
| 18065 | 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 | 18488 | } else { |
| 18068 | values[i] = Value.initTag(.unreachable_value); | |
| 18489 | values[i] = .none; | |
| 18069 | 18490 | runtime_index = i; |
| 18070 | 18491 | } |
| 18071 | 18492 | } |
| 18072 | 18493 | break :rs runtime_index; |
| 18073 | 18494 | }; |
| 18074 | 18495 | |
| 18075 | const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{ | |
| 18076 | .names = try sema.arena.dupe([]const u8, fields.keys()), | |
| 18496 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ | |
| 18497 | .names = fields.keys(), | |
| 18077 | 18498 | .types = types, |
| 18078 | 18499 | .values = values, |
| 18079 | }); | |
| 18500 | } }); | |
| 18080 | 18501 | |
| 18081 | 18502 | const runtime_index = opt_runtime_index orelse { |
| 18082 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 18083 | return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref); | |
| 18503 | const tuple_val = try mod.intern(.{ .aggregate = .{ | |
| 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 | 18510 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| 18087 | 18511 | error.NeededSourceLocation => { |
| 18088 | const decl = sema.mod.declPtr(block.src_decl); | |
| 18089 | const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index); | |
| 18512 | const decl = mod.declPtr(block.src_decl); | |
| 18513 | const field_src = mod.initSrc(src.node_offset.x, decl, runtime_index); | |
| 18090 | 18514 | try sema.requireRuntimeBlock(block, src, field_src); |
| 18091 | 18515 | unreachable; |
| 18092 | 18516 | }, |
| ... | ... | @@ -18094,9 +18518,9 @@ fn zirStructInitAnon( |
| 18094 | 18518 | }; |
| 18095 | 18519 | |
| 18096 | 18520 | if (is_ref) { |
| 18097 | const target = sema.mod.getTarget(); | |
| 18098 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 18099 | .pointee_type = tuple_ty, | |
| 18521 | const target = mod.getTarget(); | |
| 18522 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ | |
| 18523 | .pointee_type = tuple_ty.toType(), | |
| 18100 | 18524 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18101 | 18525 | }); |
| 18102 | 18526 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | ... | @@ -18106,12 +18530,12 @@ fn zirStructInitAnon( |
| 18106 | 18530 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 18107 | 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 | 18534 | .mutable = true, |
| 18111 | 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 | 18539 | const init = try sema.resolveInst(item.data.init); |
| 18116 | 18540 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18117 | 18541 | _ = try block.addBinOp(.store, field_ptr, init); |
| ... | ... | @@ -18129,7 +18553,7 @@ fn zirStructInitAnon( |
| 18129 | 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 | 18559 | fn zirArrayInit( |
| ... | ... | @@ -18138,6 +18562,7 @@ fn zirArrayInit( |
| 18138 | 18562 | inst: Zir.Inst.Index, |
| 18139 | 18563 | is_ref: bool, |
| 18140 | 18564 | ) CompileError!Air.Inst.Ref { |
| 18565 | const mod = sema.mod; | |
| 18141 | 18566 | const gpa = sema.gpa; |
| 18142 | 18567 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 18143 | 18568 | const src = inst_data.src(); |
| ... | ... | @@ -18147,20 +18572,20 @@ fn zirArrayInit( |
| 18147 | 18572 | assert(args.len >= 2); // array_ty + at least one element |
| 18148 | 18573 | |
| 18149 | 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 | 18577 | const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null)); |
| 18153 | 18578 | defer gpa.free(resolved_args); |
| 18154 | 18579 | for (args[1..], 0..) |arg, i| { |
| 18155 | 18580 | const resolved_arg = try sema.resolveInst(arg); |
| 18156 | const elem_ty = if (array_ty.zigTypeTag() == .Struct) | |
| 18157 | array_ty.structFieldType(i) | |
| 18581 | const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct) | |
| 18582 | array_ty.structFieldType(i, mod) | |
| 18158 | 18583 | else |
| 18159 | array_ty.elemType2(); | |
| 18584 | array_ty.elemType2(mod); | |
| 18160 | 18585 | resolved_args[i] = sema.coerce(block, elem_ty, resolved_arg, .unneeded) catch |err| switch (err) { |
| 18161 | 18586 | error.NeededSourceLocation => { |
| 18162 | const decl = sema.mod.declPtr(block.src_decl); | |
| 18163 | const elem_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i); | |
| 18587 | const decl = mod.declPtr(block.src_decl); | |
| 18588 | const elem_src = mod.initSrc(src.node_offset.x, decl, i); | |
| 18164 | 18589 | _ = try sema.coerce(block, elem_ty, resolved_arg, elem_src); |
| 18165 | 18590 | unreachable; |
| 18166 | 18591 | }, |
| ... | ... | @@ -18169,7 +18594,7 @@ fn zirArrayInit( |
| 18169 | 18594 | } |
| 18170 | 18595 | |
| 18171 | 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 | 18600 | const opt_runtime_index: ?u32 = for (resolved_args, 0..) |arg, i| { |
| ... | ... | @@ -18178,21 +18603,25 @@ fn zirArrayInit( |
| 18178 | 18603 | } else null; |
| 18179 | 18604 | |
| 18180 | 18605 | const runtime_index = opt_runtime_index orelse { |
| 18181 | const elem_vals = try sema.arena.alloc(Value, resolved_args.len); | |
| 18182 | ||
| 18183 | for (resolved_args, 0..) |arg, i| { | |
| 18606 | const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len); | |
| 18607 | for (elem_vals, resolved_args, 0..) |*val, 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 | 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 | ||
| 18188 | const array_val = try Value.Tag.aggregate.create(sema.arena, elem_vals); | |
| 18189 | return sema.addConstantMaybeRef(block, array_ty, array_val, is_ref); | |
| 18615 | return sema.addConstantMaybeRef(block, array_ty, (try mod.intern(.{ .aggregate = .{ | |
| 18616 | .ty = array_ty.toIntern(), | |
| 18617 | .storage = .{ .elems = elem_vals }, | |
| 18618 | } })).toValue(), is_ref); | |
| 18190 | 18619 | }; |
| 18191 | 18620 | |
| 18192 | 18621 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| 18193 | 18622 | error.NeededSourceLocation => { |
| 18194 | const decl = sema.mod.declPtr(block.src_decl); | |
| 18195 | const elem_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index); | |
| 18623 | const decl = mod.declPtr(block.src_decl); | |
| 18624 | const elem_src = mod.initSrc(src.node_offset.x, decl, runtime_index); | |
| 18196 | 18625 | try sema.requireRuntimeBlock(block, src, elem_src); |
| 18197 | 18626 | unreachable; |
| 18198 | 18627 | }, |
| ... | ... | @@ -18201,19 +18630,19 @@ fn zirArrayInit( |
| 18201 | 18630 | try sema.queueFullTypeResolution(array_ty); |
| 18202 | 18631 | |
| 18203 | 18632 | if (is_ref) { |
| 18204 | const target = sema.mod.getTarget(); | |
| 18205 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 18633 | const target = mod.getTarget(); | |
| 18634 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ | |
| 18206 | 18635 | .pointee_type = array_ty, |
| 18207 | 18636 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18208 | 18637 | }); |
| 18209 | 18638 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 18210 | 18639 | |
| 18211 | if (array_ty.isTuple()) { | |
| 18640 | if (array_ty.isTuple(mod)) { | |
| 18212 | 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 | 18643 | .mutable = true, |
| 18215 | 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 | 18647 | const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); |
| 18219 | 18648 | |
| ... | ... | @@ -18224,10 +18653,10 @@ fn zirArrayInit( |
| 18224 | 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 | 18657 | .mutable = true, |
| 18229 | 18658 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18230 | .pointee_type = array_ty.elemType2(), | |
| 18659 | .pointee_type = array_ty.elemType2(mod), | |
| 18231 | 18660 | }); |
| 18232 | 18661 | const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); |
| 18233 | 18662 | |
| ... | ... | @@ -18252,44 +18681,49 @@ fn zirArrayInitAnon( |
| 18252 | 18681 | const src = inst_data.src(); |
| 18253 | 18682 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); |
| 18254 | 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); | |
| 18257 | const values = try sema.arena.alloc(Value, operands.len); | |
| 18686 | const types = try sema.arena.alloc(InternPool.Index, operands.len); | |
| 18687 | const values = try sema.arena.alloc(InternPool.Index, operands.len); | |
| 18258 | 18688 | |
| 18259 | 18689 | const opt_runtime_src = rs: { |
| 18260 | 18690 | var runtime_src: ?LazySrcLoc = null; |
| 18261 | 18691 | for (operands, 0..) |operand, i| { |
| 18262 | 18692 | const operand_src = src; // TODO better source location |
| 18263 | 18693 | const elem = try sema.resolveInst(operand); |
| 18264 | types[i] = sema.typeOf(elem); | |
| 18265 | if (types[i].zigTypeTag() == .Opaque) { | |
| 18694 | types[i] = sema.typeOf(elem).toIntern(); | |
| 18695 | if (types[i].toType().zigTypeTag(mod) == .Opaque) { | |
| 18266 | 18696 | const msg = msg: { |
| 18267 | 18697 | const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18268 | 18698 | errdefer msg.destroy(sema.gpa); |
| 18269 | 18699 | |
| 18270 | try sema.addDeclaredHereNote(msg, types[i]); | |
| 18700 | try sema.addDeclaredHereNote(msg, types[i].toType()); | |
| 18271 | 18701 | break :msg msg; |
| 18272 | 18702 | }; |
| 18273 | 18703 | return sema.failWithOwnedErrorMsg(msg); |
| 18274 | 18704 | } |
| 18275 | 18705 | if (try sema.resolveMaybeUndefVal(elem)) |val| { |
| 18276 | values[i] = val; | |
| 18706 | values[i] = val.toIntern(); | |
| 18277 | 18707 | } else { |
| 18278 | values[i] = Value.initTag(.unreachable_value); | |
| 18708 | values[i] = .none; | |
| 18279 | 18709 | runtime_src = operand_src; |
| 18280 | 18710 | } |
| 18281 | 18711 | } |
| 18282 | 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 | 18716 | .types = types, |
| 18287 | 18717 | .values = values, |
| 18288 | }); | |
| 18718 | .names = &.{}, | |
| 18719 | } }); | |
| 18289 | 18720 | |
| 18290 | 18721 | const runtime_src = opt_runtime_src orelse { |
| 18291 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 18292 | return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref); | |
| 18722 | const tuple_val = try mod.intern(.{ .aggregate = .{ | |
| 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 | 18729 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | ... | @@ -18297,7 +18731,7 @@ fn zirArrayInitAnon( |
| 18297 | 18731 | if (is_ref) { |
| 18298 | 18732 | const target = sema.mod.getTarget(); |
| 18299 | 18733 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18300 | .pointee_type = tuple_ty, | |
| 18734 | .pointee_type = tuple_ty.toType(), | |
| 18301 | 18735 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18302 | 18736 | }); |
| 18303 | 18737 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | ... | @@ -18306,9 +18740,9 @@ fn zirArrayInitAnon( |
| 18306 | 18740 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18307 | 18741 | .mutable = true, |
| 18308 | 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 | 18746 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18313 | 18747 | _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); |
| 18314 | 18748 | } |
| ... | ... | @@ -18322,7 +18756,7 @@ fn zirArrayInitAnon( |
| 18322 | 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 | 18762 | fn addConstantMaybeRef( |
| ... | ... | @@ -18337,8 +18771,8 @@ fn addConstantMaybeRef( |
| 18337 | 18771 | var anon_decl = try block.startAnonDecl(); |
| 18338 | 18772 | defer anon_decl.deinit(); |
| 18339 | 18773 | const decl = try anon_decl.finish( |
| 18340 | try ty.copy(anon_decl.arena()), | |
| 18341 | try val.copy(anon_decl.arena()), | |
| 18774 | ty, | |
| 18775 | val, | |
| 18342 | 18776 | 0, // default alignment |
| 18343 | 18777 | ); |
| 18344 | 18778 | return sema.analyzeDeclRef(decl); |
| ... | ... | @@ -18350,11 +18784,13 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 18350 | 18784 | const ty_src = inst_data.src(); |
| 18351 | 18785 | const field_src = inst_data.src(); |
| 18352 | 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 | 18788 | return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); |
| 18355 | 18789 | } |
| 18356 | 18790 | |
| 18357 | 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 | 18794 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 18359 | 18795 | const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; |
| 18360 | 18796 | const ty_src = inst_data.src(); |
| ... | ... | @@ -18367,7 +18803,8 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 18367 | 18803 | error.GenericPoison => return Air.Inst.Ref.generic_poison_type, |
| 18368 | 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 | 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 | 18812 | sema: *Sema, |
| 18376 | 18813 | block: *Block, |
| 18377 | 18814 | aggregate_ty: Type, |
| 18378 | field_name: []const u8, | |
| 18815 | field_name: InternPool.NullTerminatedString, | |
| 18379 | 18816 | field_src: LazySrcLoc, |
| 18380 | 18817 | ty_src: LazySrcLoc, |
| 18381 | 18818 | ) CompileError!Air.Inst.Ref { |
| 18819 | const mod = sema.mod; | |
| 18382 | 18820 | var cur_ty = aggregate_ty; |
| 18383 | 18821 | while (true) { |
| 18384 | 18822 | const resolved_ty = try sema.resolveTypeFields(cur_ty); |
| 18385 | 18823 | cur_ty = resolved_ty; |
| 18386 | switch (cur_ty.zigTypeTag()) { | |
| 18387 | .Struct => { | |
| 18388 | if (cur_ty.isAnonStruct()) { | |
| 18824 | switch (cur_ty.zigTypeTag(mod)) { | |
| 18825 | .Struct => switch (mod.intern_pool.indexToKey(cur_ty.toIntern())) { | |
| 18826 | .anon_struct_type => |anon_struct| { | |
| 18389 | 18827 | const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); |
| 18390 | return sema.addType(cur_ty.tupleFields().types[field_index]); | |
| 18391 | } | |
| 18392 | const struct_obj = cur_ty.castTag(.@"struct").?.data; | |
| 18393 | const field = struct_obj.fields.get(field_name) orelse | |
| 18394 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | |
| 18395 | return sema.addType(field.ty); | |
| 18828 | return sema.addType(anon_struct.types[field_index].toType()); | |
| 18829 | }, | |
| 18830 | .struct_type => |struct_type| { | |
| 18831 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 18832 | const field = struct_obj.fields.get(field_name) orelse | |
| 18833 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | |
| 18834 | return sema.addType(field.ty); | |
| 18835 | }, | |
| 18836 | else => unreachable, | |
| 18396 | 18837 | }, |
| 18397 | 18838 | .Union => { |
| 18398 | const union_obj = cur_ty.cast(Type.Payload.Union).?.data; | |
| 18839 | const union_obj = mod.typeToUnion(cur_ty).?; | |
| 18399 | 18840 | const field = union_obj.fields.get(field_name) orelse |
| 18400 | 18841 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); |
| 18401 | 18842 | return sema.addType(field.ty); |
| 18402 | 18843 | }, |
| 18403 | 18844 | .Optional => { |
| 18404 | if (cur_ty.castTag(.optional)) |some| { | |
| 18405 | // Struct/array init through optional requires the child type to not be a pointer. | |
| 18406 | // If the child of .optional is a pointer it'll error on the next loop. | |
| 18407 | cur_ty = some.data; | |
| 18408 | continue; | |
| 18409 | } | |
| 18845 | // 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. | |
| 18847 | cur_ty = mod.intern_pool.indexToKey(cur_ty.toIntern()).opt_type.toType(); | |
| 18848 | continue; | |
| 18410 | 18849 | }, |
| 18411 | 18850 | .ErrorUnion => { |
| 18412 | cur_ty = cur_ty.errorUnionPayload(); | |
| 18851 | cur_ty = cur_ty.errorUnionPayload(mod); | |
| 18413 | 18852 | continue; |
| 18414 | 18853 | }, |
| 18415 | 18854 | else => {}, |
| ... | ... | @@ -18425,18 +18864,23 @@ fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 18425 | 18864 | } |
| 18426 | 18865 | |
| 18427 | 18866 | fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 18867 | const mod = sema.mod; | |
| 18428 | 18868 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 18429 | 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 | 18873 | if (sema.owner_func != null and |
| 18433 | 18874 | sema.owner_func.?.calls_or_awaits_errorable_fn and |
| 18434 | sema.mod.comp.bin_file.options.error_return_tracing and | |
| 18435 | sema.mod.backendSupportsFeature(.error_return_trace)) | |
| 18875 | mod.comp.bin_file.options.error_return_tracing and | |
| 18876 | mod.backendSupportsFeature(.error_return_trace)) | |
| 18436 | 18877 | { |
| 18437 | 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 | 18886 | fn zirFrame( |
| ... | ... | @@ -18449,27 +18893,28 @@ fn zirFrame( |
| 18449 | 18893 | } |
| 18450 | 18894 | |
| 18451 | 18895 | fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 18896 | const mod = sema.mod; | |
| 18452 | 18897 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 18453 | 18898 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 18454 | 18899 | const ty = try sema.resolveType(block, operand_src, inst_data.operand); |
| 18455 | if (ty.isNoReturn()) { | |
| 18900 | if (ty.isNoReturn(mod)) { | |
| 18456 | 18901 | return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)}); |
| 18457 | 18902 | } |
| 18458 | const target = sema.mod.getTarget(); | |
| 18459 | const val = try ty.lazyAbiAlignment(target, sema.arena); | |
| 18460 | if (val.tag() == .lazy_align) { | |
| 18903 | const val = try ty.lazyAbiAlignment(mod); | |
| 18904 | if (val.isLazyAlign(mod)) { | |
| 18461 | 18905 | try sema.queueFullTypeResolution(ty); |
| 18462 | 18906 | } |
| 18463 | 18907 | return sema.addConstant(Type.comptime_int, val); |
| 18464 | 18908 | } |
| 18465 | 18909 | |
| 18466 | 18910 | fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 18911 | const mod = sema.mod; | |
| 18467 | 18912 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 18468 | 18913 | const operand = try sema.resolveInst(inst_data.operand); |
| 18469 | 18914 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 18470 | if (val.isUndef()) return sema.addConstUndef(Type.u1); | |
| 18471 | if (val.toBool()) return sema.addConstant(Type.u1, Value.one); | |
| 18472 | return sema.addConstant(Type.u1, Value.zero); | |
| 18915 | if (val.isUndef(mod)) return sema.addConstUndef(Type.u1); | |
| 18916 | if (val.toBool()) return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 1)); | |
| 18917 | return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0)); | |
| 18473 | 18918 | } |
| 18474 | 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 | 18925 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 18481 | 18926 | |
| 18482 | 18927 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { |
| 18483 | const bytes = val.castTag(.@"error").?.data.name; | |
| 18484 | return sema.addStrLit(block, bytes); | |
| 18928 | const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name; | |
| 18929 | return sema.addStrLit(block, sema.mod.intern_pool.stringToSlice(err_name)); | |
| 18485 | 18930 | } |
| 18486 | 18931 | |
| 18487 | 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 | 18944 | const tracy = trace(@src()); |
| 18500 | 18945 | defer tracy.end(); |
| 18501 | 18946 | |
| 18947 | const mod = sema.mod; | |
| 18502 | 18948 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 18503 | 18949 | const operand = try sema.resolveInst(inst_data.operand); |
| 18504 | 18950 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 18505 | 18951 | const operand_ty = sema.typeOf(operand); |
| 18506 | 18952 | |
| 18507 | switch (operand_ty.zigTypeTag()) { | |
| 18953 | switch (operand_ty.zigTypeTag(mod)) { | |
| 18508 | 18954 | .ComptimeFloat, .Float => {}, |
| 18509 | 18955 | .Vector => { |
| 18510 | const scalar_ty = operand_ty.scalarType(); | |
| 18511 | switch (scalar_ty.zigTypeTag()) { | |
| 18956 | const scalar_ty = operand_ty.scalarType(mod); | |
| 18957 | switch (scalar_ty.zigTypeTag(mod)) { | |
| 18512 | 18958 | .ComptimeFloat, .Float => {}, |
| 18513 | 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 | 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 | 18966 | .Vector => { |
| 18521 | const scalar_ty = operand_ty.scalarType(); | |
| 18522 | const vec_len = operand_ty.vectorLen(); | |
| 18523 | const result_ty = try Type.vector(sema.arena, vec_len, scalar_ty); | |
| 18967 | const scalar_ty = operand_ty.scalarType(mod); | |
| 18968 | const vec_len = operand_ty.vectorLen(mod); | |
| 18969 | const result_ty = try mod.vectorType(.{ | |
| 18970 | .len = vec_len, | |
| 18971 | .child = scalar_ty.toIntern(), | |
| 18972 | }); | |
| 18524 | 18973 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 18525 | if (val.isUndef()) | |
| 18974 | if (val.isUndef(mod)) | |
| 18526 | 18975 | return sema.addConstUndef(result_ty); |
| 18527 | 18976 | |
| 18528 | var elem_buf: Value.ElemValueBuffer = undefined; | |
| 18529 | const elems = try sema.arena.alloc(Value, vec_len); | |
| 18977 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 18530 | 18978 | for (elems, 0..) |*elem, i| { |
| 18531 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | |
| 18532 | elem.* = try eval(elem_val, scalar_ty, sema.arena, sema.mod); | |
| 18979 | const elem_val = try val.elemValue(sema.mod, i); | |
| 18980 | elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod); | |
| 18533 | 18981 | } |
| 18534 | return sema.addConstant( | |
| 18535 | result_ty, | |
| 18536 | try Value.Tag.aggregate.create(sema.arena, elems), | |
| 18537 | ); | |
| 18982 | return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{ | |
| 18983 | .ty = result_ty.toIntern(), | |
| 18984 | .storage = .{ .elems = elems }, | |
| 18985 | } })).toValue()); | |
| 18538 | 18986 | } |
| 18539 | 18987 | |
| 18540 | 18988 | try sema.requireRuntimeBlock(block, operand_src, null); |
| ... | ... | @@ -18542,7 +18990,7 @@ fn zirUnaryMath( |
| 18542 | 18990 | }, |
| 18543 | 18991 | .ComptimeFloat, .Float => { |
| 18544 | 18992 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { |
| 18545 | if (operand_val.isUndef()) | |
| 18993 | if (operand_val.isUndef(mod)) | |
| 18546 | 18994 | return sema.addConstUndef(operand_ty); |
| 18547 | 18995 | const result_val = try eval(operand_val, operand_ty, sema.arena, sema.mod); |
| 18548 | 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 | 19010 | const operand = try sema.resolveInst(inst_data.operand); |
| 18563 | 19011 | const operand_ty = sema.typeOf(operand); |
| 18564 | 19012 | const mod = sema.mod; |
| 19013 | const ip = &mod.intern_pool; | |
| 18565 | 19014 | |
| 18566 | 19015 | try sema.resolveTypeLayout(operand_ty); |
| 18567 | const enum_ty = switch (operand_ty.zigTypeTag()) { | |
| 19016 | const enum_ty = switch (operand_ty.zigTypeTag(mod)) { | |
| 18568 | 19017 | .EnumLiteral => { |
| 18569 | 19018 | const val = try sema.resolveConstValue(block, .unneeded, operand, ""); |
| 18570 | const bytes = val.castTag(.enum_literal).?.data; | |
| 18571 | return sema.addStrLit(block, bytes); | |
| 19019 | const tag_name = ip.indexToKey(val.toIntern()).enum_literal; | |
| 19020 | return sema.addStrLit(block, ip.stringToSlice(tag_name)); | |
| 18572 | 19021 | }, |
| 18573 | 19022 | .Enum => operand_ty, |
| 18574 | .Union => operand_ty.unionTagType() orelse { | |
| 19023 | .Union => operand_ty.unionTagType(mod) orelse { | |
| 18575 | 19024 | const msg = msg: { |
| 18576 | 19025 | const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{ |
| 18577 | 19026 | operand_ty.fmt(sema.mod), |
| ... | ... | @@ -18586,30 +19035,31 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18586 | 19035 | operand_ty.fmt(mod), |
| 18587 | 19036 | }), |
| 18588 | 19037 | }; |
| 18589 | if (enum_ty.enumFieldCount() == 0) { | |
| 19038 | if (enum_ty.enumFieldCount(mod) == 0) { | |
| 18590 | 19039 | // TODO I don't think this is the correct way to handle this but |
| 18591 | 19040 | // it prevents a crash. |
| 18592 | 19041 | return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{ |
| 18593 | 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 | 19046 | const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); |
| 18598 | 19047 | if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { |
| 18599 | 19048 | const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse { |
| 18600 | 19049 | const enum_decl = mod.declPtr(enum_decl_index); |
| 18601 | 19050 | const msg = msg: { |
| 18602 | const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{ | |
| 18603 | val.fmtValue(enum_ty, sema.mod), enum_decl.name, | |
| 19051 | const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{}'", .{ | |
| 19052 | val.fmtValue(enum_ty, sema.mod), enum_decl.name.fmt(ip), | |
| 18604 | 19053 | }); |
| 18605 | 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 | 19056 | break :msg msg; |
| 18608 | 19057 | }; |
| 18609 | 19058 | return sema.failWithOwnedErrorMsg(msg); |
| 18610 | 19059 | }; |
| 18611 | const field_name = enum_ty.enumFieldName(field_index); | |
| 18612 | return sema.addStrLit(block, field_name); | |
| 19060 | // TODO: write something like getCoercedInts to avoid needing to dupe | |
| 19061 | const field_name = enum_ty.enumFieldName(field_index, mod); | |
| 19062 | return sema.addStrLit(block, ip.stringToSlice(field_name)); | |
| 18613 | 19063 | } |
| 18614 | 19064 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 18615 | 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 | 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 | 19081 | const mod = sema.mod; |
| 19082 | const gpa = sema.gpa; | |
| 19083 | const ip = &mod.intern_pool; | |
| 18627 | 19084 | const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small); |
| 18628 | 19085 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 18629 | 19086 | const src = LazySrcLoc.nodeOffset(extra.node); |
| ... | ... | @@ -18632,10 +19089,10 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 18632 | 19089 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 18633 | 19090 | const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); |
| 18634 | 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 | 19093 | const target = mod.getTarget(); |
| 18637 | const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag, mod).?; | |
| 18638 | if (union_val.val.anyUndef(mod)) return sema.failWithUseOfUndef(block, src); | |
| 19094 | if (try union_val.val.toValue().anyUndef(mod)) return sema.failWithUseOfUndef(block, src); | |
| 19095 | const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag.toValue(), mod).?; | |
| 18639 | 19096 | switch (@intToEnum(std.builtin.TypeId, tag_index)) { |
| 18640 | 19097 | .Type => return Air.Inst.Ref.type_type, |
| 18641 | 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 | 19105 | .AnyFrame => return sema.failWithUseOfAsync(block, src), |
| 18649 | 19106 | .EnumLiteral => return Air.Inst.Ref.enum_literal_type, |
| 18650 | 19107 | .Int => { |
| 18651 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 18652 | // TODO use reflection instead of magic numbers here | |
| 18653 | const signedness_val = struct_val[0]; | |
| 18654 | const bits_val = struct_val[1]; | |
| 18655 | ||
| 18656 | const signedness = signedness_val.toEnum(std.builtin.Signedness); | |
| 18657 | const bits = @intCast(u16, bits_val.toUnsignedInt(target)); | |
| 18658 | const ty = switch (signedness) { | |
| 18659 | .signed => try Type.Tag.int_signed.create(sema.arena, bits), | |
| 18660 | .unsigned => try Type.Tag.int_unsigned.create(sema.arena, bits), | |
| 18661 | }; | |
| 19108 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19109 | const signedness_val = try union_val.val.toValue().fieldValue( | |
| 19110 | mod, | |
| 19111 | fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?, | |
| 19112 | ); | |
| 19113 | const bits_val = try union_val.val.toValue().fieldValue( | |
| 19114 | mod, | |
| 19115 | fields.getIndex(try ip.getOrPutString(gpa, "bits")).?, | |
| 19116 | ); | |
| 19117 | ||
| 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 | 19121 | return sema.addType(ty); |
| 18663 | 19122 | }, |
| 18664 | 19123 | .Vector => { |
| 18665 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 18666 | // TODO use reflection instead of magic numbers here | |
| 18667 | const len_val = struct_val[0]; | |
| 18668 | const child_val = struct_val[1]; | |
| 19124 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19125 | const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19126 | try ip.getOrPutString(gpa, "len"), | |
| 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); | |
| 18671 | var buffer: Value.ToTypeBuffer = undefined; | |
| 18672 | const child_ty = child_val.toType(&buffer); | |
| 19132 | const len = @intCast(u32, len_val.toUnsignedInt(mod)); | |
| 19133 | const child_ty = child_val.toType(); | |
| 18673 | 19134 | |
| 18674 | 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 | 19141 | return sema.addType(ty); |
| 18678 | 19142 | }, |
| 18679 | 19143 | .Float => { |
| 18680 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 18681 | // TODO use reflection instead of magic numbers here | |
| 18682 | // bits: comptime_int, | |
| 18683 | const bits_val = struct_val[0]; | |
| 19144 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19145 | const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19146 | try ip.getOrPutString(gpa, "bits"), | |
| 19147 | ).?); | |
| 18684 | 19148 | |
| 18685 | const bits = @intCast(u16, bits_val.toUnsignedInt(target)); | |
| 19149 | const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); | |
| 18686 | 19150 | const ty = switch (bits) { |
| 18687 | 19151 | 16 => Type.f16, |
| 18688 | 19152 | 32 => Type.f32, |
| ... | ... | @@ -18694,25 +19158,42 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 18694 | 19158 | return sema.addType(ty); |
| 18695 | 19159 | }, |
| 18696 | 19160 | .Pointer => { |
| 18697 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 18698 | // TODO use reflection instead of magic numbers here | |
| 18699 | const size_val = struct_val[0]; | |
| 18700 | const is_const_val = struct_val[1]; | |
| 18701 | const is_volatile_val = struct_val[2]; | |
| 18702 | const alignment_val = struct_val[3]; | |
| 18703 | const address_space_val = struct_val[4]; | |
| 18704 | const child_val = struct_val[5]; | |
| 18705 | const is_allowzero_val = struct_val[6]; | |
| 18706 | const sentinel_val = struct_val[7]; | |
| 19161 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19162 | const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19163 | try ip.getOrPutString(gpa, "size"), | |
| 19164 | ).?); | |
| 19165 | const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19166 | try ip.getOrPutString(gpa, "is_const"), | |
| 19167 | ).?); | |
| 19168 | const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19169 | try ip.getOrPutString(gpa, "is_volatile"), | |
| 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 | 19187 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { |
| 18709 | 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; | |
| 18714 | const unresolved_elem_ty = child_val.toType(&buffer); | |
| 18715 | const elem_ty = if (abi_align == 0) | |
| 19191 | const abi_align = InternPool.Alignment.fromByteUnits( | |
| 19192 | (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?, | |
| 19193 | ); | |
| 19194 | ||
| 19195 | const unresolved_elem_ty = child_val.toType(); | |
| 19196 | const elem_ty = if (abi_align == .none) | |
| 18716 | 19197 | unresolved_elem_ty |
| 18717 | 19198 | else t: { |
| 18718 | 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 | 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; | |
| 18726 | if (!sentinel_val.isNull()) { | |
| 18727 | if (ptr_size == .One or ptr_size == .C) { | |
| 18728 | return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); | |
| 19206 | const actual_sentinel: InternPool.Index = s: { | |
| 19207 | if (!sentinel_val.isNull(mod)) { | |
| 19208 | if (ptr_size == .One or ptr_size == .C) { | |
| 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; | |
| 18731 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ | |
| 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 | } | |
| 19219 | break :s .none; | |
| 19220 | }; | |
| 18737 | 19221 | |
| 18738 | if (elem_ty.zigTypeTag() == .NoReturn) { | |
| 19222 | if (elem_ty.zigTypeTag(mod) == .NoReturn) { | |
| 18739 | 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 | 19225 | if (ptr_size != .One) { |
| 18742 | 19226 | return sema.fail(block, src, "function pointers must be single pointers", .{}); |
| 18743 | 19227 | } |
| 18744 | const fn_align = elem_ty.fnInfo().alignment; | |
| 18745 | if (abi_align != 0 and fn_align != 0 and | |
| 19228 | const fn_align = mod.typeToFunc(elem_ty).?.alignment; | |
| 19229 | if (abi_align != .none and fn_align != .none and | |
| 18746 | 19230 | abi_align != fn_align) |
| 18747 | 19231 | { |
| 18748 | 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 | 19235 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); |
| 18752 | 19236 | } else if (ptr_size == .C) { |
| 18753 | 19237 | if (!try sema.validateExternType(elem_ty, .other)) { |
| 18754 | 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)}); | |
| 18756 | errdefer msg.destroy(sema.gpa); | |
| 19239 | const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(mod)}); | |
| 19240 | errdefer msg.destroy(gpa); | |
| 18757 | 19241 | |
| 18758 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 18759 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), elem_ty, .other); | |
| 19242 | const src_decl = mod.declPtr(block.src_decl); | |
| 19243 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), elem_ty, .other); | |
| 18760 | 19244 | |
| 18761 | 19245 | try sema.addDeclaredHereNote(msg, elem_ty); |
| 18762 | 19246 | break :msg msg; |
| 18763 | 19247 | }; |
| 18764 | 19248 | return sema.failWithOwnedErrorMsg(msg); |
| 18765 | 19249 | } |
| 18766 | if (elem_ty.zigTypeTag() == .Opaque) { | |
| 19250 | if (elem_ty.zigTypeTag(mod) == .Opaque) { | |
| 18767 | 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, .{ | |
| 18772 | .size = ptr_size, | |
| 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(), | |
| 19255 | const ty = try mod.ptrType(.{ | |
| 19256 | .child = elem_ty.toIntern(), | |
| 18779 | 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 | 19267 | return sema.addType(ty); |
| 18782 | 19268 | }, |
| 18783 | 19269 | .Array => { |
| 18784 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 18785 | // TODO use reflection instead of magic numbers here | |
| 18786 | // len: comptime_int, | |
| 18787 | const len_val = struct_val[0]; | |
| 18788 | // child: type, | |
| 18789 | const child_val = struct_val[1]; | |
| 18790 | // sentinel: ?*const anyopaque, | |
| 18791 | const sentinel_val = struct_val[2]; | |
| 18792 | ||
| 18793 | const len = len_val.toUnsignedInt(target); | |
| 18794 | var buffer: Value.ToTypeBuffer = undefined; | |
| 18795 | const child_ty = try child_val.toType(&buffer).copy(sema.arena); | |
| 18796 | const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: { | |
| 19270 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19271 | const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19272 | try ip.getOrPutString(gpa, "len"), | |
| 19273 | ).?); | |
| 19274 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19275 | try ip.getOrPutString(gpa, "child"), | |
| 19276 | ).?); | |
| 19277 | const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19278 | try ip.getOrPutString(gpa, "sentinel"), | |
| 19279 | ).?); | |
| 19280 | ||
| 19281 | const len = len_val.toUnsignedInt(mod); | |
| 19282 | const child_ty = child_val.toType(); | |
| 19283 | const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: { | |
| 18797 | 19284 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 18798 | 19285 | .@"addrspace" = .generic, |
| 18799 | 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 | 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 | 19292 | return sema.addType(ty); |
| 18806 | 19293 | }, |
| 18807 | 19294 | .Optional => { |
| 18808 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 18809 | // TODO use reflection instead of magic numbers here | |
| 18810 | // child: type, | |
| 18811 | const child_val = struct_val[0]; | |
| 19295 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19296 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19297 | try ip.getOrPutString(gpa, "child"), | |
| 19298 | ).?); | |
| 18812 | 19299 | |
| 18813 | var buffer: Value.ToTypeBuffer = undefined; | |
| 18814 | const child_ty = try child_val.toType(&buffer).copy(sema.arena); | |
| 19300 | const child_ty = child_val.toType(); | |
| 18815 | 19301 | |
| 18816 | const ty = try Type.optional(sema.arena, child_ty); | |
| 19302 | const ty = try Type.optional(sema.arena, child_ty, mod); | |
| 18817 | 19303 | return sema.addType(ty); |
| 18818 | 19304 | }, |
| 18819 | 19305 | .ErrorUnion => { |
| 18820 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 18821 | // TODO use reflection instead of magic numbers here | |
| 18822 | // error_set: type, | |
| 18823 | const error_set_val = struct_val[0]; | |
| 18824 | // payload: type, | |
| 18825 | const payload_val = struct_val[1]; | |
| 18826 | ||
| 18827 | var buffer: Value.ToTypeBuffer = undefined; | |
| 18828 | const error_set_ty = try error_set_val.toType(&buffer).copy(sema.arena); | |
| 18829 | const payload_ty = try payload_val.toType(&buffer).copy(sema.arena); | |
| 18830 | ||
| 18831 | if (error_set_ty.zigTypeTag() != .ErrorSet) { | |
| 19306 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19307 | const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19308 | try ip.getOrPutString(gpa, "error_set"), | |
| 19309 | ).?); | |
| 19310 | const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19311 | try ip.getOrPutString(gpa, "payload"), | |
| 19312 | ).?); | |
| 19313 | ||
| 19314 | const error_set_ty = error_set_val.toType(); | |
| 19315 | const payload_ty = payload_val.toType(); | |
| 19316 | ||
| 19317 | if (error_set_ty.zigTypeTag(mod) != .ErrorSet) { | |
| 18832 | 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, .{ | |
| 18836 | .error_set = error_set_ty, | |
| 18837 | .payload = payload_ty, | |
| 18838 | }); | |
| 19321 | const ty = try mod.errorUnionType(error_set_ty, payload_ty); | |
| 18839 | 19322 | return sema.addType(ty); |
| 18840 | 19323 | }, |
| 18841 | 19324 | .ErrorSet => { |
| 18842 | const payload_val = union_val.val.optionalValue() orelse | |
| 18843 | return sema.addType(Type.initTag(.anyerror)); | |
| 18844 | const slice_val = payload_val.castTag(.slice).?.data; | |
| 19325 | const payload_val = union_val.val.toValue().optionalValue(mod) orelse | |
| 19326 | return sema.addType(Type.anyerror); | |
| 18845 | 19327 | |
| 18846 | const len = try sema.usizeCast(block, src, slice_val.len.toUnsignedInt(mod.getTarget())); | |
| 18847 | var names: Module.ErrorSet.NameMap = .{}; | |
| 19328 | const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod)); | |
| 19329 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; | |
| 18848 | 19330 | try names.ensureUnusedCapacity(sema.arena, len); |
| 18849 | var i: usize = 0; | |
| 18850 | while (i < len) : (i += 1) { | |
| 18851 | var buf: Value.ElemValueBuffer = undefined; | |
| 18852 | const elem_val = slice_val.ptr.elemValueBuffer(mod, i, &buf); | |
| 18853 | const struct_val = elem_val.castTag(.aggregate).?.data; | |
| 18854 | // TODO use reflection instead of magic numbers here | |
| 18855 | // error_set: type, | |
| 18856 | const name_val = struct_val[0]; | |
| 18857 | const name_str = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, sema.mod); | |
| 18858 | ||
| 18859 | const kv = try mod.getErrorValue(name_str); | |
| 18860 | const gop = names.getOrPutAssumeCapacity(kv.key); | |
| 19331 | for (0..len) |i| { | |
| 19332 | const elem_val = try payload_val.elemValue(mod, i); | |
| 19333 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 19334 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19335 | try ip.getOrPutString(gpa, "name"), | |
| 19336 | ).?); | |
| 19337 | ||
| 19338 | const name = try name_val.toIpString(Type.slice_const_u8, mod); | |
| 19339 | _ = try mod.getErrorValue(name); | |
| 19340 | const gop = names.getOrPutAssumeCapacity(name); | |
| 18861 | 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 | |
| 18867 | Module.ErrorSet.sortNames(&names); | |
| 18868 | const ty = try Type.Tag.error_set_merged.create(sema.arena, names); | |
| 19348 | const ty = try mod.errorSetFromUnsortedNames(names.keys()); | |
| 18869 | 19349 | return sema.addType(ty); |
| 18870 | 19350 | }, |
| 18871 | 19351 | .Struct => { |
| 18872 | // TODO use reflection instead of magic numbers here | |
| 18873 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 18874 | // layout: containerlayout, | |
| 18875 | const layout_val = struct_val[0]; | |
| 18876 | // backing_int: ?type, | |
| 18877 | const backing_int_val = struct_val[1]; | |
| 18878 | // fields: []const enumfield, | |
| 18879 | const fields_val = struct_val[2]; | |
| 18880 | // decls: []const declaration, | |
| 18881 | const decls_val = struct_val[3]; | |
| 18882 | // is_tuple: bool, | |
| 18883 | const is_tuple_val = struct_val[4]; | |
| 18884 | assert(struct_val.len == 5); | |
| 18885 | ||
| 18886 | const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); | |
| 19352 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19353 | const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19354 | try ip.getOrPutString(gpa, "layout"), | |
| 19355 | ).?); | |
| 19356 | const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19357 | try ip.getOrPutString(gpa, "backing_integer"), | |
| 19358 | ).?); | |
| 19359 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19360 | try ip.getOrPutString(gpa, "fields"), | |
| 19361 | ).?); | |
| 19362 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19363 | try ip.getOrPutString(gpa, "decls"), | |
| 19364 | ).?); | |
| 19365 | const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19366 | try ip.getOrPutString(gpa, "is_tuple"), | |
| 19367 | ).?); | |
| 19368 | ||
| 19369 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); | |
| 18887 | 19370 | |
| 18888 | 19371 | // Decls |
| 18889 | 19372 | if (decls_val.sliceLen(mod) > 0) { |
| 18890 | 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 | 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 | 19382 | .Enum => { |
| 18900 | const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data; | |
| 18901 | // TODO use reflection instead of magic numbers here | |
| 18902 | // tag_type: type, | |
| 18903 | const tag_type_val = struct_val[0]; | |
| 18904 | // fields: []const EnumField, | |
| 18905 | const fields_val = struct_val[1]; | |
| 18906 | // decls: []const Declaration, | |
| 18907 | const decls_val = struct_val[2]; | |
| 18908 | // is_exhaustive: bool, | |
| 18909 | const is_exhaustive_val = struct_val[3]; | |
| 19383 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19384 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19385 | try ip.getOrPutString(gpa, "tag_type"), | |
| 19386 | ).?); | |
| 19387 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19388 | try ip.getOrPutString(gpa, "fields"), | |
| 19389 | ).?); | |
| 19390 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19391 | try ip.getOrPutString(gpa, "decls"), | |
| 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 | 19397 | // Decls |
| 18912 | 19398 | if (decls_val.sliceLen(mod) > 0) { |
| 18913 | 19399 | return sema.fail(block, src, "reified enums must have no decls", .{}); |
| 18914 | 19400 | } |
| 18915 | 19401 | |
| 18916 | const gpa = sema.gpa; | |
| 18917 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | |
| 18918 | errdefer new_decl_arena.deinit(); | |
| 18919 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 19402 | const int_tag_ty = tag_type_val.toType(); | |
| 19403 | if (int_tag_ty.zigTypeTag(mod) != .Int) { | |
| 19404 | return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); | |
| 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 | 19411 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 18936 | .ty = Type.type, | |
| 18937 | .val = enum_val, | |
| 19412 | .ty = Type.noreturn, | |
| 19413 | .val = Value.@"unreachable", | |
| 18938 | 19414 | }, name_strategy, "enum", inst); |
| 18939 | 19415 | const new_decl = mod.declPtr(new_decl_index); |
| 18940 | 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.* = .{ | |
| 18944 | .owner_decl = new_decl_index, | |
| 18945 | .tag_ty = Type.null, | |
| 18946 | .tag_ty_inferred = false, | |
| 18947 | .fields = .{}, | |
| 18948 | .values = .{}, | |
| 18949 | .namespace = .{ | |
| 18950 | .parent = block.namespace, | |
| 18951 | .ty = enum_ty, | |
| 18952 | .file_scope = block.getFileScope(), | |
| 18953 | }, | |
| 18954 | }; | |
| 19422 | // Define our empty enum decl | |
| 19423 | const fields_len = @intCast(u32, try sema.usizeCast(block, src, fields_val.sliceLen(mod))); | |
| 19424 | const incomplete_enum = try ip.getIncompleteEnum(gpa, .{ | |
| 19425 | .decl = new_decl_index, | |
| 19426 | .namespace = .none, | |
| 19427 | .fields_len = fields_len, | |
| 19428 | .has_values = true, | |
| 19429 | .tag_mode = if (!is_exhaustive_val.toBool()) | |
| 19430 | .nonexhaustive | |
| 19431 | else | |
| 19432 | .explicit, | |
| 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 | |
| 18957 | var buffer: Value.ToTypeBuffer = undefined; | |
| 18958 | const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 19438 | new_decl.ty = Type.type; | |
| 19439 | new_decl.val = incomplete_enum.index.toValue(); | |
| 18959 | 19440 | |
| 18960 | if (int_tag_ty.zigTypeTag() != .Int) { | |
| 18961 | return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); | |
| 18962 | } | |
| 18963 | enum_obj.tag_ty = int_tag_ty; | |
| 18964 | ||
| 18965 | // Fields | |
| 18966 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); | |
| 18967 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | |
| 18968 | try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ | |
| 18969 | .ty = enum_obj.tag_ty, | |
| 18970 | .mod = mod, | |
| 18971 | }); | |
| 19441 | for (0..fields_len) |field_i| { | |
| 19442 | const elem_val = try fields_val.elemValue(mod, field_i); | |
| 19443 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 19444 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19445 | try ip.getOrPutString(gpa, "name"), | |
| 19446 | ).?); | |
| 19447 | const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19448 | try ip.getOrPutString(gpa, "value"), | |
| 19449 | ).?); | |
| 18972 | 19450 | |
| 18973 | var field_i: usize = 0; | |
| 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 | ); | |
| 19451 | const field_name = try name_val.toIpString(Type.slice_const_u8, mod); | |
| 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 | 19454 | // TODO: better source location |
| 18991 | return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{ | |
| 18992 | field_name, | |
| 19455 | return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{ | |
| 19456 | field_name.fmt(ip), | |
| 18993 | 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); | |
| 18999 | if (gop_field.found_existing) { | |
| 19462 | if (try incomplete_enum.addFieldName(ip, gpa, field_name)) |other_index| { | |
| 19000 | 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 | 19467 | errdefer msg.destroy(gpa); |
| 19468 | _ = other_index; // TODO: this note is incorrect | |
| 19003 | 19469 | try sema.errNote(block, src, msg, "other field here", .{}); |
| 19004 | 19470 | break :msg msg; |
| 19005 | 19471 | }; |
| 19006 | 19472 | return sema.failWithOwnedErrorMsg(msg); |
| 19007 | 19473 | } |
| 19008 | 19474 | |
| 19009 | const copied_tag_val = try value_val.copy(new_decl_arena_allocator); | |
| 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) { | |
| 19475 | if (try incomplete_enum.addFieldValue(ip, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| { | |
| 19015 | 19476 | const msg = msg: { |
| 19016 | 19477 | const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); |
| 19017 | 19478 | errdefer msg.destroy(gpa); |
| 19479 | _ = other; // TODO: this note is incorrect | |
| 19018 | 19480 | try sema.errNote(block, src, msg, "other enum tag value here", .{}); |
| 19019 | 19481 | break :msg msg; |
| 19020 | 19482 | }; |
| ... | ... | @@ -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); | |
| 19026 | return sema.analyzeDeclVal(block, src, new_decl_index); | |
| 19487 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | |
| 19488 | try mod.finalizeAnonDecl(new_decl_index); | |
| 19489 | return decl_val; | |
| 19027 | 19490 | }, |
| 19028 | 19491 | .Opaque => { |
| 19029 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 19030 | // decls: []const Declaration, | |
| 19031 | const decls_val = struct_val[0]; | |
| 19492 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19493 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19494 | try ip.getOrPutString(gpa, "decls"), | |
| 19495 | ).?); | |
| 19032 | 19496 | |
| 19033 | 19497 | // Decls |
| 19034 | 19498 | if (decls_val.sliceLen(mod) > 0) { |
| 19035 | 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); | |
| 19039 | errdefer new_decl_arena.deinit(); | |
| 19040 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 19502 | // Because these three things each reference each other, | |
| 19503 | // `undefined` placeholders are used in two places before being set | |
| 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 | 19506 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 19051 | .ty = Type.type, | |
| 19052 | .val = opaque_val, | |
| 19507 | .ty = Type.noreturn, | |
| 19508 | .val = Value.@"unreachable", | |
| 19053 | 19509 | }, name_strategy, "opaque", inst); |
| 19054 | 19510 | const new_decl = mod.declPtr(new_decl_index); |
| 19055 | 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.* = .{ | |
| 19059 | .owner_decl = new_decl_index, | |
| 19060 | .namespace = .{ | |
| 19061 | .parent = block.namespace, | |
| 19062 | .ty = opaque_ty, | |
| 19063 | .file_scope = block.getFileScope(), | |
| 19064 | }, | |
| 19065 | }; | |
| 19517 | const new_namespace_index = try mod.createNamespace(.{ | |
| 19518 | .parent = block.namespace.toOptional(), | |
| 19519 | .ty = undefined, | |
| 19520 | .file_scope = block.getFileScope(mod), | |
| 19521 | }); | |
| 19522 | const new_namespace = mod.namespacePtr(new_namespace_index); | |
| 19523 | errdefer mod.destroyNamespace(new_namespace_index); | |
| 19066 | 19524 | |
| 19067 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 19068 | return sema.analyzeDeclVal(block, src, new_decl_index); | |
| 19525 | const opaque_ty = try mod.intern(.{ .opaque_type = .{ | |
| 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 | 19540 | .Union => { |
| 19071 | // TODO use reflection instead of magic numbers here | |
| 19072 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 19073 | // layout: containerlayout, | |
| 19074 | const layout_val = struct_val[0]; | |
| 19075 | // tag_type: ?type, | |
| 19076 | const tag_type_val = struct_val[1]; | |
| 19077 | // fields: []const enumfield, | |
| 19078 | const fields_val = struct_val[2]; | |
| 19079 | // decls: []const declaration, | |
| 19080 | const decls_val = struct_val[3]; | |
| 19541 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19542 | const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19543 | try ip.getOrPutString(gpa, "layout"), | |
| 19544 | ).?); | |
| 19545 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19546 | try ip.getOrPutString(gpa, "tag_type"), | |
| 19547 | ).?); | |
| 19548 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19549 | try ip.getOrPutString(gpa, "fields"), | |
| 19550 | ).?); | |
| 19551 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19552 | try ip.getOrPutString(gpa, "decls"), | |
| 19553 | ).?); | |
| 19081 | 19554 | |
| 19082 | 19555 | // Decls |
| 19083 | 19556 | if (decls_val.sliceLen(mod) > 0) { |
| 19084 | 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); | |
| 19089 | errdefer new_decl_arena.deinit(); | |
| 19090 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 19561 | // Because these three things each reference each other, `undefined` | |
| 19562 | // placeholders are used before being set after the union type gains an | |
| 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 | 19565 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 19109 | .ty = Type.type, | |
| 19110 | .val = new_union_val, | |
| 19566 | .ty = Type.noreturn, | |
| 19567 | .val = Value.@"unreachable", | |
| 19111 | 19568 | }, name_strategy, "union", inst); |
| 19112 | 19569 | const new_decl = mod.declPtr(new_decl_index); |
| 19113 | 19570 | new_decl.owns_tv = true; |
| 19114 | errdefer mod.abortAnonDecl(new_decl_index); | |
| 19115 | union_obj.* = .{ | |
| 19571 | errdefer { | |
| 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 | 19585 | .owner_decl = new_decl_index, |
| 19117 | .tag_ty = Type.initTag(.null), | |
| 19586 | .tag_ty = Type.null, | |
| 19118 | 19587 | .fields = .{}, |
| 19119 | 19588 | .zir_index = inst, |
| 19120 | 19589 | .layout = layout, |
| 19121 | 19590 | .status = .have_field_types, |
| 19122 | .namespace = .{ | |
| 19123 | .parent = block.namespace, | |
| 19124 | .ty = union_ty, | |
| 19125 | .file_scope = block.getFileScope(), | |
| 19591 | .namespace = new_namespace_index, | |
| 19592 | }); | |
| 19593 | const union_obj = mod.unionPtr(union_index); | |
| 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 | 19614 | // Tag type |
| 19130 | var tag_ty_field_names: ?Module.EnumFull.NameMap = null; | |
| 19131 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; | |
| 19132 | 19615 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); |
| 19133 | if (tag_type_val.optionalValue()) |payload_val| { | |
| 19134 | var buffer: Value.ToTypeBuffer = undefined; | |
| 19135 | union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 19616 | var explicit_tags_seen: []bool = &.{}; | |
| 19617 | var enum_field_names: []InternPool.NullTerminatedString = &.{}; | |
| 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) { | |
| 19138 | return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}); | |
| 19139 | } | |
| 19140 | tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena); | |
| 19626 | explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); | |
| 19627 | @memset(explicit_tags_seen, false); | |
| 19141 | 19628 | } else { |
| 19142 | union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null); | |
| 19143 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; | |
| 19629 | enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); | |
| 19144 | 19630 | } |
| 19145 | 19631 | |
| 19146 | 19632 | // Fields |
| 19147 | try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | |
| 19148 | ||
| 19149 | var i: usize = 0; | |
| 19150 | while (i < fields_len) : (i += 1) { | |
| 19151 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); | |
| 19152 | const field_struct_val = elem_val.castTag(.aggregate).?.data; | |
| 19153 | // TODO use reflection instead of magic numbers here | |
| 19154 | // name: []const u8 | |
| 19155 | const name_val = field_struct_val[0]; | |
| 19156 | // type: type, | |
| 19157 | const type_val = field_struct_val[1]; | |
| 19158 | // alignment: comptime_int, | |
| 19159 | const alignment_val = field_struct_val[2]; | |
| 19160 | ||
| 19161 | const field_name = try name_val.toAllocatedBytes( | |
| 19162 | Type.initTag(.const_slice_u8), | |
| 19163 | new_decl_arena_allocator, | |
| 19164 | sema.mod, | |
| 19165 | ); | |
| 19166 | ||
| 19167 | if (enum_field_names) |set| { | |
| 19168 | set.putAssumeCapacity(field_name, {}); | |
| 19169 | } | |
| 19170 | ||
| 19171 | if (tag_ty_field_names) |*names| { | |
| 19172 | const enum_has_field = names.orderedRemove(field_name); | |
| 19173 | if (!enum_has_field) { | |
| 19633 | try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); | |
| 19634 | ||
| 19635 | for (0..fields_len) |i| { | |
| 19636 | const elem_val = try fields_val.elemValue(mod, i); | |
| 19637 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 19638 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19639 | try ip.getOrPutString(gpa, "name"), | |
| 19640 | ).?); | |
| 19641 | const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19642 | try ip.getOrPutString(gpa, "type"), | |
| 19643 | ).?); | |
| 19644 | const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19645 | try ip.getOrPutString(gpa, "alignment"), | |
| 19646 | ).?); | |
| 19647 | ||
| 19648 | const field_name = try name_val.toIpString(Type.slice_const_u8, mod); | |
| 19649 | ||
| 19650 | if (enum_field_names.len != 0) { | |
| 19651 | enum_field_names[i] = field_name; | |
| 19652 | } | |
| 19653 | ||
| 19654 | if (explicit_tags_seen.len > 0) { | |
| 19655 | const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type; | |
| 19656 | const enum_index = tag_info.nameIndex(ip, field_name) orelse { | |
| 19174 | 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) }); | |
| 19176 | errdefer msg.destroy(sema.gpa); | |
| 19658 | const msg = try sema.errMsg(block, src, "no field named '{}' in enum '{}'", .{ | |
| 19659 | field_name.fmt(ip), | |
| 19660 | union_obj.tag_ty.fmt(mod), | |
| 19661 | }); | |
| 19662 | errdefer msg.destroy(gpa); | |
| 19177 | 19663 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 19178 | 19664 | break :msg msg; |
| 19179 | 19665 | }; |
| 19180 | 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 | 19674 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 19185 | 19675 | if (gop.found_existing) { |
| 19186 | 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; | |
| 19191 | const field_ty = try type_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 19680 | const field_ty = type_val.toType(); | |
| 19192 | 19681 | gop.value_ptr.* = .{ |
| 19193 | 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 | 19687 | const msg = msg: { |
| 19199 | 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 | 19691 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19203 | 19692 | break :msg msg; |
| ... | ... | @@ -19206,23 +19695,23 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 19206 | 19695 | } |
| 19207 | 19696 | if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { |
| 19208 | 19697 | const msg = msg: { |
| 19209 | const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | |
| 19210 | errdefer msg.destroy(sema.gpa); | |
| 19698 | const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); | |
| 19699 | errdefer msg.destroy(gpa); | |
| 19211 | 19700 | |
| 19212 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 19213 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), field_ty, .union_field); | |
| 19701 | const src_decl = mod.declPtr(block.src_decl); | |
| 19702 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field); | |
| 19214 | 19703 | |
| 19215 | 19704 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19216 | 19705 | break :msg msg; |
| 19217 | 19706 | }; |
| 19218 | 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 | 19709 | const msg = msg: { |
| 19221 | const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | |
| 19222 | errdefer msg.destroy(sema.gpa); | |
| 19710 | const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); | |
| 19711 | errdefer msg.destroy(gpa); | |
| 19223 | 19712 | |
| 19224 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 19225 | try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl), field_ty); | |
| 19713 | const src_decl = mod.declPtr(block.src_decl); | |
| 19714 | try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty); | |
| 19226 | 19715 | |
| 19227 | 19716 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19228 | 19717 | break :msg msg; |
| ... | ... | @@ -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| { | |
| 19235 | if (names.count() > 0) { | |
| 19723 | if (explicit_tags_seen.len > 0) { | |
| 19724 | const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type; | |
| 19725 | if (tag_info.names.len > fields_len) { | |
| 19236 | 19726 | const msg = msg: { |
| 19237 | 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 | 19730 | const enum_ty = union_obj.tag_ty; |
| 19241 | for (names.keys()) |field_name| { | |
| 19242 | const field_index = enum_ty.enumFieldIndex(field_name).?; | |
| 19243 | try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); | |
| 19731 | for (tag_info.names, 0..) |field_name, field_index| { | |
| 19732 | if (explicit_tags_seen[field_index]) continue; | |
| 19733 | try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{ | |
| 19734 | field_name.fmt(ip), | |
| 19735 | }); | |
| 19244 | 19736 | } |
| 19245 | 19737 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 19246 | 19738 | break :msg msg; |
| 19247 | 19739 | }; |
| 19248 | 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); | |
| 19253 | return sema.analyzeDeclVal(block, src, new_decl_index); | |
| 19746 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | |
| 19747 | try mod.finalizeAnonDecl(new_decl_index); | |
| 19748 | return decl_val; | |
| 19254 | 19749 | }, |
| 19255 | 19750 | .Fn => { |
| 19256 | const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data; | |
| 19257 | // TODO use reflection instead of magic numbers here | |
| 19258 | // calling_convention: CallingConvention, | |
| 19259 | const cc = struct_val[0].toEnum(std.builtin.CallingConvention); | |
| 19260 | // alignment: comptime_int, | |
| 19261 | const alignment_val = struct_val[1]; | |
| 19262 | // is_generic: bool, | |
| 19263 | const is_generic = struct_val[2].toBool(); | |
| 19264 | // is_var_args: bool, | |
| 19265 | const is_var_args = struct_val[3].toBool(); | |
| 19266 | // return_type: ?type, | |
| 19267 | const return_type_val = struct_val[4]; | |
| 19268 | // args: []const Param, | |
| 19269 | const args_val = struct_val[5]; | |
| 19270 | ||
| 19751 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 19752 | const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19753 | try ip.getOrPutString(gpa, "calling_convention"), | |
| 19754 | ).?); | |
| 19755 | const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19756 | try ip.getOrPutString(gpa, "alignment"), | |
| 19757 | ).?); | |
| 19758 | const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19759 | try ip.getOrPutString(gpa, "is_generic"), | |
| 19760 | ).?); | |
| 19761 | const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 19762 | try ip.getOrPutString(gpa, "is_var_args"), | |
| 19763 | ).?); | |
| 19764 | const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 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 | 19772 | if (is_generic) { |
| 19272 | 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 | 19778 | if (is_var_args and cc != .C) { |
| 19276 | 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 | 19783 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { |
| 19281 | 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 | 19787 | if (alignment == target_util.defaultFunctionAlignment(target)) { |
| 19285 | break :alignment 0; | |
| 19788 | break :alignment .none; | |
| 19286 | 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 | 19794 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| 19292 | 19795 | |
| 19293 | var buf: Value.ToTypeBuffer = undefined; | |
| 19294 | ||
| 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); | |
| 19796 | const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod)); | |
| 19797 | const param_types = try sema.arena.alloc(InternPool.Index, args_len); | |
| 19300 | 19798 | |
| 19301 | 19799 | var noalias_bits: u32 = 0; |
| 19302 | var i: usize = 0; | |
| 19303 | while (i < args_len) : (i += 1) { | |
| 19304 | var arg_buf: Value.ElemValueBuffer = undefined; | |
| 19305 | const arg = args_slice_val.ptr.elemValueBuffer(mod, i, &arg_buf); | |
| 19306 | const arg_val = arg.castTag(.aggregate).?.data; | |
| 19307 | // TODO use reflection instead of magic numbers here | |
| 19308 | // is_generic: bool, | |
| 19309 | const arg_is_generic = arg_val[0].toBool(); | |
| 19310 | // is_noalias: bool, | |
| 19311 | const arg_is_noalias = arg_val[1].toBool(); | |
| 19312 | // type: ?type, | |
| 19313 | const param_type_opt_val = arg_val[2]; | |
| 19314 | ||
| 19315 | if (arg_is_generic) { | |
| 19800 | for (param_types, 0..) |*param_type, i| { | |
| 19801 | const elem_val = try params_val.elemValue(mod, i); | |
| 19802 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 19803 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19804 | try ip.getOrPutString(gpa, "is_generic"), | |
| 19805 | ).?); | |
| 19806 | const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19807 | try ip.getOrPutString(gpa, "is_noalias"), | |
| 19808 | ).?); | |
| 19809 | const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19810 | try ip.getOrPutString(gpa, "type"), | |
| 19811 | ).?); | |
| 19812 | ||
| 19813 | if (param_is_generic_val.toBool()) { | |
| 19316 | 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 | 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) { | |
| 19324 | if (!param_type.isPtrAtRuntime()) { | |
| 19821 | if (param_is_noalias_val.toBool()) { | |
| 19822 | if (!param_type.toType().isPtrAtRuntime(mod)) { | |
| 19325 | 19823 | return sema.fail(block, src, "non-pointer parameter declared noalias", .{}); |
| 19326 | 19824 | } |
| 19327 | 19825 | noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse |
| 19328 | 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 | 19831 | .param_types = param_types, |
| 19337 | .comptime_params = comptime_params.ptr, | |
| 19832 | .comptime_bits = 0, | |
| 19338 | 19833 | .noalias_bits = noalias_bits, |
| 19339 | .return_type = try return_type.toType(&buf).copy(sema.arena), | |
| 19834 | .return_type = return_type.toIntern(), | |
| 19340 | 19835 | .alignment = alignment, |
| 19341 | 19836 | .cc = cc, |
| 19342 | 19837 | .is_var_args = is_var_args, |
| ... | ... | @@ -19346,9 +19841,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 19346 | 19841 | .cc_is_generic = false, |
| 19347 | 19842 | .section_is_generic = false, |
| 19348 | 19843 | .addrspace_is_generic = false, |
| 19349 | }; | |
| 19350 | ||
| 19351 | const ty = try Type.Tag.function.create(sema.arena, fn_info); | |
| 19844 | }); | |
| 19352 | 19845 | return sema.addType(ty); |
| 19353 | 19846 | }, |
| 19354 | 19847 | .Frame => return sema.failWithUseOfAsync(block, src), |
| ... | ... | @@ -19366,22 +19859,34 @@ fn reifyStruct( |
| 19366 | 19859 | name_strategy: Zir.Inst.NameStrategy, |
| 19367 | 19860 | is_tuple: bool, |
| 19368 | 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 | 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 | 19870 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 19378 | .ty = Type.type, | |
| 19379 | .val = new_struct_val, | |
| 19871 | .ty = Type.noreturn, | |
| 19872 | .val = Value.@"unreachable", | |
| 19380 | 19873 | }, name_strategy, "struct", inst); |
| 19381 | 19874 | const new_decl = mod.declPtr(new_decl_index); |
| 19382 | 19875 | new_decl.owns_tv = true; |
| 19383 | errdefer mod.abortAnonDecl(new_decl_index); | |
| 19384 | struct_obj.* = .{ | |
| 19876 | errdefer { | |
| 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 | 19890 | .owner_decl = new_decl_index, |
| 19386 | 19891 | .fields = .{}, |
| 19387 | 19892 | .zir_index = inst, |
| ... | ... | @@ -19389,38 +19894,49 @@ fn reifyStruct( |
| 19389 | 19894 | .status = .have_field_types, |
| 19390 | 19895 | .known_non_opv = false, |
| 19391 | 19896 | .is_tuple = is_tuple, |
| 19392 | .namespace = .{ | |
| 19393 | .parent = block.namespace, | |
| 19394 | .ty = struct_ty, | |
| 19395 | .file_scope = block.getFileScope(), | |
| 19396 | }, | |
| 19397 | }; | |
| 19897 | .namespace = new_namespace_index, | |
| 19898 | }); | |
| 19899 | const struct_obj = mod.structPtr(struct_index); | |
| 19900 | errdefer mod.destroyStruct(struct_index); | |
| 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 | 19913 | // Fields |
| 19402 | 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 | 19916 | var i: usize = 0; |
| 19405 | 19917 | while (i < fields_len) : (i += 1) { |
| 19406 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); | |
| 19407 | const field_struct_val = elem_val.castTag(.aggregate).?.data; | |
| 19408 | // TODO use reflection instead of magic numbers here | |
| 19409 | // name: []const u8 | |
| 19410 | const name_val = field_struct_val[0]; | |
| 19411 | // type: type, | |
| 19412 | const type_val = field_struct_val[1]; | |
| 19413 | // default_value: ?*const anyopaque, | |
| 19414 | const default_value_val = field_struct_val[2]; | |
| 19415 | // is_comptime: bool, | |
| 19416 | const is_comptime_val = field_struct_val[3]; | |
| 19417 | // alignment: comptime_int, | |
| 19418 | const alignment_val = field_struct_val[4]; | |
| 19918 | const elem_val = try fields_val.elemValue(mod, i); | |
| 19919 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 19920 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19921 | try ip.getOrPutString(gpa, "name"), | |
| 19922 | ).?); | |
| 19923 | const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19924 | try ip.getOrPutString(gpa, "type"), | |
| 19925 | ).?); | |
| 19926 | const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 19927 | try ip.getOrPutString(gpa, "default_value"), | |
| 19928 | ).?); | |
| 19929 | const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 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 | 19936 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { |
| 19421 | 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 | 19941 | if (layout == .Packed) { |
| 19426 | 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 | 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( | |
| 19434 | Type.initTag(.const_slice_u8), | |
| 19435 | new_decl_arena_allocator, | |
| 19436 | mod, | |
| 19437 | ); | |
| 19949 | const field_name = try name_val.toIpString(Type.slice_const_u8, mod); | |
| 19438 | 19950 | |
| 19439 | 19951 | if (is_tuple) { |
| 19440 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch { | |
| 19441 | return sema.fail( | |
| 19442 | block, | |
| 19443 | src, | |
| 19444 | "tuple cannot have non-numeric field '{s}'", | |
| 19445 | .{field_name}, | |
| 19446 | ); | |
| 19447 | }; | |
| 19952 | const field_index = field_name.toUnsigned(ip) orelse return sema.fail( | |
| 19953 | block, | |
| 19954 | src, | |
| 19955 | "tuple cannot have non-numeric field '{}'", | |
| 19956 | .{field_name.fmt(ip)}, | |
| 19957 | ); | |
| 19448 | 19958 | |
| 19449 | 19959 | if (field_index >= fields_len) { |
| 19450 | 19960 | return sema.fail( |
| ... | ... | @@ -19458,22 +19968,19 @@ fn reifyStruct( |
| 19458 | 19968 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); |
| 19459 | 19969 | if (gop.found_existing) { |
| 19460 | 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: { | |
| 19465 | const payload_val = if (opt_val.pointerDecl()) |opt_decl| | |
| 19466 | mod.declPtr(opt_decl).val | |
| 19467 | else | |
| 19468 | opt_val; | |
| 19469 | break :blk try payload_val.copy(new_decl_arena_allocator); | |
| 19470 | } else Value.initTag(.unreachable_value); | |
| 19471 | if (is_comptime_val.toBool() and default_val.tag() == .unreachable_value) { | |
| 19974 | const field_ty = type_val.toType(); | |
| 19975 | const default_val = if (default_value_val.optionalValue(mod)) |opt_val| | |
| 19976 | (try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse | |
| 19977 | return sema.failWithNeededComptime(block, src, "struct field default value must be comptime-known")).toIntern() | |
| 19978 | else | |
| 19979 | .none; | |
| 19980 | if (is_comptime_val.toBool() and default_val == .none) { | |
| 19472 | 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 | 19984 | gop.value_ptr.* = .{ |
| 19478 | 19985 | .ty = field_ty, |
| 19479 | 19986 | .abi_align = abi_align, |
| ... | ... | @@ -19482,20 +19989,20 @@ fn reifyStruct( |
| 19482 | 19989 | .offset = undefined, |
| 19483 | 19990 | }; |
| 19484 | 19991 | |
| 19485 | if (field_ty.zigTypeTag() == .Opaque) { | |
| 19992 | if (field_ty.zigTypeTag(mod) == .Opaque) { | |
| 19486 | 19993 | const msg = msg: { |
| 19487 | 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 | 19997 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19491 | 19998 | break :msg msg; |
| 19492 | 19999 | }; |
| 19493 | 20000 | return sema.failWithOwnedErrorMsg(msg); |
| 19494 | 20001 | } |
| 19495 | if (field_ty.zigTypeTag() == .NoReturn) { | |
| 20002 | if (field_ty.zigTypeTag(mod) == .NoReturn) { | |
| 19496 | 20003 | const msg = msg: { |
| 19497 | 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 | 20007 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19501 | 20008 | break :msg msg; |
| ... | ... | @@ -19505,22 +20012,22 @@ fn reifyStruct( |
| 19505 | 20012 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) { |
| 19506 | 20013 | const msg = msg: { |
| 19507 | 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 | 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 | 20020 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19514 | 20021 | break :msg msg; |
| 19515 | 20022 | }; |
| 19516 | 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 | 20025 | const msg = msg: { |
| 19519 | 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 | 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 | 20032 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19526 | 20033 | break :msg msg; |
| ... | ... | @@ -19536,7 +20043,7 @@ fn reifyStruct( |
| 19536 | 20043 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { |
| 19537 | 20044 | error.AnalysisFail => { |
| 19538 | 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 | 20047 | return err; |
| 19541 | 20048 | }, |
| 19542 | 20049 | else => return err, |
| ... | ... | @@ -19545,30 +20052,27 @@ fn reifyStruct( |
| 19545 | 20052 | |
| 19546 | 20053 | var fields_bit_sum: u64 = 0; |
| 19547 | 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| { | |
| 19552 | var buf: Value.ToTypeBuffer = undefined; | |
| 19553 | const backing_int_ty = payload.toType(&buf); | |
| 20058 | if (backing_int_val.optionalValue(mod)) |payload| { | |
| 20059 | const backing_int_ty = payload.toType(); | |
| 19554 | 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 | 20062 | } else { |
| 19557 | var buf: Type.Payload.Bits = .{ | |
| 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); | |
| 20063 | struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum)); | |
| 19562 | 20064 | } |
| 19563 | 20065 | |
| 19564 | 20066 | struct_obj.status = .have_layout; |
| 19565 | 20067 | } |
| 19566 | 20068 | |
| 19567 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 19568 | return sema.analyzeDeclVal(block, src, new_decl_index); | |
| 20069 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | |
| 20070 | try mod.finalizeAnonDecl(new_decl_index); | |
| 20071 | return decl_val; | |
| 19569 | 20072 | } |
| 19570 | 20073 | |
| 19571 | 20074 | fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20075 | const mod = sema.mod; | |
| 19572 | 20076 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 19573 | 20077 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 19574 | 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 | 20084 | |
| 19581 | 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 | 20088 | const src_addrspace = ptr_info.@"addrspace"; |
| 19585 | 20089 | if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) { |
| 19586 | 20090 | const msg = msg: { |
| ... | ... | @@ -19594,8 +20098,8 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 19594 | 20098 | |
| 19595 | 20099 | ptr_info.@"addrspace" = dest_addrspace; |
| 19596 | 20100 | const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); |
| 19597 | const dest_ty = if (ptr_ty.zigTypeTag() == .Optional) | |
| 19598 | try Type.optional(sema.arena, dest_ptr_ty) | |
| 20101 | const dest_ty = if (ptr_ty.zigTypeTag(mod) == .Optional) | |
| 20102 | try Type.optional(sema.arena, dest_ptr_ty, mod) | |
| 19599 | 20103 | else |
| 19600 | 20104 | dest_ptr_ty; |
| 19601 | 20105 | |
| ... | ... | @@ -19624,6 +20128,7 @@ fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.In |
| 19624 | 20128 | } |
| 19625 | 20129 | |
| 19626 | 20130 | fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20131 | const mod = sema.mod; | |
| 19627 | 20132 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 19628 | 20133 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 19629 | 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 | 20143 | errdefer msg.destroy(sema.gpa); |
| 19639 | 20144 | |
| 19640 | 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 | 20148 | try sema.addDeclaredHereNote(msg, arg_ty); |
| 19644 | 20149 | break :msg msg; |
| ... | ... | @@ -19685,6 +20190,7 @@ fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) |
| 19685 | 20190 | } |
| 19686 | 20191 | |
| 19687 | 20192 | fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20193 | const mod = sema.mod; | |
| 19688 | 20194 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 19689 | 20195 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 19690 | 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 | 20198 | var anon_decl = try block.startAnonDecl(); |
| 19693 | 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 | 20208 | const new_decl = try anon_decl.finish( |
| 19698 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | |
| 19699 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 20209 | decl_ty, | |
| 20210 | (try mod.intern(.{ .aggregate = .{ | |
| 20211 | .ty = decl_ty.toIntern(), | |
| 20212 | .storage = .{ .bytes = bytes }, | |
| 20213 | } })).toValue(), | |
| 19700 | 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 | 20230 | } |
| 19717 | 20231 | |
| 19718 | 20232 | fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20233 | const mod = sema.mod; | |
| 19719 | 20234 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19720 | 20235 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 19721 | 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 | 20245 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 19731 | 20246 | const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty); |
| 19732 | 20247 | return sema.addConstant(dest_ty, result_val); |
| 19733 | } else if (dest_ty.zigTypeTag() == .ComptimeInt) { | |
| 20248 | } else if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { | |
| 19734 | 20249 | return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime-known"); |
| 19735 | 20250 | } |
| 19736 | 20251 | |
| 19737 | 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 | 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 | 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 | 20260 | const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand); |
| 19746 | 20261 | if (block.wantSafety()) { |
| 19747 | 20262 | const back = try block.addTyOp(.int_to_float, operand_ty, result); |
| 19748 | 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)); | |
| 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)); | |
| 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))); | |
| 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 | 20266 | const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg); |
| 19752 | 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 | 20270 | } |
| 19756 | 20271 | |
| 19757 | 20272 | fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20273 | const mod = sema.mod; | |
| 19758 | 20274 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19759 | 20275 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 19760 | 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 | 20285 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 19770 | 20286 | const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, sema.mod, sema); |
| 19771 | 20287 | return sema.addConstant(dest_ty, result_val); |
| 19772 | } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { | |
| 20288 | } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) { | |
| 19773 | 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 | 20294 | } |
| 19779 | 20295 | |
| 19780 | 20296 | fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20297 | const mod = sema.mod; | |
| 19781 | 20298 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19782 | 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 | 20307 | const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 19791 | 20308 | const ptr_ty = try sema.resolveType(block, src, extra.lhs); |
| 19792 | 20309 | try sema.checkPtrType(block, type_src, ptr_ty); |
| 19793 | const elem_ty = ptr_ty.elemType2(); | |
| 19794 | const target = sema.mod.getTarget(); | |
| 19795 | const ptr_align = try ptr_ty.ptrAlignmentAdvanced(target, sema); | |
| 20310 | const elem_ty = ptr_ty.elemType2(mod); | |
| 20311 | const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema); | |
| 19796 | 20312 | |
| 19797 | if (ptr_ty.isSlice()) { | |
| 20313 | if (ptr_ty.isSlice(mod)) { | |
| 19798 | 20314 | const msg = msg: { |
| 19799 | 20315 | const msg = try sema.errMsg(block, type_src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(sema.mod)}); |
| 19800 | 20316 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -19805,36 +20321,26 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 19805 | 20321 | } |
| 19806 | 20322 | |
| 19807 | 20323 | if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| { |
| 19808 | const addr = val.toUnsignedInt(target); | |
| 19809 | if (!ptr_ty.isAllowzeroPtr() and addr == 0) | |
| 20324 | const addr = val.toUnsignedInt(mod); | |
| 20325 | if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0) | |
| 19810 | 20326 | return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)}); |
| 19811 | 20327 | if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0) |
| 19812 | 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); | |
| 19815 | val_payload.* = .{ | |
| 19816 | .base = .{ .tag = .int_u64 }, | |
| 19817 | .data = addr, | |
| 19818 | }; | |
| 19819 | return sema.addConstant(ptr_ty, Value.initPayload(&val_payload.base)); | |
| 20330 | return sema.addConstant(ptr_ty, try mod.ptrIntValue(ptr_ty, addr)); | |
| 19820 | 20331 | } |
| 19821 | 20332 | |
| 19822 | 20333 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 19823 | if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag() == .Fn)) { | |
| 19824 | if (!ptr_ty.isAllowzeroPtr()) { | |
| 20334 | if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) { | |
| 20335 | if (!ptr_ty.isAllowzeroPtr(mod)) { | |
| 19825 | 20336 | const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize); |
| 19826 | 20337 | try sema.addSafetyCheck(block, is_non_zero, .cast_to_null); |
| 19827 | 20338 | } |
| 19828 | 20339 | |
| 19829 | 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 | 20341 | const align_minus_1 = try sema.addConstant( |
| 19836 | 20342 | Type.usize, |
| 19837 | Value.initPayload(&val_payload.base), | |
| 20343 | try mod.intValue(Type.usize, ptr_align - 1), | |
| 19838 | 20344 | ); |
| 19839 | 20345 | const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); |
| 19840 | 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 | 20351 | } |
| 19846 | 20352 | |
| 19847 | 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 | 20356 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 19849 | 20357 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 19850 | 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 | 20368 | |
| 19861 | 20369 | if (disjoint: { |
| 19862 | 20370 | // Try avoiding resolving inferred error sets if we can |
| 19863 | if (!dest_ty.isAnyError() and dest_ty.errorSetNames().len == 0) break :disjoint true; | |
| 19864 | if (!operand_ty.isAnyError() and operand_ty.errorSetNames().len == 0) break :disjoint true; | |
| 19865 | if (dest_ty.isAnyError()) break :disjoint false; | |
| 19866 | if (operand_ty.isAnyError()) break :disjoint false; | |
| 19867 | for (dest_ty.errorSetNames()) |dest_err_name| | |
| 19868 | if (operand_ty.errorSetHasField(dest_err_name)) | |
| 20371 | if (!dest_ty.isAnyError(mod) and dest_ty.errorSetNames(mod).len == 0) break :disjoint true; | |
| 20372 | if (!operand_ty.isAnyError(mod) and operand_ty.errorSetNames(mod).len == 0) break :disjoint true; | |
| 20373 | if (dest_ty.isAnyError(mod)) break :disjoint false; | |
| 20374 | if (operand_ty.isAnyError(mod)) break :disjoint false; | |
| 20375 | for (dest_ty.errorSetNames(mod)) |dest_err_name| { | |
| 20376 | if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name)) | |
| 19869 | 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 | 20383 | break :disjoint true; |
| 20384 | } | |
| 19873 | 20385 | |
| 19874 | 20386 | try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty); |
| 19875 | 20387 | try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty); |
| 19876 | for (dest_ty.errorSetNames()) |dest_err_name| | |
| 19877 | if (operand_ty.errorSetHasField(dest_err_name)) | |
| 20388 | for (dest_ty.errorSetNames(mod)) |dest_err_name| { | |
| 20389 | if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name)) | |
| 19878 | 20390 | break :disjoint false; |
| 20391 | } | |
| 19879 | 20392 | |
| 19880 | 20393 | break :disjoint true; |
| 19881 | 20394 | }) { |
| ... | ... | @@ -19895,15 +20408,15 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 19895 | 20408 | } |
| 19896 | 20409 | |
| 19897 | 20410 | if (maybe_operand_val) |val| { |
| 19898 | if (!dest_ty.isAnyError()) { | |
| 19899 | const error_name = val.castTag(.@"error").?.data.name; | |
| 19900 | if (!dest_ty.errorSetHasField(error_name)) { | |
| 20411 | if (!dest_ty.isAnyError(mod)) { | |
| 20412 | const error_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; | |
| 20413 | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), error_name)) { | |
| 19901 | 20414 | const msg = msg: { |
| 19902 | 20415 | const msg = try sema.errMsg( |
| 19903 | 20416 | block, |
| 19904 | 20417 | src, |
| 19905 | "'error.{s}' not a member of error set '{}'", | |
| 19906 | .{ error_name, dest_ty.fmt(sema.mod) }, | |
| 20418 | "'error.{}' not a member of error set '{}'", | |
| 20419 | .{ error_name.fmt(ip), dest_ty.fmt(sema.mod) }, | |
| 19907 | 20420 | ); |
| 19908 | 20421 | errdefer msg.destroy(sema.gpa); |
| 19909 | 20422 | try sema.addDeclaredHereNote(msg, dest_ty); |
| ... | ... | @@ -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 | 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 | 20434 | const err_int_inst = try block.addBitCast(Type.err_int, operand); |
| 19922 | 20435 | const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); |
| 19923 | 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 | 20439 | } |
| 19927 | 20440 | |
| 19928 | 20441 | fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20442 | const mod = sema.mod; | |
| 19929 | 20443 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19930 | 20444 | const src = inst_data.src(); |
| 19931 | 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 | 20448 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 19935 | 20449 | const operand = try sema.resolveInst(extra.rhs); |
| 19936 | 20450 | const operand_ty = sema.typeOf(operand); |
| 19937 | const target = sema.mod.getTarget(); | |
| 19938 | 20451 | |
| 19939 | 20452 | try sema.checkPtrType(block, dest_ty_src, dest_ty); |
| 19940 | 20453 | try sema.checkPtrOperand(block, operand_src, operand_ty); |
| 19941 | 20454 | |
| 19942 | const operand_info = operand_ty.ptrInfo().data; | |
| 19943 | const dest_info = dest_ty.ptrInfo().data; | |
| 20455 | const operand_info = operand_ty.ptrInfo(mod); | |
| 20456 | const dest_info = dest_ty.ptrInfo(mod); | |
| 19944 | 20457 | if (!operand_info.mutable and dest_info.mutable) { |
| 19945 | 20458 | const msg = msg: { |
| 19946 | 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 | 20485 | return sema.failWithOwnedErrorMsg(msg); |
| 19973 | 20486 | } |
| 19974 | 20487 | |
| 19975 | const dest_is_slice = dest_ty.isSlice(); | |
| 19976 | const operand_is_slice = operand_ty.isSlice(); | |
| 20488 | const dest_is_slice = dest_ty.isSlice(mod); | |
| 20489 | const operand_is_slice = operand_ty.isSlice(mod); | |
| 19977 | 20490 | if (dest_is_slice and !operand_is_slice) { |
| 19978 | 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 | 20495 | else |
| 19983 | 20496 | operand; |
| 19984 | 20497 | |
| 19985 | const dest_elem_ty = dest_ty.elemType2(); | |
| 20498 | const dest_elem_ty = dest_ty.elemType2(mod); | |
| 19986 | 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 | 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 | 20506 | // If the destination is less aligned than the source, preserve the source alignment |
| 19994 | 20507 | const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: { |
| 19995 | 20508 | // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result |
| 19996 | if (dest_ty.zigTypeTag() == .Optional) { | |
| 19997 | var buf: Type.Payload.ElemType = undefined; | |
| 19998 | var dest_ptr_info = dest_ty.optionalChild(&buf).ptrInfo().data; | |
| 20509 | if (dest_ty.zigTypeTag(mod) == .Optional) { | |
| 20510 | var dest_ptr_info = dest_ty.optionalChild(mod).ptrInfo(mod); | |
| 19999 | 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 | 20513 | } else { |
| 20002 | var dest_ptr_info = dest_ty.ptrInfo().data; | |
| 20514 | var dest_ptr_info = dest_ty.ptrInfo(mod); | |
| 20003 | 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 | 20520 | if (dest_is_slice) { |
| 20009 | const operand_elem_size = operand_elem_ty.abiSize(target); | |
| 20010 | const dest_elem_size = dest_elem_ty.abiSize(target); | |
| 20521 | const operand_elem_size = operand_elem_ty.abiSize(mod); | |
| 20522 | const dest_elem_size = dest_elem_ty.abiSize(mod); | |
| 20011 | 20523 | if (operand_elem_size != dest_elem_size) { |
| 20012 | 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 | 20531 | errdefer msg.destroy(sema.gpa); |
| 20020 | 20532 | |
| 20021 | 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 | 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 | 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 | 20544 | } |
| 20033 | 20545 | |
| 20034 | 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 | 20548 | return sema.failWithUseOfUndef(block, operand_src); |
| 20037 | 20549 | } |
| 20038 | if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) { | |
| 20039 | return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.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)); | |
| 20550 | if (!dest_ty.ptrAllowsZero(mod) and operand_val.isNull(mod)) { | |
| 20551 | return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)}); | |
| 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 | 20556 | try sema.requireRuntimeBlock(block, src, null); |
| 20048 | if (block.wantSafety() and operand_ty.ptrAllowsZero() and !dest_ty.ptrAllowsZero() and | |
| 20049 | (try sema.typeHasRuntimeBits(dest_ty.elemType2()) or dest_ty.elemType2().zigTypeTag() == .Fn)) | |
| 20557 | if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and | |
| 20558 | (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn)) | |
| 20050 | 20559 | { |
| 20051 | 20560 | const ptr_int = try block.addUnOp(.ptrtoint, ptr); |
| 20052 | 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 | 20571 | } |
| 20063 | 20572 | |
| 20064 | 20573 | fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20574 | const mod = sema.mod; | |
| 20065 | 20575 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 20066 | 20576 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 20067 | 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 | 20579 | const operand_ty = sema.typeOf(operand); |
| 20070 | 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 | 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 | 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 | 20590 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -20082,6 +20592,7 @@ fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 20082 | 20592 | } |
| 20083 | 20593 | |
| 20084 | 20594 | fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20595 | const mod = sema.mod; | |
| 20085 | 20596 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 20086 | 20597 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 20087 | 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 | 20600 | const operand_ty = sema.typeOf(operand); |
| 20090 | 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 | 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 | 20607 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { |
| 20097 | 20608 | return sema.addConstant(dest_ty, operand_val); |
| ... | ... | @@ -20102,6 +20613,7 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 20102 | 20613 | } |
| 20103 | 20614 | |
| 20104 | 20615 | fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20616 | const mod = sema.mod; | |
| 20105 | 20617 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 20106 | 20618 | const src = inst_data.src(); |
| 20107 | 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 | 20624 | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty); |
| 20113 | 20625 | const operand_ty = sema.typeOf(operand); |
| 20114 | 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 | 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 | 20633 | else |
| 20119 | 20634 | dest_scalar_ty; |
| 20120 | 20635 | |
| ... | ... | @@ -20122,22 +20637,21 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20122 | 20637 | return sema.coerce(block, dest_ty, operand, operand_src); |
| 20123 | 20638 | } |
| 20124 | 20639 | |
| 20125 | const target = sema.mod.getTarget(); | |
| 20126 | const dest_info = dest_scalar_ty.intInfo(target); | |
| 20640 | const dest_info = dest_scalar_ty.intInfo(mod); | |
| 20127 | 20641 | |
| 20128 | 20642 | if (try sema.typeHasOnePossibleValue(dest_ty)) |val| { |
| 20129 | 20643 | return sema.addConstant(dest_ty, val); |
| 20130 | 20644 | } |
| 20131 | 20645 | |
| 20132 | if (operand_scalar_ty.zigTypeTag() != .ComptimeInt) { | |
| 20133 | const operand_info = operand_ty.intInfo(target); | |
| 20646 | if (operand_scalar_ty.zigTypeTag(mod) != .ComptimeInt) { | |
| 20647 | const operand_info = operand_ty.intInfo(mod); | |
| 20134 | 20648 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { |
| 20135 | 20649 | return sema.addConstant(operand_ty, val); |
| 20136 | 20650 | } |
| 20137 | 20651 | |
| 20138 | 20652 | if (operand_info.signedness != dest_info.signedness) { |
| 20139 | 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 | 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 | 20660 | block, |
| 20147 | 20661 | src, |
| 20148 | 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 | 20665 | errdefer msg.destroy(sema.gpa); |
| 20152 | 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 | 20676 | } |
| 20163 | 20677 | |
| 20164 | 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 | 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 | 20683 | dest_ty, |
| 20169 | try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, sema.mod), | |
| 20170 | ); | |
| 20684 | )); | |
| 20171 | 20685 | } |
| 20172 | var elem_buf: Value.ElemValueBuffer = undefined; | |
| 20173 | const elems = try sema.arena.alloc(Value, operand_ty.vectorLen()); | |
| 20686 | const elems = try sema.arena.alloc(InternPool.Index, operand_ty.vectorLen(mod)); | |
| 20174 | 20687 | for (elems, 0..) |*elem, i| { |
| 20175 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | |
| 20176 | elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, sema.mod); | |
| 20688 | const elem_val = try val.elemValue(mod, i); | |
| 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( | |
| 20179 | dest_ty, | |
| 20180 | try Value.Tag.aggregate.create(sema.arena, elems), | |
| 20181 | ); | |
| 20691 | return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ | |
| 20692 | .ty = dest_ty.toIntern(), | |
| 20693 | .storage = .{ .elems = elems }, | |
| 20694 | } })).toValue()); | |
| 20182 | 20695 | } |
| 20183 | 20696 | |
| 20184 | 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 | 20699 | } |
| 20187 | 20700 | |
| 20188 | 20701 | fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20702 | const mod = sema.mod; | |
| 20189 | 20703 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 20190 | 20704 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 20191 | 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 | 20710 | |
| 20197 | 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 | 20714 | ptr_info.@"align" = dest_align; |
| 20201 | var dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); | |
| 20202 | if (ptr_ty.zigTypeTag() == .Optional) { | |
| 20203 | dest_ty = try Type.Tag.optional.create(sema.arena, dest_ty); | |
| 20715 | var dest_ty = try Type.ptr(sema.arena, mod, ptr_info); | |
| 20716 | if (ptr_ty.zigTypeTag(mod) == .Optional) { | |
| 20717 | dest_ty = try mod.optionalType(dest_ty.toIntern()); | |
| 20204 | 20718 | } |
| 20205 | 20719 | |
| 20206 | 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 | 20722 | if (addr % dest_align != 0) { |
| 20209 | 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 | 20729 | try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); |
| 20216 | 20730 | if (block.wantSafety() and dest_align > 1 and |
| 20217 | 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 | 20733 | const align_minus_1 = try sema.addConstant( |
| 20225 | 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 | 20738 | try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty) |
| 20230 | 20739 | else |
| 20231 | 20740 | ptr; |
| 20232 | 20741 | const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); |
| 20233 | 20742 | const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); |
| 20234 | 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 | 20745 | const len = try sema.analyzeSliceLen(block, ptr_src, ptr); |
| 20237 | 20746 | const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); |
| 20238 | 20747 | break :ok try block.addBinOp(.bit_or, len_zero, is_aligned); |
| ... | ... | @@ -20247,51 +20756,52 @@ fn zirBitCount( |
| 20247 | 20756 | block: *Block, |
| 20248 | 20757 | inst: Zir.Inst.Index, |
| 20249 | 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 | 20760 | ) CompileError!Air.Inst.Ref { |
| 20761 | const mod = sema.mod; | |
| 20252 | 20762 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 20253 | 20763 | const src = inst_data.src(); |
| 20254 | 20764 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 20255 | 20765 | const operand = try sema.resolveInst(inst_data.operand); |
| 20256 | 20766 | const operand_ty = sema.typeOf(operand); |
| 20257 | 20767 | _ = try sema.checkIntOrVector(block, operand, operand_src); |
| 20258 | const target = sema.mod.getTarget(); | |
| 20259 | const bits = operand_ty.intInfo(target).bits; | |
| 20768 | const bits = operand_ty.intInfo(mod).bits; | |
| 20260 | 20769 | |
| 20261 | 20770 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { |
| 20262 | 20771 | return sema.addConstant(operand_ty, val); |
| 20263 | 20772 | } |
| 20264 | 20773 | |
| 20265 | const result_scalar_ty = try Type.smallestUnsignedInt(sema.arena, bits); | |
| 20266 | switch (operand_ty.zigTypeTag()) { | |
| 20774 | const result_scalar_ty = try mod.smallestUnsignedInt(bits); | |
| 20775 | switch (operand_ty.zigTypeTag(mod)) { | |
| 20267 | 20776 | .Vector => { |
| 20268 | const vec_len = operand_ty.vectorLen(); | |
| 20269 | const result_ty = try Type.vector(sema.arena, vec_len, result_scalar_ty); | |
| 20777 | const vec_len = operand_ty.vectorLen(mod); | |
| 20778 | const result_ty = try mod.vectorType(.{ | |
| 20779 | .len = vec_len, | |
| 20780 | .child = result_scalar_ty.toIntern(), | |
| 20781 | }); | |
| 20270 | 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; | |
| 20274 | const elems = try sema.arena.alloc(Value, vec_len); | |
| 20275 | const scalar_ty = operand_ty.scalarType(); | |
| 20785 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 20786 | const scalar_ty = operand_ty.scalarType(mod); | |
| 20276 | 20787 | for (elems, 0..) |*elem, i| { |
| 20277 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | |
| 20278 | const count = comptimeOp(elem_val, scalar_ty, target); | |
| 20279 | elem.* = try Value.Tag.int_u64.create(sema.arena, count); | |
| 20280 | } | |
| 20281 | return sema.addConstant( | |
| 20282 | result_ty, | |
| 20283 | try Value.Tag.aggregate.create(sema.arena, elems), | |
| 20284 | ); | |
| 20788 | const elem_val = try val.elemValue(mod, i); | |
| 20789 | const count = comptimeOp(elem_val, scalar_ty, mod); | |
| 20790 | elem.* = (try mod.intValue(result_scalar_ty, count)).toIntern(); | |
| 20791 | } | |
| 20792 | return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{ | |
| 20793 | .ty = result_ty.toIntern(), | |
| 20794 | .storage = .{ .elems = elems }, | |
| 20795 | } })).toValue()); | |
| 20285 | 20796 | } else { |
| 20286 | 20797 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 20287 | 20798 | return block.addTyOp(air_tag, result_ty, operand); |
| 20288 | 20799 | } |
| 20289 | 20800 | }, |
| 20290 | 20801 | .Int => { |
| 20291 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | |
| 20292 | if (val.isUndef()) return sema.addConstUndef(result_scalar_ty); | |
| 20293 | try sema.resolveLazyValue(val); | |
| 20294 | return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, target)); | |
| 20802 | if (try sema.resolveMaybeUndefLazyVal(operand)) |val| { | |
| 20803 | if (val.isUndef(mod)) return sema.addConstUndef(result_scalar_ty); | |
| 20804 | return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, mod)); | |
| 20295 | 20805 | } else { |
| 20296 | 20806 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 20297 | 20807 | return block.addTyOp(air_tag, result_scalar_ty, operand); |
| ... | ... | @@ -20302,20 +20812,20 @@ fn zirBitCount( |
| 20302 | 20812 | } |
| 20303 | 20813 | |
| 20304 | 20814 | fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20815 | const mod = sema.mod; | |
| 20305 | 20816 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 20306 | 20817 | const src = inst_data.src(); |
| 20307 | 20818 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 20308 | 20819 | const operand = try sema.resolveInst(inst_data.operand); |
| 20309 | 20820 | const operand_ty = sema.typeOf(operand); |
| 20310 | 20821 | const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src); |
| 20311 | const target = sema.mod.getTarget(); | |
| 20312 | const bits = scalar_ty.intInfo(target).bits; | |
| 20822 | const bits = scalar_ty.intInfo(mod).bits; | |
| 20313 | 20823 | if (bits % 8 != 0) { |
| 20314 | 20824 | return sema.fail( |
| 20315 | 20825 | block, |
| 20316 | 20826 | operand_src, |
| 20317 | 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 | 20833 | return sema.addConstant(operand_ty, val); |
| 20324 | 20834 | } |
| 20325 | 20835 | |
| 20326 | switch (operand_ty.zigTypeTag()) { | |
| 20836 | switch (operand_ty.zigTypeTag(mod)) { | |
| 20327 | 20837 | .Int => { |
| 20328 | 20838 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20329 | if (val.isUndef()) return sema.addConstUndef(operand_ty); | |
| 20330 | const result_val = try val.byteSwap(operand_ty, target, sema.arena); | |
| 20839 | if (val.isUndef(mod)) return sema.addConstUndef(operand_ty); | |
| 20840 | const result_val = try val.byteSwap(operand_ty, mod, sema.arena); | |
| 20331 | 20841 | return sema.addConstant(operand_ty, result_val); |
| 20332 | 20842 | } else operand_src; |
| 20333 | 20843 | |
| ... | ... | @@ -20336,20 +20846,19 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20336 | 20846 | }, |
| 20337 | 20847 | .Vector => { |
| 20338 | 20848 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20339 | if (val.isUndef()) | |
| 20849 | if (val.isUndef(mod)) | |
| 20340 | 20850 | return sema.addConstUndef(operand_ty); |
| 20341 | 20851 | |
| 20342 | const vec_len = operand_ty.vectorLen(); | |
| 20343 | var elem_buf: Value.ElemValueBuffer = undefined; | |
| 20344 | const elems = try sema.arena.alloc(Value, vec_len); | |
| 20852 | const vec_len = operand_ty.vectorLen(mod); | |
| 20853 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 20345 | 20854 | for (elems, 0..) |*elem, i| { |
| 20346 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | |
| 20347 | elem.* = try elem_val.byteSwap(operand_ty, target, sema.arena); | |
| 20855 | const elem_val = try val.elemValue(mod, i); | |
| 20856 | elem.* = try (try elem_val.byteSwap(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod); | |
| 20348 | 20857 | } |
| 20349 | return sema.addConstant( | |
| 20350 | operand_ty, | |
| 20351 | try Value.Tag.aggregate.create(sema.arena, elems), | |
| 20352 | ); | |
| 20858 | return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{ | |
| 20859 | .ty = operand_ty.toIntern(), | |
| 20860 | .storage = .{ .elems = elems }, | |
| 20861 | } })).toValue()); | |
| 20353 | 20862 | } else operand_src; |
| 20354 | 20863 | |
| 20355 | 20864 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | ... | @@ -20371,12 +20880,12 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 20371 | 20880 | return sema.addConstant(operand_ty, val); |
| 20372 | 20881 | } |
| 20373 | 20882 | |
| 20374 | const target = sema.mod.getTarget(); | |
| 20375 | switch (operand_ty.zigTypeTag()) { | |
| 20883 | const mod = sema.mod; | |
| 20884 | switch (operand_ty.zigTypeTag(mod)) { | |
| 20376 | 20885 | .Int => { |
| 20377 | 20886 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20378 | if (val.isUndef()) return sema.addConstUndef(operand_ty); | |
| 20379 | const result_val = try val.bitReverse(operand_ty, target, sema.arena); | |
| 20887 | if (val.isUndef(mod)) return sema.addConstUndef(operand_ty); | |
| 20888 | const result_val = try val.bitReverse(operand_ty, mod, sema.arena); | |
| 20380 | 20889 | return sema.addConstant(operand_ty, result_val); |
| 20381 | 20890 | } else operand_src; |
| 20382 | 20891 | |
| ... | ... | @@ -20385,20 +20894,19 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 20385 | 20894 | }, |
| 20386 | 20895 | .Vector => { |
| 20387 | 20896 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20388 | if (val.isUndef()) | |
| 20897 | if (val.isUndef(mod)) | |
| 20389 | 20898 | return sema.addConstUndef(operand_ty); |
| 20390 | 20899 | |
| 20391 | const vec_len = operand_ty.vectorLen(); | |
| 20392 | var elem_buf: Value.ElemValueBuffer = undefined; | |
| 20393 | const elems = try sema.arena.alloc(Value, vec_len); | |
| 20900 | const vec_len = operand_ty.vectorLen(mod); | |
| 20901 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 20394 | 20902 | for (elems, 0..) |*elem, i| { |
| 20395 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | |
| 20396 | elem.* = try elem_val.bitReverse(scalar_ty, target, sema.arena); | |
| 20903 | const elem_val = try val.elemValue(mod, i); | |
| 20904 | elem.* = try (try elem_val.bitReverse(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod); | |
| 20397 | 20905 | } |
| 20398 | return sema.addConstant( | |
| 20399 | operand_ty, | |
| 20400 | try Value.Tag.aggregate.create(sema.arena, elems), | |
| 20401 | ); | |
| 20906 | return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{ | |
| 20907 | .ty = operand_ty.toIntern(), | |
| 20908 | .storage = .{ .elems = elems }, | |
| 20909 | } })).toValue()); | |
| 20402 | 20910 | } else operand_src; |
| 20403 | 20911 | |
| 20404 | 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 | 20936 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 20429 | 20937 | |
| 20430 | 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"); | |
| 20432 | const target = sema.mod.getTarget(); | |
| 20939 | const field_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, "name of field must be comptime-known"); | |
| 20433 | 20940 | |
| 20941 | const mod = sema.mod; | |
| 20434 | 20942 | try sema.resolveTypeLayout(ty); |
| 20435 | switch (ty.zigTypeTag()) { | |
| 20943 | switch (ty.zigTypeTag(mod)) { | |
| 20436 | 20944 | .Struct => {}, |
| 20437 | 20945 | else => { |
| 20438 | 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 | 20948 | errdefer msg.destroy(sema.gpa); |
| 20441 | 20949 | try sema.addDeclaredHereNote(msg, ty); |
| 20442 | 20950 | break :msg msg; |
| ... | ... | @@ -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: { | |
| 20449 | if (mem.eql(u8, field_name, "len")) { | |
| 20956 | const field_index = if (ty.isTuple(mod)) blk: { | |
| 20957 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { | |
| 20450 | 20958 | return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); |
| 20451 | 20959 | } |
| 20452 | 20960 | break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src); |
| 20453 | 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 | 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 | 20968 | .Packed => { |
| 20461 | 20969 | var bit_sum: u64 = 0; |
| 20462 | const fields = ty.structFields(); | |
| 20970 | const fields = ty.structFields(mod); | |
| 20463 | 20971 | for (fields.values(), 0..) |field, i| { |
| 20464 | 20972 | if (i == field_index) { |
| 20465 | 20973 | return bit_sum; |
| 20466 | 20974 | } |
| 20467 | bit_sum += field.ty.bitSize(target); | |
| 20975 | bit_sum += field.ty.bitSize(mod); | |
| 20468 | 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 | 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 | 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 | 20990 | /// Returns `true` if the type was a comptime_int. |
| 20482 | 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 | 20994 | .ComptimeInt => return true, |
| 20485 | 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 | 21003 | src: LazySrcLoc, |
| 20494 | 21004 | ty: Type, |
| 20495 | 21005 | ) CompileError!void { |
| 20496 | switch (try ty.zigTypeTagOrPoison()) { | |
| 20497 | .Pointer => switch (ty.ptrSize()) { | |
| 21006 | const mod = sema.mod; | |
| 21007 | switch (try ty.zigTypeTagOrPoison(mod)) { | |
| 21008 | .Pointer => switch (ty.ptrSize(mod)) { | |
| 20498 | 21009 | .One, .Slice => return, |
| 20499 | 21010 | .Many, .C => return sema.fail( |
| 20500 | 21011 | block, |
| ... | ... | @@ -20532,7 +21043,8 @@ fn checkPtrOperand( |
| 20532 | 21043 | ty_src: LazySrcLoc, |
| 20533 | 21044 | ty: Type, |
| 20534 | 21045 | ) CompileError!void { |
| 20535 | switch (ty.zigTypeTag()) { | |
| 21046 | const mod = sema.mod; | |
| 21047 | switch (ty.zigTypeTag(mod)) { | |
| 20536 | 21048 | .Pointer => return, |
| 20537 | 21049 | .Fn => { |
| 20538 | 21050 | const msg = msg: { |
| ... | ... | @@ -20540,7 +21052,7 @@ fn checkPtrOperand( |
| 20540 | 21052 | block, |
| 20541 | 21053 | ty_src, |
| 20542 | 21054 | "expected pointer, found '{}'", |
| 20543 | .{ty.fmt(sema.mod)}, | |
| 21055 | .{ty.fmt(mod)}, | |
| 20544 | 21056 | ); |
| 20545 | 21057 | errdefer msg.destroy(sema.gpa); |
| 20546 | 21058 | |
| ... | ... | @@ -20550,10 +21062,10 @@ fn checkPtrOperand( |
| 20550 | 21062 | }; |
| 20551 | 21063 | return sema.failWithOwnedErrorMsg(msg); |
| 20552 | 21064 | }, |
| 20553 | .Optional => if (ty.isPtrLikeOptional()) return, | |
| 21065 | .Optional => if (ty.isPtrLikeOptional(mod)) return, | |
| 20554 | 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 | 21071 | fn checkPtrType( |
| ... | ... | @@ -20562,7 +21074,8 @@ fn checkPtrType( |
| 20562 | 21074 | ty_src: LazySrcLoc, |
| 20563 | 21075 | ty: Type, |
| 20564 | 21076 | ) CompileError!void { |
| 20565 | switch (ty.zigTypeTag()) { | |
| 21077 | const mod = sema.mod; | |
| 21078 | switch (ty.zigTypeTag(mod)) { | |
| 20566 | 21079 | .Pointer => return, |
| 20567 | 21080 | .Fn => { |
| 20568 | 21081 | const msg = msg: { |
| ... | ... | @@ -20570,7 +21083,7 @@ fn checkPtrType( |
| 20570 | 21083 | block, |
| 20571 | 21084 | ty_src, |
| 20572 | 21085 | "expected pointer type, found '{}'", |
| 20573 | .{ty.fmt(sema.mod)}, | |
| 21086 | .{ty.fmt(mod)}, | |
| 20574 | 21087 | ); |
| 20575 | 21088 | errdefer msg.destroy(sema.gpa); |
| 20576 | 21089 | |
| ... | ... | @@ -20580,10 +21093,10 @@ fn checkPtrType( |
| 20580 | 21093 | }; |
| 20581 | 21094 | return sema.failWithOwnedErrorMsg(msg); |
| 20582 | 21095 | }, |
| 20583 | .Optional => if (ty.isPtrLikeOptional()) return, | |
| 21096 | .Optional => if (ty.isPtrLikeOptional(mod)) return, | |
| 20584 | 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 | 21102 | fn checkVectorElemType( |
| ... | ... | @@ -20592,11 +21105,12 @@ fn checkVectorElemType( |
| 20592 | 21105 | ty_src: LazySrcLoc, |
| 20593 | 21106 | ty: Type, |
| 20594 | 21107 | ) CompileError!void { |
| 20595 | switch (ty.zigTypeTag()) { | |
| 21108 | const mod = sema.mod; | |
| 21109 | switch (ty.zigTypeTag(mod)) { | |
| 20596 | 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 | 21116 | fn checkFloatType( |
| ... | ... | @@ -20605,9 +21119,10 @@ fn checkFloatType( |
| 20605 | 21119 | ty_src: LazySrcLoc, |
| 20606 | 21120 | ty: Type, |
| 20607 | 21121 | ) CompileError!void { |
| 20608 | switch (ty.zigTypeTag()) { | |
| 21122 | const mod = sema.mod; | |
| 21123 | switch (ty.zigTypeTag(mod)) { | |
| 20609 | 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 | 21132 | ty_src: LazySrcLoc, |
| 20618 | 21133 | ty: Type, |
| 20619 | 21134 | ) CompileError!void { |
| 20620 | switch (ty.zigTypeTag()) { | |
| 21135 | const mod = sema.mod; | |
| 21136 | switch (ty.zigTypeTag(mod)) { | |
| 20621 | 21137 | .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, |
| 20622 | .Vector => switch (ty.childType().zigTypeTag()) { | |
| 21138 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { | |
| 20623 | 21139 | .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, |
| 20624 | 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 | 21153 | ptr_src: LazySrcLoc, |
| 20638 | 21154 | ptr_const: bool, |
| 20639 | 21155 | ) CompileError!Air.Inst.Ref { |
| 20640 | const target = sema.mod.getTarget(); | |
| 20641 | var diag: target_util.AtomicPtrAlignmentDiagnostics = .{}; | |
| 20642 | const alignment = target_util.atomicPtrAlignment(target, elem_ty, &diag) catch |err| switch (err) { | |
| 21156 | const mod = sema.mod; | |
| 21157 | var diag: Module.AtomicPtrAlignmentDiagnostics = .{}; | |
| 21158 | const alignment = mod.atomicPtrAlignment(elem_ty, &diag) catch |err| switch (err) { | |
| 21159 | error.OutOfMemory => return error.OutOfMemory, | |
| 20643 | 21160 | error.FloatTooBig => return sema.fail( |
| 20644 | 21161 | block, |
| 20645 | 21162 | elem_ty_src, |
| ... | ... | @@ -20656,7 +21173,7 @@ fn checkAtomicPtrOperand( |
| 20656 | 21173 | block, |
| 20657 | 21174 | elem_ty_src, |
| 20658 | 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 | 21185 | }; |
| 20669 | 21186 | |
| 20670 | 21187 | const ptr_ty = sema.typeOf(ptr); |
| 20671 | const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison()) { | |
| 20672 | .Pointer => ptr_ty.ptrInfo().data, | |
| 21188 | const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) { | |
| 21189 | .Pointer => ptr_ty.ptrInfo(mod), | |
| 20673 | 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 | 21192 | _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 20676 | 21193 | unreachable; |
| 20677 | 21194 | }, |
| ... | ... | @@ -20681,7 +21198,7 @@ fn checkAtomicPtrOperand( |
| 20681 | 21198 | wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero"; |
| 20682 | 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 | 21202 | const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 20686 | 21203 | |
| 20687 | 21204 | return casted_ptr; |
| ... | ... | @@ -20695,7 +21212,7 @@ fn checkPtrIsNotComptimeMutable( |
| 20695 | 21212 | operand_src: LazySrcLoc, |
| 20696 | 21213 | ) CompileError!void { |
| 20697 | 21214 | _ = operand_src; |
| 20698 | if (ptr_val.isComptimeMutablePtr()) { | |
| 21215 | if (ptr_val.isComptimeMutablePtr(sema.mod)) { | |
| 20699 | 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 | 21221 | sema: *Sema, |
| 20705 | 21222 | block: *Block, |
| 20706 | 21223 | src: LazySrcLoc, |
| 20707 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | |
| 21224 | decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl, | |
| 20708 | 21225 | ) CompileError!void { |
| 20709 | 21226 | if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) { |
| 20710 | 21227 | if (block.runtime_cond) |cond_src| { |
| ... | ... | @@ -20735,20 +21252,21 @@ fn checkIntOrVector( |
| 20735 | 21252 | operand: Air.Inst.Ref, |
| 20736 | 21253 | operand_src: LazySrcLoc, |
| 20737 | 21254 | ) CompileError!Type { |
| 21255 | const mod = sema.mod; | |
| 20738 | 21256 | const operand_ty = sema.typeOf(operand); |
| 20739 | switch (try operand_ty.zigTypeTagOrPoison()) { | |
| 21257 | switch (try operand_ty.zigTypeTagOrPoison(mod)) { | |
| 20740 | 21258 | .Int => return operand_ty, |
| 20741 | 21259 | .Vector => { |
| 20742 | const elem_ty = operand_ty.childType(); | |
| 20743 | switch (try elem_ty.zigTypeTagOrPoison()) { | |
| 21260 | const elem_ty = operand_ty.childType(mod); | |
| 21261 | switch (try elem_ty.zigTypeTagOrPoison(mod)) { | |
| 20744 | 21262 | .Int => return elem_ty, |
| 20745 | 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 | 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 | 21277 | operand_ty: Type, |
| 20760 | 21278 | operand_src: LazySrcLoc, |
| 20761 | 21279 | ) CompileError!Type { |
| 20762 | switch (try operand_ty.zigTypeTagOrPoison()) { | |
| 21280 | const mod = sema.mod; | |
| 21281 | switch (try operand_ty.zigTypeTagOrPoison(mod)) { | |
| 20763 | 21282 | .Int, .ComptimeInt => return operand_ty, |
| 20764 | 21283 | .Vector => { |
| 20765 | const elem_ty = operand_ty.childType(); | |
| 20766 | switch (try elem_ty.zigTypeTagOrPoison()) { | |
| 21284 | const elem_ty = operand_ty.childType(mod); | |
| 21285 | switch (try elem_ty.zigTypeTagOrPoison(mod)) { | |
| 20767 | 21286 | .Int, .ComptimeInt => return elem_ty, |
| 20768 | 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 | 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 | 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 | 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 | 21325 | lhs_src: LazySrcLoc, |
| 20806 | 21326 | rhs_src: LazySrcLoc, |
| 20807 | 21327 | ) CompileError!SimdBinOp { |
| 21328 | const mod = sema.mod; | |
| 20808 | 21329 | const lhs_ty = sema.typeOf(uncasted_lhs); |
| 20809 | 21330 | const rhs_ty = sema.typeOf(uncasted_rhs); |
| 20810 | 21331 | |
| 20811 | 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 | 21334 | const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{ |
| 20814 | 21335 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 20815 | 21336 | }); |
| ... | ... | @@ -20823,7 +21344,7 @@ fn checkSimdBinOp( |
| 20823 | 21344 | .lhs_val = try sema.resolveMaybeUndefVal(lhs), |
| 20824 | 21345 | .rhs_val = try sema.resolveMaybeUndefVal(rhs), |
| 20825 | 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 | 21357 | lhs_src: LazySrcLoc, |
| 20837 | 21358 | rhs_src: LazySrcLoc, |
| 20838 | 21359 | ) CompileError!void { |
| 20839 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 20840 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 21360 | const mod = sema.mod; | |
| 21361 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | |
| 21362 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | |
| 20841 | 21363 | if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return; |
| 20842 | 21364 | |
| 20843 | 21365 | const lhs_is_vector = switch (lhs_zig_ty_tag) { |
| ... | ... | @@ -20850,8 +21372,8 @@ fn checkVectorizableBinaryOperands( |
| 20850 | 21372 | }; |
| 20851 | 21373 | |
| 20852 | 21374 | if (lhs_is_vector and rhs_is_vector) { |
| 20853 | const lhs_len = lhs_ty.arrayLen(); | |
| 20854 | const rhs_len = rhs_ty.arrayLen(); | |
| 21375 | const lhs_len = lhs_ty.arrayLen(mod); | |
| 21376 | const rhs_len = rhs_ty.arrayLen(mod); | |
| 20855 | 21377 | if (lhs_len != rhs_len) { |
| 20856 | 21378 | const msg = msg: { |
| 20857 | 21379 | const msg = try sema.errMsg(block, src, "vector length mismatch", .{}); |
| ... | ... | @@ -20865,7 +21387,7 @@ fn checkVectorizableBinaryOperands( |
| 20865 | 21387 | } else { |
| 20866 | 21388 | const msg = msg: { |
| 20867 | 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 | 21392 | errdefer msg.destroy(sema.gpa); |
| 20871 | 21393 | if (lhs_is_vector) { |
| ... | ... | @@ -20883,7 +21405,8 @@ fn checkVectorizableBinaryOperands( |
| 20883 | 21405 | |
| 20884 | 21406 | fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { |
| 20885 | 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 | 21412 | fn resolveExportOptions( |
| ... | ... | @@ -20891,7 +21414,10 @@ fn resolveExportOptions( |
| 20891 | 21414 | block: *Block, |
| 20892 | 21415 | src: LazySrcLoc, |
| 20893 | 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 | 21421 | const export_options_ty = try sema.getBuiltinType("ExportOptions"); |
| 20896 | 21422 | const air_ref = try sema.resolveInst(zir_ref); |
| 20897 | 21423 | const options = try sema.coerce(block, export_options_ty, air_ref, src); |
| ... | ... | @@ -20901,26 +21427,26 @@ fn resolveExportOptions( |
| 20901 | 21427 | const section_src = sema.maybeOptionsSrc(block, src, "section"); |
| 20902 | 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 | 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); | |
| 20907 | const name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod); | |
| 21432 | const name_ty = Type.slice_const_u8; | |
| 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 | 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 | 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); | |
| 20916 | const section = if (section_opt_val.optionalValue()) |section_val| | |
| 20917 | try section_val.toAllocatedBytes(section_ty, sema.arena, sema.mod) | |
| 21441 | const section_ty = Type.slice_const_u8; | |
| 21442 | const section = if (section_opt_val.optionalValue(mod)) |section_val| | |
| 21443 | try section_val.toAllocatedBytes(section_ty, sema.arena, mod) | |
| 20918 | 21444 | else |
| 20919 | 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 | 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 | 21451 | if (name.len < 1) { |
| 20926 | 21452 | return sema.fail(block, name_src, "exported symbol name cannot be empty", .{}); |
| ... | ... | @@ -20932,10 +21458,10 @@ fn resolveExportOptions( |
| 20932 | 21458 | }); |
| 20933 | 21459 | } |
| 20934 | 21460 | |
| 20935 | return std.builtin.ExportOptions{ | |
| 20936 | .name = name, | |
| 21461 | return .{ | |
| 21462 | .name = try ip.getOrPutString(gpa, name), | |
| 20937 | 21463 | .linkage = linkage, |
| 20938 | .section = section, | |
| 21464 | .section = try ip.getOrPutStringOpt(gpa, section), | |
| 20939 | 21465 | .visibility = visibility, |
| 20940 | 21466 | }; |
| 20941 | 21467 | } |
| ... | ... | @@ -20948,11 +21474,12 @@ fn resolveBuiltinEnum( |
| 20948 | 21474 | comptime name: []const u8, |
| 20949 | 21475 | reason: []const u8, |
| 20950 | 21476 | ) CompileError!@field(std.builtin, name) { |
| 21477 | const mod = sema.mod; | |
| 20951 | 21478 | const ty = try sema.getBuiltinType(name); |
| 20952 | 21479 | const air_ref = try sema.resolveInst(zir_ref); |
| 20953 | 21480 | const coerced = try sema.coerce(block, ty, air_ref, src); |
| 20954 | 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 | 21485 | fn resolveAtomicOrder( |
| ... | ... | @@ -20979,6 +21506,7 @@ fn zirCmpxchg( |
| 20979 | 21506 | block: *Block, |
| 20980 | 21507 | extended: Zir.Inst.Extended.InstData, |
| 20981 | 21508 | ) CompileError!Air.Inst.Ref { |
| 21509 | const mod = sema.mod; | |
| 20982 | 21510 | const extra = sema.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data; |
| 20983 | 21511 | const air_tag: Air.Inst.Tag = switch (extended.small) { |
| 20984 | 21512 | 0 => .cmpxchg_weak, |
| ... | ... | @@ -20996,12 +21524,12 @@ fn zirCmpxchg( |
| 20996 | 21524 | // zig fmt: on |
| 20997 | 21525 | const expected_value = try sema.resolveInst(extra.expected_value); |
| 20998 | 21526 | const elem_ty = sema.typeOf(expected_value); |
| 20999 | if (elem_ty.zigTypeTag() == .Float) { | |
| 21527 | if (elem_ty.zigTypeTag(mod) == .Float) { | |
| 21000 | 21528 | return sema.fail( |
| 21001 | 21529 | block, |
| 21002 | 21530 | elem_ty_src, |
| 21003 | 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 | 21535 | const uncasted_ptr = try sema.resolveInst(extra.ptr); |
| ... | ... | @@ -21023,29 +21551,34 @@ fn zirCmpxchg( |
| 21023 | 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 | 21556 | // special case zero bit types |
| 21029 | 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 | 21564 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { |
| 21034 | 21565 | if (try sema.resolveMaybeUndefVal(expected_value)) |expected_val| { |
| 21035 | 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 | 21568 | // TODO: this should probably cause the memory stored at the pointer |
| 21038 | 21569 | // to become undef as well |
| 21039 | 21570 | return sema.addConstUndef(result_ty); |
| 21040 | 21571 | } |
| 21041 | 21572 | const ptr_ty = sema.typeOf(ptr); |
| 21042 | 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: { | |
| 21044 | try sema.storePtr(block, src, ptr, new_value); | |
| 21045 | break :blk Value.null; | |
| 21046 | } else try Value.Tag.opt_payload.create(sema.arena, stored_val); | |
| 21047 | ||
| 21048 | return sema.addConstant(result_ty, result_val); | |
| 21574 | const result_val = try mod.intern(.{ .opt = .{ | |
| 21575 | .ty = result_ty.toIntern(), | |
| 21576 | .val = if (stored_val.eql(expected_val, elem_ty, mod)) blk: { | |
| 21577 | try sema.storePtr(block, src, ptr, new_value); | |
| 21578 | break :blk .none; | |
| 21579 | } else stored_val.toIntern(), | |
| 21580 | } }); | |
| 21581 | return sema.addConstant(result_ty, result_val.toValue()); | |
| 21049 | 21582 | } else break :rs new_value_src; |
| 21050 | 21583 | } else break :rs expected_src; |
| 21051 | 21584 | } else ptr_src; |
| ... | ... | @@ -21069,6 +21602,7 @@ fn zirCmpxchg( |
| 21069 | 21602 | } |
| 21070 | 21603 | |
| 21071 | 21604 | fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 21605 | const mod = sema.mod; | |
| 21072 | 21606 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 21073 | 21607 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 21074 | 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 | 21611 | const scalar = try sema.resolveInst(extra.rhs); |
| 21078 | 21612 | const scalar_ty = sema.typeOf(scalar); |
| 21079 | 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 | 21615 | .len = len, |
| 21082 | .elem_type = scalar_ty, | |
| 21616 | .child = scalar_ty.toIntern(), | |
| 21083 | 21617 | }); |
| 21084 | 21618 | if (try sema.resolveMaybeUndefVal(scalar)) |scalar_val| { |
| 21085 | if (scalar_val.isUndef()) return sema.addConstUndef(vector_ty); | |
| 21086 | ||
| 21087 | return sema.addConstant( | |
| 21088 | vector_ty, | |
| 21089 | try Value.Tag.repeated.create(sema.arena, scalar_val), | |
| 21090 | ); | |
| 21619 | if (scalar_val.isUndef(mod)) return sema.addConstUndef(vector_ty); | |
| 21620 | return sema.addConstant(vector_ty, try sema.splat(vector_ty, scalar_val)); | |
| 21091 | 21621 | } |
| 21092 | 21622 | |
| 21093 | 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 | 21632 | const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime-known"); |
| 21103 | 21633 | const operand = try sema.resolveInst(extra.rhs); |
| 21104 | 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) { | |
| 21108 | return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(sema.mod)}); | |
| 21637 | if (operand_ty.zigTypeTag(mod) != .Vector) { | |
| 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 | 21643 | // Type-check depending on operation. |
| 21114 | 21644 | switch (operation) { |
| 21115 | .And, .Or, .Xor => switch (scalar_ty.zigTypeTag()) { | |
| 21645 | .And, .Or, .Xor => switch (scalar_ty.zigTypeTag(mod)) { | |
| 21116 | 21646 | .Int, .Bool => {}, |
| 21117 | 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 | 21652 | .Int, .Float => {}, |
| 21123 | 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 | 21660 | if (vec_len == 0) { |
| 21131 | 21661 | // TODO re-evaluate if we should introduce a "neutral value" for some operations, |
| 21132 | 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 | 21664 | } |
| 21135 | 21665 | |
| 21136 | 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); | |
| 21140 | var elem_buf: Value.ElemValueBuffer = undefined; | |
| 21669 | var accum: Value = try operand_val.elemValue(mod, 0); | |
| 21141 | 21670 | var i: u32 = 1; |
| 21142 | 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 | 21673 | switch (operation) { |
| 21145 | .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, sema.mod), | |
| 21146 | .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, sema.mod), | |
| 21147 | .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, sema.mod), | |
| 21148 | .Min => accum = accum.numberMin(elem_val, target), | |
| 21149 | .Max => accum = accum.numberMax(elem_val, target), | |
| 21674 | .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, mod), | |
| 21675 | .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, mod), | |
| 21676 | .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, mod), | |
| 21677 | .Min => accum = accum.numberMin(elem_val, mod), | |
| 21678 | .Max => accum = accum.numberMax(elem_val, mod), | |
| 21150 | 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 | 21683 | return sema.addConstant(scalar_ty, accum); |
| ... | ... | @@ -21165,6 +21694,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 21165 | 21694 | } |
| 21166 | 21695 | |
| 21167 | 21696 | fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 21697 | const mod = sema.mod; | |
| 21168 | 21698 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 21169 | 21699 | const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data; |
| 21170 | 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 | 21707 | var mask = try sema.resolveInst(extra.mask); |
| 21178 | 21708 | var mask_ty = sema.typeOf(mask); |
| 21179 | 21709 | |
| 21180 | const mask_len = switch (sema.typeOf(mask).zigTypeTag()) { | |
| 21181 | .Array, .Vector => sema.typeOf(mask).arrayLen(), | |
| 21710 | const mask_len = switch (sema.typeOf(mask).zigTypeTag(mod)) { | |
| 21711 | .Array, .Vector => sema.typeOf(mask).arrayLen(mod), | |
| 21182 | 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, .{ | |
| 21185 | .len = mask_len, | |
| 21186 | .elem_type = Type.i32, | |
| 21714 | mask_ty = try mod.vectorType(.{ | |
| 21715 | .len = @intCast(u32, mask_len), | |
| 21716 | .child = .i32_type, | |
| 21187 | 21717 | }); |
| 21188 | 21718 | mask = try sema.coerce(block, mask_ty, mask, mask_src); |
| 21189 | 21719 | const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime-known"); |
| ... | ... | @@ -21200,27 +21730,28 @@ fn analyzeShuffle( |
| 21200 | 21730 | mask: Value, |
| 21201 | 21731 | mask_len: u32, |
| 21202 | 21732 | ) CompileError!Air.Inst.Ref { |
| 21733 | const mod = sema.mod; | |
| 21203 | 21734 | const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node }; |
| 21204 | 21735 | const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node }; |
| 21205 | 21736 | const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node }; |
| 21206 | 21737 | var a = a_arg; |
| 21207 | 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 | 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()) { | |
| 21215 | .Array, .Vector => sema.typeOf(a).arrayLen(), | |
| 21745 | var maybe_a_len = switch (sema.typeOf(a).zigTypeTag(mod)) { | |
| 21746 | .Array, .Vector => sema.typeOf(a).arrayLen(mod), | |
| 21216 | 21747 | .Undefined => null, |
| 21217 | 21748 | else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{ |
| 21218 | 21749 | elem_ty.fmt(sema.mod), |
| 21219 | 21750 | sema.typeOf(a).fmt(sema.mod), |
| 21220 | 21751 | }), |
| 21221 | 21752 | }; |
| 21222 | var maybe_b_len = switch (sema.typeOf(b).zigTypeTag()) { | |
| 21223 | .Array, .Vector => sema.typeOf(b).arrayLen(), | |
| 21753 | var maybe_b_len = switch (sema.typeOf(b).zigTypeTag(mod)) { | |
| 21754 | .Array, .Vector => sema.typeOf(b).arrayLen(mod), | |
| 21224 | 21755 | .Undefined => null, |
| 21225 | 21756 | else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{ |
| 21226 | 21757 | elem_ty.fmt(sema.mod), |
| ... | ... | @@ -21230,16 +21761,16 @@ fn analyzeShuffle( |
| 21230 | 21761 | if (maybe_a_len == null and maybe_b_len == null) { |
| 21231 | 21762 | return sema.addConstUndef(res_ty); |
| 21232 | 21763 | } |
| 21233 | const a_len = maybe_a_len orelse maybe_b_len.?; | |
| 21234 | const b_len = maybe_b_len orelse a_len; | |
| 21764 | const a_len = @intCast(u32, maybe_a_len orelse maybe_b_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 | 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 | 21772 | .len = b_len, |
| 21242 | .elem_type = elem_ty, | |
| 21773 | .child = elem_ty.toIntern(), | |
| 21243 | 21774 | }); |
| 21244 | 21775 | |
| 21245 | 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 | 21781 | .{ b_len, b_src, b_ty }, |
| 21251 | 21782 | }; |
| 21252 | 21783 | |
| 21253 | var i: usize = 0; | |
| 21254 | while (i < mask_len) : (i += 1) { | |
| 21255 | var buf: Value.ElemValueBuffer = undefined; | |
| 21256 | const elem = mask.elemValueBuffer(sema.mod, i, &buf); | |
| 21257 | if (elem.isUndef()) continue; | |
| 21258 | const int = elem.toSignedInt(sema.mod.getTarget()); | |
| 21784 | for (0..@intCast(usize, mask_len)) |i| { | |
| 21785 | const elem = try mask.elemValue(sema.mod, i); | |
| 21786 | if (elem.isUndef(mod)) continue; | |
| 21787 | const int = elem.toSignedInt(mod); | |
| 21259 | 21788 | var unsigned: u32 = undefined; |
| 21260 | 21789 | var chosen: u32 = undefined; |
| 21261 | 21790 | if (int >= 0) { |
| ... | ... | @@ -21287,26 +21816,21 @@ fn analyzeShuffle( |
| 21287 | 21816 | |
| 21288 | 21817 | if (try sema.resolveMaybeUndefVal(a)) |a_val| { |
| 21289 | 21818 | if (try sema.resolveMaybeUndefVal(b)) |b_val| { |
| 21290 | const values = try sema.arena.alloc(Value, mask_len); | |
| 21291 | ||
| 21292 | i = 0; | |
| 21293 | while (i < mask_len) : (i += 1) { | |
| 21294 | var buf: Value.ElemValueBuffer = undefined; | |
| 21295 | const mask_elem_val = mask.elemValueBuffer(sema.mod, i, &buf); | |
| 21296 | if (mask_elem_val.isUndef()) { | |
| 21297 | values[i] = Value.undef; | |
| 21819 | const values = try sema.arena.alloc(InternPool.Index, mask_len); | |
| 21820 | for (values, 0..) |*value, i| { | |
| 21821 | const mask_elem_val = try mask.elemValue(sema.mod, i); | |
| 21822 | if (mask_elem_val.isUndef(mod)) { | |
| 21823 | value.* = try mod.intern(.{ .undef = elem_ty.toIntern() }); | |
| 21298 | 21824 | continue; |
| 21299 | 21825 | } |
| 21300 | const int = mask_elem_val.toSignedInt(sema.mod.getTarget()); | |
| 21826 | const int = mask_elem_val.toSignedInt(mod); | |
| 21301 | 21827 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); |
| 21302 | if (int >= 0) { | |
| 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 | } | |
| 21828 | values[i] = try (try (if (int >= 0) a_val else b_val).elemValue(mod, unsigned)).intern(elem_ty, mod); | |
| 21307 | 21829 | } |
| 21308 | const res_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 21309 | return sema.addConstant(res_ty, res_val); | |
| 21830 | return sema.addConstant(res_ty, (try mod.intern(.{ .aggregate = .{ | |
| 21831 | .ty = res_ty.toIntern(), | |
| 21832 | .storage = .{ .elems = values }, | |
| 21833 | } })).toValue()); | |
| 21310 | 21834 | } |
| 21311 | 21835 | } |
| 21312 | 21836 | |
| ... | ... | @@ -21320,27 +21844,27 @@ fn analyzeShuffle( |
| 21320 | 21844 | const max_src = if (a_len > b_len) a_src else b_src; |
| 21321 | 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); | |
| 21324 | i = 0; | |
| 21325 | while (i < min_len) : (i += 1) { | |
| 21326 | expand_mask_values[i] = try Value.Tag.int_u64.create(sema.arena, i); | |
| 21847 | const expand_mask_values = try sema.arena.alloc(InternPool.Index, max_len); | |
| 21848 | for (@intCast(usize, 0)..@intCast(usize, min_len)) |i| { | |
| 21849 | expand_mask_values[i] = (try mod.intValue(Type.comptime_int, i)).toIntern(); | |
| 21327 | 21850 | } |
| 21328 | while (i < max_len) : (i += 1) { | |
| 21329 | expand_mask_values[i] = Value.negative_one; | |
| 21851 | for (@intCast(usize, min_len)..@intCast(usize, max_len)) |i| { | |
| 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 | 21859 | if (a_len < b_len) { |
| 21334 | 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 | 21862 | } else { |
| 21337 | 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 | 21868 | return block.addInst(.{ |
| 21345 | 21869 | .tag = .shuffle, |
| 21346 | 21870 | .data = .{ .ty_pl = .{ |
| ... | ... | @@ -21348,7 +21872,7 @@ fn analyzeShuffle( |
| 21348 | 21872 | .payload = try block.sema.addExtra(Air.Shuffle{ |
| 21349 | 21873 | .a = a, |
| 21350 | 21874 | .b = b, |
| 21351 | .mask = mask_index, | |
| 21875 | .mask = mask.toIntern(), | |
| 21352 | 21876 | .mask_len = mask_len, |
| 21353 | 21877 | }), |
| 21354 | 21878 | } }, |
| ... | ... | @@ -21356,6 +21880,7 @@ fn analyzeShuffle( |
| 21356 | 21880 | } |
| 21357 | 21881 | |
| 21358 | 21882 | fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 21883 | const mod = sema.mod; | |
| 21359 | 21884 | const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data; |
| 21360 | 21885 | |
| 21361 | 21886 | const src = LazySrcLoc.nodeOffset(extra.node); |
| ... | ... | @@ -21369,16 +21894,22 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C |
| 21369 | 21894 | const pred_uncoerced = try sema.resolveInst(extra.pred); |
| 21370 | 21895 | const pred_ty = sema.typeOf(pred_uncoerced); |
| 21371 | 21896 | |
| 21372 | const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison()) { | |
| 21373 | .Vector, .Array => pred_ty.arrayLen(), | |
| 21374 | else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(sema.mod)}), | |
| 21897 | const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison(mod)) { | |
| 21898 | .Vector, .Array => pred_ty.arrayLen(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 | 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 | 21913 | const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src); |
| 21383 | 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 | 21918 | const maybe_b = try sema.resolveMaybeUndefVal(b); |
| 21388 | 21919 | |
| 21389 | 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 | 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 | 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; | |
| 21399 | const elems = try sema.gpa.alloc(Value, vec_len); | |
| 21929 | const elems = try sema.gpa.alloc(InternPool.Index, vec_len); | |
| 21400 | 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 | 21932 | const should_choose_a = pred_elem_val.toBool(); |
| 21403 | if (should_choose_a) { | |
| 21404 | elem.* = a_val.elemValueBuffer(sema.mod, i, &buf); | |
| 21405 | } else { | |
| 21406 | elem.* = b_val.elemValueBuffer(sema.mod, i, &buf); | |
| 21407 | } | |
| 21933 | elem.* = try (try (if (should_choose_a) a_val else b_val).elemValue(mod, i)).intern(elem_ty, mod); | |
| 21408 | 21934 | } |
| 21409 | 21935 | |
| 21410 | return sema.addConstant( | |
| 21411 | vec_ty, | |
| 21412 | try Value.Tag.aggregate.create(sema.arena, elems), | |
| 21413 | ); | |
| 21936 | return sema.addConstant(vec_ty, (try mod.intern(.{ .aggregate = .{ | |
| 21937 | .ty = vec_ty.toIntern(), | |
| 21938 | .storage = .{ .elems = elems }, | |
| 21939 | } })).toValue()); | |
| 21414 | 21940 | } else { |
| 21415 | 21941 | break :rs b_src; |
| 21416 | 21942 | } |
| 21417 | 21943 | } else { |
| 21418 | 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 | 21947 | break :rs a_src; |
| 21422 | 21948 | } |
| 21423 | 21949 | } else rs: { |
| 21424 | 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 | 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 | 21956 | break :rs pred_src; |
| 21431 | 21957 | }; |
| ... | ... | @@ -21489,6 +22015,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 21489 | 22015 | } |
| 21490 | 22016 | |
| 21491 | 22017 | fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 22018 | const mod = sema.mod; | |
| 21492 | 22019 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 21493 | 22020 | const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; |
| 21494 | 22021 | const src = inst_data.src(); |
| ... | ... | @@ -21505,7 +22032,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 21505 | 22032 | const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); |
| 21506 | 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 | 22036 | .Enum => if (op != .Xchg) { |
| 21510 | 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 | 22062 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); |
| 21536 | 22063 | break :rs operand_src; |
| 21537 | 22064 | }; |
| 21538 | if (ptr_val.isComptimeMutablePtr()) { | |
| 21539 | const target = sema.mod.getTarget(); | |
| 22065 | if (ptr_val.isComptimeMutablePtr(mod)) { | |
| 21540 | 22066 | const ptr_ty = sema.typeOf(ptr); |
| 21541 | 22067 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; |
| 21542 | 22068 | const new_val = switch (op) { |
| ... | ... | @@ -21544,12 +22070,12 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 21544 | 22070 | .Xchg => operand_val, |
| 21545 | 22071 | .Add => try sema.numberAddWrapScalar(stored_val, operand_val, elem_ty), |
| 21546 | 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), | |
| 21548 | .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, sema.mod), | |
| 21549 | .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, sema.mod), | |
| 21550 | .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, sema.mod), | |
| 21551 | .Max => stored_val.numberMax (operand_val, target), | |
| 21552 | .Min => stored_val.numberMin (operand_val, target), | |
| 22073 | .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, mod), | |
| 22074 | .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, mod), | |
| 22075 | .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, mod), | |
| 22076 | .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, mod), | |
| 22077 | .Max => stored_val.numberMax (operand_val, mod), | |
| 22078 | .Min => stored_val.numberMin (operand_val, mod), | |
| 21553 | 22079 | // zig fmt: on |
| 21554 | 22080 | }; |
| 21555 | 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 | 22149 | const maybe_mulend1 = try sema.resolveMaybeUndefVal(mulend1); |
| 21624 | 22150 | const maybe_mulend2 = try sema.resolveMaybeUndefVal(mulend2); |
| 21625 | 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 | 22155 | .ComptimeFloat, .Float, .Vector => {}, |
| 21629 | 22156 | else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(sema.mod)}), |
| 21630 | 22157 | } |
| 21631 | 22158 | |
| 21632 | 22159 | const runtime_src = if (maybe_mulend1) |mulend1_val| rs: { |
| 21633 | 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 | 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 | 22165 | const result_val = try Value.mulAdd(ty, mulend1_val, mulend2_val, addend_val, sema.arena, sema.mod); |
| 21639 | 22166 | return sema.addConstant(ty, result_val); |
| 21640 | 22167 | } else { |
| ... | ... | @@ -21642,16 +22169,16 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 21642 | 22169 | } |
| 21643 | 22170 | } else { |
| 21644 | 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 | 22174 | break :rs mulend2_src; |
| 21648 | 22175 | } |
| 21649 | 22176 | } else rs: { |
| 21650 | 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 | 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 | 22183 | break :rs mulend1_src; |
| 21657 | 22184 | }; |
| ... | ... | @@ -21673,6 +22200,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 21673 | 22200 | const tracy = trace(@src()); |
| 21674 | 22201 | defer tracy.end(); |
| 21675 | 22202 | |
| 22203 | const mod = sema.mod; | |
| 21676 | 22204 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 21677 | 22205 | const modifier_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 21678 | 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 | 22214 | const air_ref = try sema.resolveInst(extra.modifier); |
| 21687 | 22215 | const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src); |
| 21688 | 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 | 22218 | switch (modifier) { |
| 21691 | 22219 | // These can be upgraded to comptime or nosuspend calls. |
| 21692 | 22220 | .auto, .never_tail, .no_async => { |
| ... | ... | @@ -21732,18 +22260,17 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 21732 | 22260 | const args = try sema.resolveInst(extra.args); |
| 21733 | 22261 | |
| 21734 | 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 | 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 | 22268 | for (resolved_args, 0..) |*resolved, i| { |
| 21741 | 22269 | resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); |
| 21742 | 22270 | } |
| 21743 | 22271 | |
| 21744 | 22272 | const callee_ty = sema.typeOf(func); |
| 21745 | 22273 | const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false); |
| 21746 | ||
| 21747 | 22274 | const ensure_result_used = extra.flags.ensure_result_used; |
| 21748 | 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 | 22284 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 21758 | 22285 | |
| 21759 | 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 | 22288 | const field_ptr = try sema.resolveInst(extra.field_ptr); |
| 21762 | 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 | 22294 | return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)}); |
| 21766 | 22295 | } |
| 21767 | 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 | 22299 | .Struct => blk: { |
| 21771 | if (parent_ty.isTuple()) { | |
| 21772 | if (mem.eql(u8, field_name, "len")) { | |
| 22300 | if (parent_ty.isTuple(mod)) { | |
| 22301 | if (ip.stringEqlSlice(field_name, "len")) { | |
| 21773 | 22302 | return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{}); |
| 21774 | 22303 | } |
| 21775 | 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 | 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 | 22314 | return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{}); |
| 21786 | 22315 | } |
| 21787 | 22316 | |
| 21788 | 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 | 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 | 22322 | .mutable = field_ptr_ty_info.mutable, |
| 21794 | 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 | 22327 | return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{}); |
| 21799 | 22328 | } else { |
| 21800 | 22329 | ptr_ty_data.@"align" = blk: { |
| 21801 | if (parent_ty.castTag(.@"struct")) |struct_obj| { | |
| 21802 | break :blk struct_obj.data.fields.values()[field_index].abi_align; | |
| 21803 | } else if (parent_ty.cast(Type.Payload.Union)) |union_obj| { | |
| 21804 | break :blk union_obj.data.fields.values()[field_index].abi_align; | |
| 22330 | if (mod.typeToStruct(parent_ty)) |struct_obj| { | |
| 22331 | break :blk struct_obj.fields.values()[field_index].abi_align; | |
| 22332 | } else if (mod.typeToUnion(parent_ty)) |union_obj| { | |
| 22333 | break :blk union_obj.fields.values()[field_index].abi_align; | |
| 21805 | 22334 | } else { |
| 21806 | 22335 | break :blk 0; |
| 21807 | 22336 | } |
| ... | ... | @@ -21815,19 +22344,24 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 21815 | 22344 | const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); |
| 21816 | 22345 | |
| 21817 | 22346 | if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| { |
| 21818 | const payload = field_ptr_val.castTag(.field_ptr) orelse { | |
| 21819 | return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{}); | |
| 21820 | }; | |
| 21821 | if (payload.data.field_index != field_index) { | |
| 22347 | const field = switch (ip.indexToKey(field_ptr_val.toIntern())) { | |
| 22348 | .ptr => |ptr| switch (ptr.addr) { | |
| 22349 | .field => |field| field, | |
| 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 | 22356 | const msg = msg: { |
| 21823 | 22357 | const msg = try sema.errMsg( |
| 21824 | 22358 | block, |
| 21825 | 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 | 22363 | field_index, |
| 21830 | payload.data.field_index, | |
| 22364 | field.index, | |
| 21831 | 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 | 22371 | }; |
| 21838 | 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 | 22377 | try sema.requireRuntimeBlock(block, src, ptr_src); |
| ... | ... | @@ -21913,15 +22447,14 @@ fn analyzeMinMax( |
| 21913 | 22447 | ) CompileError!Air.Inst.Ref { |
| 21914 | 22448 | assert(operands.len == operand_srcs.len); |
| 21915 | 22449 | assert(operands.len > 0); |
| 22450 | const mod = sema.mod; | |
| 21916 | 22451 | |
| 21917 | 22452 | if (operands.len == 1) return operands[0]; |
| 21918 | 22453 | |
| 21919 | const mod = sema.mod; | |
| 21920 | const target = mod.getTarget(); | |
| 21921 | 22454 | const opFunc = switch (air_tag) { |
| 21922 | 22455 | .min => Value.numberMin, |
| 21923 | 22456 | .max => Value.numberMax, |
| 21924 | else => unreachable, | |
| 22457 | else => @compileError("unreachable"), | |
| 21925 | 22458 | }; |
| 21926 | 22459 | |
| 21927 | 22460 | // First, find all comptime-known arguments, and get their min/max |
| ... | ... | @@ -21939,32 +22472,30 @@ fn analyzeMinMax( |
| 21939 | 22472 | |
| 21940 | 22473 | runtime_known.unset(operand_idx); |
| 21941 | 22474 | |
| 21942 | if (cur_val.isUndef()) continue; // result is also undef | |
| 21943 | if (operand_val.isUndef()) { | |
| 22475 | if (cur_val.isUndef(mod)) continue; // result is also undef | |
| 22476 | if (operand_val.isUndef(mod)) { | |
| 21944 | 22477 | cur_minmax = try sema.addConstUndef(simd_op.result_ty); |
| 21945 | 22478 | continue; |
| 21946 | 22479 | } |
| 21947 | 22480 | |
| 21948 | try sema.resolveLazyValue(cur_val); | |
| 21949 | try sema.resolveLazyValue(operand_val); | |
| 22481 | const resolved_cur_val = try sema.resolveLazyValue(cur_val); | |
| 22482 | const resolved_operand_val = try sema.resolveLazyValue(operand_val); | |
| 21950 | 22483 | |
| 21951 | 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 | 22486 | cur_minmax = try sema.addConstant(simd_op.result_ty, result_val); |
| 21954 | 22487 | continue; |
| 21955 | 22488 | }; |
| 21956 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 21957 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 21958 | const elems = try sema.arena.alloc(Value, vec_len); | |
| 22489 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 21959 | 22490 | for (elems, 0..) |*elem, i| { |
| 21960 | const lhs_elem_val = cur_val.elemValueBuffer(mod, i, &lhs_buf); | |
| 21961 | const rhs_elem_val = operand_val.elemValueBuffer(mod, i, &rhs_buf); | |
| 21962 | elem.* = opFunc(lhs_elem_val, rhs_elem_val, target); | |
| 21963 | } | |
| 21964 | cur_minmax = try sema.addConstant( | |
| 21965 | simd_op.result_ty, | |
| 21966 | try Value.Tag.aggregate.create(sema.arena, elems), | |
| 21967 | ); | |
| 22491 | const lhs_elem_val = try resolved_cur_val.elemValue(mod, i); | |
| 22492 | const rhs_elem_val = try resolved_operand_val.elemValue(mod, i); | |
| 22493 | elem.* = try opFunc(lhs_elem_val, rhs_elem_val, mod).intern(simd_op.scalar_ty, mod); | |
| 22494 | } | |
| 22495 | cur_minmax = try sema.addConstant(simd_op.result_ty, (try mod.intern(.{ .aggregate = .{ | |
| 22496 | .ty = simd_op.result_ty.toIntern(), | |
| 22497 | .storage = .{ .elems = elems }, | |
| 22498 | } })).toValue()); | |
| 21968 | 22499 | } else { |
| 21969 | 22500 | runtime_known.unset(operand_idx); |
| 21970 | 22501 | cur_minmax = try sema.addConstant(sema.typeOf(operand), uncasted_operand_val); |
| ... | ... | @@ -21984,28 +22515,31 @@ fn analyzeMinMax( |
| 21984 | 22515 | break :refined orig_ty; |
| 21985 | 22516 | } |
| 21986 | 22517 | |
| 21987 | const refined_ty = if (orig_ty.zigTypeTag() == .Vector) blk: { | |
| 21988 | const elem_ty = orig_ty.childType(); | |
| 21989 | const len = orig_ty.vectorLen(); | |
| 22518 | const refined_ty = if (orig_ty.zigTypeTag(mod) == .Vector) blk: { | |
| 22519 | const elem_ty = orig_ty.childType(mod); | |
| 22520 | const len = orig_ty.vectorLen(mod); | |
| 21990 | 22521 | |
| 21991 | 22522 | if (len == 0) break :blk orig_ty; |
| 21992 | 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 | 22526 | var cur_max: Value = cur_min; |
| 21996 | 22527 | for (1..len) |idx| { |
| 21997 | const elem_val = try val.elemValue(mod, sema.arena, idx); | |
| 21998 | if (elem_val.isUndef()) break :blk orig_ty; // can't refine undef | |
| 21999 | if (Value.order(elem_val, cur_min, target).compare(.lt)) cur_min = elem_val; | |
| 22000 | if (Value.order(elem_val, cur_max, target).compare(.gt)) cur_max = elem_val; | |
| 22528 | const elem_val = try val.elemValue(mod, idx); | |
| 22529 | if (elem_val.isUndef(mod)) break :blk orig_ty; // can't refine undef | |
| 22530 | if (Value.order(elem_val, cur_min, mod).compare(.lt)) cur_min = 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); | |
| 22004 | break :blk try Type.vector(sema.arena, len, refined_elem_ty); | |
| 22534 | const refined_elem_ty = try mod.intFittingRange(cur_min, cur_max); | |
| 22535 | break :blk try mod.vectorType(.{ | |
| 22536 | .len = len, | |
| 22537 | .child = refined_elem_ty.toIntern(), | |
| 22538 | }); | |
| 22005 | 22539 | } else blk: { |
| 22006 | 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 | |
| 22008 | break :blk try Type.intFittingRange(target, sema.arena, val, val); | |
| 22541 | if (val.isUndef(mod)) break :blk orig_ty; // can't refine undef | |
| 22542 | break :blk try mod.intFittingRange(val, val); | |
| 22009 | 22543 | }; |
| 22010 | 22544 | |
| 22011 | 22545 | // Apply the refined type to the current value - this isn't strictly necessary in the |
| ... | ... | @@ -22016,7 +22550,7 @@ fn analyzeMinMax( |
| 22016 | 22550 | if (std.debug.runtime_safety) { |
| 22017 | 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 | 22556 | break :refined refined_ty; |
| ... | ... | @@ -22032,7 +22566,7 @@ fn analyzeMinMax( |
| 22032 | 22566 | // If the comptime-known part is undef we can avoid emitting actual instructions later |
| 22033 | 22567 | const known_undef = if (cur_minmax) |operand| blk: { |
| 22034 | 22568 | const val = (try sema.resolveMaybeUndefVal(operand)).?; |
| 22035 | break :blk val.isUndef(); | |
| 22569 | break :blk val.isUndef(mod); | |
| 22036 | 22570 | } else false; |
| 22037 | 22571 | |
| 22038 | 22572 | if (cur_minmax == null) { |
| ... | ... | @@ -22061,29 +22595,32 @@ fn analyzeMinMax( |
| 22061 | 22595 | // Finally, refine the type based on the comptime-known bound. |
| 22062 | 22596 | if (known_undef) break :refine; // can't refine undef |
| 22063 | 22597 | const unrefined_ty = sema.typeOf(cur_minmax.?); |
| 22064 | const is_vector = unrefined_ty.zigTypeTag() == .Vector; | |
| 22065 | const comptime_elem_ty = if (is_vector) comptime_ty.childType() else comptime_ty; | |
| 22066 | const unrefined_elem_ty = if (is_vector) unrefined_ty.childType() else unrefined_ty; | |
| 22598 | const is_vector = unrefined_ty.zigTypeTag(mod) == .Vector; | |
| 22599 | const comptime_elem_ty = if (is_vector) comptime_ty.childType(mod) else comptime_ty; | |
| 22600 | const unrefined_elem_ty = if (is_vector) unrefined_ty.childType(mod) else unrefined_ty; | |
| 22067 | 22601 | |
| 22068 | 22602 | if (unrefined_elem_ty.isAnyFloat()) break :refine; // we can't refine floats |
| 22069 | 22603 | |
| 22070 | 22604 | // Compute the final bounds based on the runtime type and the comptime-known bound type |
| 22071 | 22605 | const min_val = switch (air_tag) { |
| 22072 | .min => try unrefined_elem_ty.minInt(sema.arena, target), | |
| 22073 | .max => try comptime_elem_ty.minInt(sema.arena, target), // @max(ct, rt) >= ct | |
| 22606 | .min => try unrefined_elem_ty.minInt(mod, unrefined_elem_ty), | |
| 22607 | .max => try comptime_elem_ty.minInt(mod, comptime_elem_ty), // @max(ct, rt) >= ct | |
| 22074 | 22608 | else => unreachable, |
| 22075 | 22609 | }; |
| 22076 | 22610 | const max_val = switch (air_tag) { |
| 22077 | .min => try comptime_elem_ty.maxInt(sema.arena, target), // @min(ct, rt) <= ct | |
| 22078 | .max => try unrefined_elem_ty.maxInt(sema.arena, target), | |
| 22611 | .min => try comptime_elem_ty.maxInt(mod, comptime_elem_ty), // @min(ct, rt) <= ct | |
| 22612 | .max => try unrefined_elem_ty.maxInt(mod, unrefined_elem_ty), | |
| 22079 | 22613 | else => unreachable, |
| 22080 | 22614 | }; |
| 22081 | 22615 | |
| 22082 | 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 | 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 | 22624 | else |
| 22088 | 22625 | final_elem_ty; |
| 22089 | 22626 | |
| ... | ... | @@ -22098,7 +22635,7 @@ fn analyzeMinMax( |
| 22098 | 22635 | |
| 22099 | 22636 | fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !Air.Inst.Ref { |
| 22100 | 22637 | const mod = sema.mod; |
| 22101 | const info = sema.typeOf(ptr).ptrInfo().data; | |
| 22638 | const info = sema.typeOf(ptr).ptrInfo(mod); | |
| 22102 | 22639 | if (info.size == .One) { |
| 22103 | 22640 | // Already an array pointer. |
| 22104 | 22641 | return ptr; |
| ... | ... | @@ -22132,8 +22669,9 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22132 | 22669 | const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr); |
| 22133 | 22670 | const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr); |
| 22134 | 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 | 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 | 22732 | } |
| 22195 | 22733 | |
| 22196 | 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 | 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 | 22738 | const len = try sema.usizeCast(block, dest_src, len_u64); |
| 22201 | 22739 | for (0..len) |i| { |
| 22202 | 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 | 22777 | // lowering. The AIR instruction requires pointers with element types of |
| 22240 | 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 | 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(); | |
| 22247 | const src_elem_ty = src_ty.elemType2(); | |
| 22784 | const dest_elem_ty = dest_ty.elemType2(mod); | |
| 22785 | const src_elem_ty = src_ty.elemType2(mod); | |
| 22248 | 22786 | if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src)) { |
| 22249 | 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 | 22793 | var new_dest_ptr = dest_ptr; |
| 22256 | 22794 | var new_src_ptr = src_ptr; |
| 22257 | 22795 | if (len_val) |val| { |
| 22258 | const len = val.toUnsignedInt(target); | |
| 22796 | const len = val.toUnsignedInt(mod); | |
| 22259 | 22797 | if (len == 0) { |
| 22260 | 22798 | // This AIR instruction guarantees length > 0 if it is comptime-known. |
| 22261 | 22799 | return; |
| ... | ... | @@ -22268,7 +22806,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22268 | 22806 | // Change the src from slice to a many pointer, to avoid multiple ptr |
| 22269 | 22807 | // slice extractions in AIR instructions. |
| 22270 | 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 | 22810 | new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); |
| 22273 | 22811 | } |
| 22274 | 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 | 22814 | const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr); |
| 22277 | 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 | 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 | 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 | 22833 | // Extract raw pointer from dest slice. The AIR instructions could support them, but |
| 22296 | 22834 | // it would cause redundant machine code instructions. |
| 22297 | 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 | 22837 | try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty) |
| 22300 | else | |
| 22301 | new_dest_ptr; | |
| 22838 | else if (new_dest_ptr_ty.ptrSize(mod) == .One) 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 | 22857 | // ok1: dest >= src + len |
| 22304 | 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 | 22860 | const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src); |
| 22307 | 22861 | const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); |
| 22308 | 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 | 22874 | } |
| 22321 | 22875 | |
| 22322 | 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 | 22880 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 22324 | 22881 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 22325 | 22882 | const src = inst_data.src(); |
| ... | ... | @@ -22330,25 +22887,24 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22330 | 22887 | const dest_ptr_ty = sema.typeOf(dest_ptr); |
| 22331 | 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 | 22891 | return sema.fail(block, dest_src, "cannot memset constant pointer", .{}); |
| 22335 | 22892 | } |
| 22336 | 22893 | |
| 22337 | const dest_elem_ty = dest_ptr_ty.elemType2(); | |
| 22338 | const target = sema.mod.getTarget(); | |
| 22894 | const dest_elem_ty = dest_ptr_ty.elemType2(mod); | |
| 22339 | 22895 | |
| 22340 | 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 | 22898 | const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse |
| 22343 | 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 | 22901 | const len = try sema.usizeCast(block, dest_src, len_u64); |
| 22346 | 22902 | if (len == 0) { |
| 22347 | 22903 | // This AIR instruction guarantees length > 0 if it is comptime-known. |
| 22348 | 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 | 22908 | if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| { |
| 22353 | 22909 | for (0..len) |i| { |
| 22354 | 22910 | const elem_index = try sema.addIntUnsigned(Type.usize, i); |
| ... | ... | @@ -22426,6 +22982,7 @@ fn zirVarExtended( |
| 22426 | 22982 | block: *Block, |
| 22427 | 22983 | extended: Zir.Inst.Extended.InstData, |
| 22428 | 22984 | ) CompileError!Air.Inst.Ref { |
| 22985 | const mod = sema.mod; | |
| 22429 | 22986 | const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); |
| 22430 | 22987 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; |
| 22431 | 22988 | const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; |
| ... | ... | @@ -22461,47 +23018,33 @@ fn zirVarExtended( |
| 22461 | 23018 | else |
| 22462 | 23019 | uncasted_init; |
| 22463 | 23020 | |
| 22464 | break :blk (try sema.resolveMaybeUndefVal(init)) orelse | |
| 22465 | return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known"); | |
| 22466 | } else Value.initTag(.unreachable_value); | |
| 23021 | break :blk ((try sema.resolveMaybeUndefVal(init)) orelse | |
| 23022 | return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known")).toIntern(); | |
| 23023 | } else .none; | |
| 22467 | 23024 | |
| 22468 | 23025 | try sema.validateVarType(block, ty_src, var_ty, small.is_extern); |
| 22469 | 23026 | |
| 22470 | const new_var = try sema.gpa.create(Module.Var); | |
| 22471 | errdefer sema.gpa.destroy(new_var); | |
| 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, | |
| 23027 | return sema.addConstant(var_ty, (try mod.intern(.{ .variable = .{ | |
| 23028 | .ty = var_ty.toIntern(), | |
| 22479 | 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 | 23035 | .is_extern = small.is_extern, |
| 22481 | .is_mutable = true, | |
| 22482 | 23036 | .is_threadlocal = small.is_threadlocal, |
| 22483 | .is_weak_linkage = false, | |
| 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; | |
| 23037 | } })).toValue()); | |
| 22496 | 23038 | } |
| 22497 | 23039 | |
| 22498 | 23040 | fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 22499 | 23041 | const tracy = trace(@src()); |
| 22500 | 23042 | defer tracy.end(); |
| 22501 | 23043 | |
| 23044 | const mod = sema.mod; | |
| 22502 | 23045 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 22503 | 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 | 23049 | const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node }; |
| 22507 | 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 | 23075 | extra_index += body.len; |
| 22533 | 23076 | |
| 22534 | 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 | 23079 | break :blk null; |
| 22537 | 23080 | } |
| 22538 | const alignment = @intCast(u32, val.toUnsignedInt(target)); | |
| 23081 | const alignment = @intCast(u32, val.toUnsignedInt(mod)); | |
| 22539 | 23082 | try sema.validateAlign(block, align_src, alignment); |
| 22540 | 23083 | if (alignment == target_util.defaultFunctionAlignment(target)) { |
| 22541 | 23084 | break :blk 0; |
| ... | ... | @@ -22551,7 +23094,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22551 | 23094 | }, |
| 22552 | 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 | 23098 | try sema.validateAlign(block, align_src, alignment); |
| 22556 | 23099 | if (alignment == target_util.defaultFunctionAlignment(target)) { |
| 22557 | 23100 | break :blk 0; |
| ... | ... | @@ -22568,10 +23111,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22568 | 23111 | |
| 22569 | 23112 | const addrspace_ty = try sema.getBuiltinType("AddressSpace"); |
| 22570 | 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 | 23115 | break :blk null; |
| 22573 | 23116 | } |
| 22574 | break :blk val.toEnum(std.builtin.AddressSpace); | |
| 23117 | break :blk mod.toEnum(std.builtin.AddressSpace, val); | |
| 22575 | 23118 | } else if (extra.data.bits.has_addrspace_ref) blk: { |
| 22576 | 23119 | const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 22577 | 23120 | extra_index += 1; |
| ... | ... | @@ -22581,7 +23124,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22581 | 23124 | }, |
| 22582 | 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 | 23128 | } else target_util.defaultAddressSpace(target, .function); |
| 22586 | 23129 | |
| 22587 | 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 | 23133 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 22591 | 23134 | extra_index += body.len; |
| 22592 | 23135 | |
| 22593 | const ty = Type.initTag(.const_slice_u8); | |
| 23136 | const ty = Type.slice_const_u8; | |
| 22594 | 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 | 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 | 23142 | } else if (extra.data.bits.has_section_ref) blk: { |
| 22600 | 23143 | const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 22601 | 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 | 23146 | error.GenericPoison => { |
| 22604 | 23147 | break :blk FuncLinkSection{ .generic = {} }; |
| 22605 | 23148 | }, |
| ... | ... | @@ -22616,10 +23159,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22616 | 23159 | |
| 22617 | 23160 | const cc_ty = try sema.getBuiltinType("CallingConvention"); |
| 22618 | 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 | 23163 | break :blk null; |
| 22621 | 23164 | } |
| 22622 | break :blk val.toEnum(std.builtin.CallingConvention); | |
| 23165 | break :blk mod.toEnum(std.builtin.CallingConvention, val); | |
| 22623 | 23166 | } else if (extra.data.bits.has_cc_ref) blk: { |
| 22624 | 23167 | const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 22625 | 23168 | extra_index += 1; |
| ... | ... | @@ -22629,7 +23172,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22629 | 23172 | }, |
| 22630 | 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 | 23176 | } else if (sema.owner_decl.is_exported and has_body) |
| 22634 | 23177 | .C |
| 22635 | 23178 | else |
| ... | ... | @@ -22642,20 +23185,18 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22642 | 23185 | extra_index += body.len; |
| 22643 | 23186 | |
| 22644 | 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; | |
| 22646 | const ty = try val.toType(&buffer).copy(sema.arena); | |
| 23188 | const ty = val.toType(); | |
| 22647 | 23189 | break :blk ty; |
| 22648 | 23190 | } else if (extra.data.bits.has_ret_ty_ref) blk: { |
| 22649 | 23191 | const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 22650 | 23192 | extra_index += 1; |
| 22651 | 23193 | const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime-known") catch |err| switch (err) { |
| 22652 | 23194 | error.GenericPoison => { |
| 22653 | break :blk Type.initTag(.generic_poison); | |
| 23195 | break :blk Type.generic_poison; | |
| 22654 | 23196 | }, |
| 22655 | 23197 | else => |e| return e, |
| 22656 | 23198 | }; |
| 22657 | var buffer: Value.ToTypeBuffer = undefined; | |
| 22658 | const ty = try ret_ty_tv.val.toType(&buffer).copy(sema.arena); | |
| 23199 | const ty = ret_ty_tv.val.toType(); | |
| 22659 | 23200 | break :blk ty; |
| 22660 | 23201 | } else Type.void; |
| 22661 | 23202 | |
| ... | ... | @@ -22727,13 +23268,14 @@ fn zirCDefine( |
| 22727 | 23268 | block: *Block, |
| 22728 | 23269 | extended: Zir.Inst.Extended.InstData, |
| 22729 | 23270 | ) CompileError!Air.Inst.Ref { |
| 23271 | const mod = sema.mod; | |
| 22730 | 23272 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 22731 | 23273 | const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 22732 | 23274 | const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; |
| 22733 | 23275 | |
| 22734 | 23276 | const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime-known"); |
| 22735 | 23277 | const rhs = try sema.resolveInst(extra.rhs); |
| 22736 | if (sema.typeOf(rhs).zigTypeTag() != .Void) { | |
| 23278 | if (sema.typeOf(rhs).zigTypeTag(mod) != .Void) { | |
| 22737 | 23279 | const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime-known"); |
| 22738 | 23280 | try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); |
| 22739 | 23281 | } else { |
| ... | ... | @@ -22799,27 +23341,29 @@ fn resolvePrefetchOptions( |
| 22799 | 23341 | src: LazySrcLoc, |
| 22800 | 23342 | zir_ref: Zir.Inst.Ref, |
| 22801 | 23343 | ) CompileError!std.builtin.PrefetchOptions { |
| 23344 | const mod = sema.mod; | |
| 23345 | const gpa = sema.gpa; | |
| 23346 | const ip = &mod.intern_pool; | |
| 22802 | 23347 | const options_ty = try sema.getBuiltinType("PrefetchOptions"); |
| 22803 | 23348 | const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src); |
| 22804 | const target = sema.mod.getTarget(); | |
| 22805 | 23349 | |
| 22806 | 23350 | const rw_src = sema.maybeOptionsSrc(block, src, "rw"); |
| 22807 | 23351 | const locality_src = sema.maybeOptionsSrc(block, src, "locality"); |
| 22808 | 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 | 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 | 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 | 23361 | const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime-known"); |
| 22818 | 23362 | |
| 22819 | 23363 | return std.builtin.PrefetchOptions{ |
| 22820 | .rw = rw_val.toEnum(std.builtin.PrefetchOptions.Rw), | |
| 22821 | .locality = @intCast(u2, locality_val.toUnsignedInt(target)), | |
| 22822 | .cache = cache_val.toEnum(std.builtin.PrefetchOptions.Cache), | |
| 23364 | .rw = mod.toEnum(std.builtin.PrefetchOptions.Rw, rw_val), | |
| 23365 | .locality = @intCast(u2, locality_val.toUnsignedInt(mod)), | |
| 23366 | .cache = mod.toEnum(std.builtin.PrefetchOptions.Cache, cache_val), | |
| 22823 | 23367 | }; |
| 22824 | 23368 | } |
| 22825 | 23369 | |
| ... | ... | @@ -22862,34 +23406,40 @@ fn resolveExternOptions( |
| 22862 | 23406 | block: *Block, |
| 22863 | 23407 | src: LazySrcLoc, |
| 22864 | 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 | 23418 | const options_inst = try sema.resolveInst(zir_ref); |
| 22867 | 23419 | const extern_options_ty = try sema.getBuiltinType("ExternOptions"); |
| 22868 | 23420 | const options = try sema.coerce(block, extern_options_ty, options_inst, src); |
| 22869 | const mod = sema.mod; | |
| 22870 | 23421 | |
| 22871 | 23422 | const name_src = sema.maybeOptionsSrc(block, src, "name"); |
| 22872 | 23423 | const library_src = sema.maybeOptionsSrc(block, src, "library"); |
| 22873 | 23424 | const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); |
| 22874 | 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 | 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 | 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 | 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 | 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: { | |
| 22891 | const payload = library_name_val.castTag(.opt_payload).?.data; | |
| 22892 | const library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod); | |
| 23441 | const library_name = if (library_name_val.optionalValue(mod)) |payload| blk: { | |
| 23442 | const library_name = try payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); | |
| 22893 | 23443 | if (library_name.len == 0) { |
| 22894 | 23444 | return sema.fail(block, library_src, "library name cannot be empty", .{}); |
| 22895 | 23445 | } |
| ... | ... | @@ -22904,9 +23454,9 @@ fn resolveExternOptions( |
| 22904 | 23454 | return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{}); |
| 22905 | 23455 | } |
| 22906 | 23456 | |
| 22907 | return std.builtin.ExternOptions{ | |
| 22908 | .name = name, | |
| 22909 | .library_name = library_name, | |
| 23457 | return .{ | |
| 23458 | .name = try ip.getOrPutString(gpa, name), | |
| 23459 | .library_name = try ip.getOrPutStringOpt(gpa, library_name), | |
| 22910 | 23460 | .linkage = linkage, |
| 22911 | 23461 | .is_thread_local = is_thread_local_val.toBool(), |
| 22912 | 23462 | }; |
| ... | ... | @@ -22917,21 +23467,21 @@ fn zirBuiltinExtern( |
| 22917 | 23467 | block: *Block, |
| 22918 | 23468 | extended: Zir.Inst.Extended.InstData, |
| 22919 | 23469 | ) CompileError!Air.Inst.Ref { |
| 23470 | const mod = sema.mod; | |
| 22920 | 23471 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 22921 | 23472 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 22922 | 23473 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; |
| 22923 | 23474 | |
| 22924 | 23475 | var ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 22925 | if (!ty.isPtrAtRuntime()) { | |
| 23476 | if (!ty.isPtrAtRuntime(mod)) { | |
| 22926 | 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 | 23480 | const msg = msg: { |
| 22930 | const mod = sema.mod; | |
| 22931 | 23481 | const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)}); |
| 22932 | 23482 | errdefer msg.destroy(sema.gpa); |
| 22933 | 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 | 23485 | break :msg msg; |
| 22936 | 23486 | }; |
| 22937 | 23487 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -22945,52 +23495,51 @@ fn zirBuiltinExtern( |
| 22945 | 23495 | else => |e| return e, |
| 22946 | 23496 | }; |
| 22947 | 23497 | |
| 22948 | if (options.linkage == .Weak and !ty.ptrAllowsZero()) { | |
| 22949 | ty = try Type.optional(sema.arena, ty); | |
| 23498 | if (options.linkage == .Weak and !ty.ptrAllowsZero(mod)) { | |
| 23499 | ty = try Type.optional(sema.arena, ty, mod); | |
| 22950 | 23500 | } |
| 22951 | 23501 | |
| 22952 | 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); | |
| 22955 | errdefer sema.mod.destroyDecl(new_decl_index); | |
| 22956 | const new_decl = sema.mod.declPtr(new_decl_index); | |
| 22957 | new_decl.name = try sema.gpa.dupeZ(u8, options.name); | |
| 23504 | const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); | |
| 23505 | errdefer mod.destroyDecl(new_decl_index); | |
| 23506 | const new_decl = mod.declPtr(new_decl_index); | |
| 23507 | new_decl.name = options.name; | |
| 22958 | 23508 | |
| 22959 | 23509 | { |
| 22960 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | |
| 22961 | errdefer new_decl_arena.deinit(); | |
| 22962 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 22963 | ||
| 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), | |
| 23510 | const new_var = try mod.intern(.{ .variable = .{ | |
| 23511 | .ty = ty.toIntern(), | |
| 23512 | .init = .none, | |
| 23513 | .decl = sema.owner_decl_index, | |
| 22968 | 23514 | .is_extern = true, |
| 22969 | .is_mutable = false, | |
| 23515 | .is_const = true, | |
| 22970 | 23516 | .is_threadlocal = options.is_thread_local, |
| 22971 | 23517 | .is_weak_linkage = options.linkage == .Weak, |
| 22972 | .lib_name = null, | |
| 22973 | }; | |
| 23518 | } }); | |
| 22974 | 23519 | |
| 22975 | 23520 | new_decl.src_line = sema.owner_decl.src_line; |
| 22976 | 23521 | // We only access this decl through the decl_ref with the correct type created |
| 22977 | 23522 | // below, so this type doesn't matter |
| 22978 | new_decl.ty = Type.Tag.init(.anyopaque); | |
| 22979 | new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var); | |
| 23523 | new_decl.ty = ty; | |
| 23524 | new_decl.val = new_var.toValue(); | |
| 22980 | 23525 | new_decl.@"align" = 0; |
| 22981 | new_decl.@"linksection" = null; | |
| 23526 | new_decl.@"linksection" = .none; | |
| 22982 | 23527 | new_decl.has_tv = true; |
| 22983 | 23528 | new_decl.analysis = .complete; |
| 22984 | new_decl.generation = sema.mod.generation; | |
| 22985 | ||
| 22986 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 23529 | new_decl.generation = mod.generation; | |
| 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 | 23533 | try sema.ensureDeclAnalyzed(new_decl_index); |
| 22991 | 23534 | |
| 22992 | const ref = try Value.Tag.decl_ref.create(sema.arena, new_decl_index); | |
| 22993 | return sema.addConstant(ty, ref); | |
| 23535 | return sema.addConstant(ty, try mod.getCoerced((try mod.intern(.{ .ptr = .{ | |
| 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 | 23545 | fn zirWorkItem( |
| ... | ... | @@ -23073,7 +23622,7 @@ fn validateVarType( |
| 23073 | 23622 | const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)}); |
| 23074 | 23623 | errdefer msg.destroy(sema.gpa); |
| 23075 | 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 | 23626 | break :msg msg; |
| 23078 | 23627 | }; |
| 23079 | 23628 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -23086,8 +23635,8 @@ fn validateVarType( |
| 23086 | 23635 | errdefer msg.destroy(sema.gpa); |
| 23087 | 23636 | |
| 23088 | 23637 | const src_decl = mod.declPtr(block.src_decl); |
| 23089 | try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl), var_ty); | |
| 23090 | if (var_ty.zigTypeTag() == .ComptimeInt or var_ty.zigTypeTag() == .ComptimeFloat) { | |
| 23638 | try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), var_ty); | |
| 23639 | if (var_ty.zigTypeTag(mod) == .ComptimeInt or var_ty.zigTypeTag(mod) == .ComptimeFloat) { | |
| 23091 | 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 | 23650 | var_ty: Type, |
| 23102 | 23651 | is_extern: bool, |
| 23103 | 23652 | ) CompileError!bool { |
| 23653 | const mod = sema.mod; | |
| 23104 | 23654 | var ty = var_ty; |
| 23105 | while (true) switch (ty.zigTypeTag()) { | |
| 23655 | while (true) switch (ty.zigTypeTag(mod)) { | |
| 23106 | 23656 | .Bool, |
| 23107 | 23657 | .Int, |
| 23108 | 23658 | .Float, |
| ... | ... | @@ -23125,23 +23675,22 @@ fn validateRunTimeType( |
| 23125 | 23675 | => return false, |
| 23126 | 23676 | |
| 23127 | 23677 | .Pointer => { |
| 23128 | const elem_ty = ty.childType(); | |
| 23129 | switch (elem_ty.zigTypeTag()) { | |
| 23678 | const elem_ty = ty.childType(mod); | |
| 23679 | switch (elem_ty.zigTypeTag(mod)) { | |
| 23130 | 23680 | .Opaque => return true, |
| 23131 | .Fn => return elem_ty.isFnOrHasRuntimeBits(), | |
| 23681 | .Fn => return elem_ty.isFnOrHasRuntimeBits(mod), | |
| 23132 | 23682 | else => ty = elem_ty, |
| 23133 | 23683 | } |
| 23134 | 23684 | }, |
| 23135 | 23685 | .Opaque => return is_extern, |
| 23136 | 23686 | |
| 23137 | 23687 | .Optional => { |
| 23138 | var buf: Type.Payload.ElemType = undefined; | |
| 23139 | const child_ty = ty.optionalChild(&buf); | |
| 23688 | const child_ty = ty.optionalChild(mod); | |
| 23140 | 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 | 23695 | .Struct, .Union => { |
| 23147 | 23696 | const resolved_ty = try sema.resolveTypeFields(ty); |
| ... | ... | @@ -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 | 23705 | fn explainWhyTypeIsComptime( |
| 23157 | 23706 | sema: *Sema, |
| ... | ... | @@ -23174,7 +23723,7 @@ fn explainWhyTypeIsComptimeInner( |
| 23174 | 23723 | type_set: *TypeSet, |
| 23175 | 23724 | ) CompileError!void { |
| 23176 | 23725 | const mod = sema.mod; |
| 23177 | switch (ty.zigTypeTag()) { | |
| 23726 | switch (ty.zigTypeTag(mod)) { | |
| 23178 | 23727 | .Bool, |
| 23179 | 23728 | .Int, |
| 23180 | 23729 | .Float, |
| ... | ... | @@ -23208,12 +23757,12 @@ fn explainWhyTypeIsComptimeInner( |
| 23208 | 23757 | }, |
| 23209 | 23758 | |
| 23210 | 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 | 23762 | .Pointer => { |
| 23214 | const elem_ty = ty.elemType2(); | |
| 23215 | if (elem_ty.zigTypeTag() == .Fn) { | |
| 23216 | const fn_info = elem_ty.fnInfo(); | |
| 23763 | const elem_ty = ty.elemType2(mod); | |
| 23764 | if (elem_ty.zigTypeTag(mod) == .Fn) { | |
| 23765 | const fn_info = mod.typeToFunc(elem_ty).?; | |
| 23217 | 23766 | if (fn_info.is_generic) { |
| 23218 | 23767 | try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{}); |
| 23219 | 23768 | } |
| ... | ... | @@ -23221,29 +23770,27 @@ fn explainWhyTypeIsComptimeInner( |
| 23221 | 23770 | .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}), |
| 23222 | 23771 | else => {}, |
| 23223 | 23772 | } |
| 23224 | if (fn_info.return_type.comptimeOnly()) { | |
| 23773 | if (fn_info.return_type.toType().comptimeOnly(mod)) { | |
| 23225 | 23774 | try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{}); |
| 23226 | 23775 | } |
| 23227 | 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 | 23781 | .Optional => { |
| 23233 | var buf: Type.Payload.ElemType = undefined; | |
| 23234 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(&buf), type_set); | |
| 23782 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(mod), type_set); | |
| 23235 | 23783 | }, |
| 23236 | 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 | 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| { | |
| 23244 | const struct_obj = payload.data; | |
| 23791 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 23245 | 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 | 23794 | .index = i, |
| 23248 | 23795 | .range = .type, |
| 23249 | 23796 | }); |
| ... | ... | @@ -23258,12 +23805,11 @@ fn explainWhyTypeIsComptimeInner( |
| 23258 | 23805 | }, |
| 23259 | 23806 | |
| 23260 | 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| { | |
| 23264 | const union_obj = payload.data; | |
| 23810 | if (mod.typeToUnion(ty)) |union_obj| { | |
| 23265 | 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 | 23813 | .index = i, |
| 23268 | 23814 | .range = .type, |
| 23269 | 23815 | }); |
| ... | ... | @@ -23295,7 +23841,8 @@ fn validateExternType( |
| 23295 | 23841 | ty: Type, |
| 23296 | 23842 | position: ExternPosition, |
| 23297 | 23843 | ) !bool { |
| 23298 | switch (ty.zigTypeTag()) { | |
| 23844 | const mod = sema.mod; | |
| 23845 | switch (ty.zigTypeTag(mod)) { | |
| 23299 | 23846 | .Type, |
| 23300 | 23847 | .ComptimeFloat, |
| 23301 | 23848 | .ComptimeInt, |
| ... | ... | @@ -23313,8 +23860,8 @@ fn validateExternType( |
| 23313 | 23860 | .Float, |
| 23314 | 23861 | .AnyFrame, |
| 23315 | 23862 | => return true, |
| 23316 | .Pointer => return !(ty.isSlice() or try sema.typeRequiresComptime(ty)), | |
| 23317 | .Int => switch (ty.intInfo(sema.mod.getTarget()).bits) { | |
| 23863 | .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)), | |
| 23864 | .Int => switch (ty.intInfo(mod).bits) { | |
| 23318 | 23865 | 8, 16, 32, 64, 128 => return true, |
| 23319 | 23866 | else => return false, |
| 23320 | 23867 | }, |
| ... | ... | @@ -23323,20 +23870,18 @@ fn validateExternType( |
| 23323 | 23870 | const target = sema.mod.getTarget(); |
| 23324 | 23871 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. |
| 23325 | 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 | 23874 | return true; |
| 23328 | 23875 | } |
| 23329 | return !Type.fnCallingConventionAllowsZigTypes(target, ty.fnCallingConvention()); | |
| 23876 | return !target_util.fnCallConvAllowsZigTypes(target, ty.fnCallingConvention(mod)); | |
| 23330 | 23877 | }, |
| 23331 | 23878 | .Enum => { |
| 23332 | var buf: Type.Payload.Bits = undefined; | |
| 23333 | return sema.validateExternType(ty.intTagType(&buf), position); | |
| 23879 | return sema.validateExternType(ty.intTagType(mod), position); | |
| 23334 | 23880 | }, |
| 23335 | .Struct, .Union => switch (ty.containerLayout()) { | |
| 23881 | .Struct, .Union => switch (ty.containerLayout(mod)) { | |
| 23336 | 23882 | .Extern => return true, |
| 23337 | 23883 | .Packed => { |
| 23338 | const target = sema.mod.getTarget(); | |
| 23339 | const bit_size = try ty.bitSizeAdvanced(target, sema); | |
| 23884 | const bit_size = try ty.bitSizeAdvanced(mod, sema); | |
| 23340 | 23885 | switch (bit_size) { |
| 23341 | 23886 | 8, 16, 32, 64, 128 => return true, |
| 23342 | 23887 | else => return false, |
| ... | ... | @@ -23346,10 +23891,10 @@ fn validateExternType( |
| 23346 | 23891 | }, |
| 23347 | 23892 | .Array => { |
| 23348 | 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), | |
| 23352 | .Optional => return ty.isPtrLikeOptional(), | |
| 23896 | .Vector => return sema.validateExternType(ty.elemType2(mod), .element), | |
| 23897 | .Optional => return ty.isPtrLikeOptional(mod), | |
| 23353 | 23898 | } |
| 23354 | 23899 | } |
| 23355 | 23900 | |
| ... | ... | @@ -23361,7 +23906,7 @@ fn explainWhyTypeIsNotExtern( |
| 23361 | 23906 | position: ExternPosition, |
| 23362 | 23907 | ) CompileError!void { |
| 23363 | 23908 | const mod = sema.mod; |
| 23364 | switch (ty.zigTypeTag()) { | |
| 23909 | switch (ty.zigTypeTag(mod)) { | |
| 23365 | 23910 | .Opaque, |
| 23366 | 23911 | .Bool, |
| 23367 | 23912 | .Float, |
| ... | ... | @@ -23380,17 +23925,17 @@ fn explainWhyTypeIsNotExtern( |
| 23380 | 23925 | => return, |
| 23381 | 23926 | |
| 23382 | 23927 | .Pointer => { |
| 23383 | if (ty.isSlice()) { | |
| 23928 | if (ty.isSlice(mod)) { | |
| 23384 | 23929 | try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); |
| 23385 | 23930 | } else { |
| 23386 | const pointee_ty = ty.childType(); | |
| 23931 | const pointee_ty = ty.childType(mod); | |
| 23387 | 23932 | try mod.errNoteNonLazy(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(sema.mod)}); |
| 23388 | 23933 | try sema.explainWhyTypeIsComptime(msg, src_loc, pointee_ty); |
| 23389 | 23934 | } |
| 23390 | 23935 | }, |
| 23391 | 23936 | .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}), |
| 23392 | 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 | 23939 | try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{}); |
| 23395 | 23940 | } else { |
| 23396 | 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 | 23946 | try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{}); |
| 23402 | 23947 | return; |
| 23403 | 23948 | } |
| 23404 | switch (ty.fnCallingConvention()) { | |
| 23949 | switch (ty.fnCallingConvention(mod)) { | |
| 23405 | 23950 | .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}), |
| 23406 | 23951 | .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}), |
| 23407 | 23952 | .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}), |
| ... | ... | @@ -23409,8 +23954,7 @@ fn explainWhyTypeIsNotExtern( |
| 23409 | 23954 | } |
| 23410 | 23955 | }, |
| 23411 | 23956 | .Enum => { |
| 23412 | var buf: Type.Payload.Bits = undefined; | |
| 23413 | const tag_ty = ty.intTagType(&buf); | |
| 23957 | const tag_ty = ty.intTagType(mod); | |
| 23414 | 23958 | try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); |
| 23415 | 23959 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); |
| 23416 | 23960 | }, |
| ... | ... | @@ -23422,17 +23966,17 @@ fn explainWhyTypeIsNotExtern( |
| 23422 | 23966 | } else if (position == .param_ty) { |
| 23423 | 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 | 23972 | .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}), |
| 23429 | 23973 | } |
| 23430 | 23974 | } |
| 23431 | 23975 | |
| 23432 | 23976 | /// Returns true if `ty` is allowed in packed types. |
| 23433 | 23977 | /// Does *NOT* require `ty` to be resolved in any way. |
| 23434 | fn validatePackedType(ty: Type) bool { | |
| 23435 | switch (ty.zigTypeTag()) { | |
| 23978 | fn validatePackedType(ty: Type, mod: *Module) bool { | |
| 23979 | switch (ty.zigTypeTag(mod)) { | |
| 23436 | 23980 | .Type, |
| 23437 | 23981 | .ComptimeFloat, |
| 23438 | 23982 | .ComptimeInt, |
| ... | ... | @@ -23448,7 +23992,7 @@ fn validatePackedType(ty: Type) bool { |
| 23448 | 23992 | .Fn, |
| 23449 | 23993 | .Array, |
| 23450 | 23994 | => return false, |
| 23451 | .Optional => return ty.isPtrLikeOptional(), | |
| 23995 | .Optional => return ty.isPtrLikeOptional(mod), | |
| 23452 | 23996 | .Void, |
| 23453 | 23997 | .Bool, |
| 23454 | 23998 | .Float, |
| ... | ... | @@ -23456,8 +24000,8 @@ fn validatePackedType(ty: Type) bool { |
| 23456 | 24000 | .Vector, |
| 23457 | 24001 | .Enum, |
| 23458 | 24002 | => return true, |
| 23459 | .Pointer => return !ty.isSlice(), | |
| 23460 | .Struct, .Union => return ty.containerLayout() == .Packed, | |
| 24003 | .Pointer => return !ty.isSlice(mod), | |
| 24004 | .Struct, .Union => return ty.containerLayout(mod) == .Packed, | |
| 23461 | 24005 | } |
| 23462 | 24006 | } |
| 23463 | 24007 | |
| ... | ... | @@ -23468,7 +24012,7 @@ fn explainWhyTypeIsNotPacked( |
| 23468 | 24012 | ty: Type, |
| 23469 | 24013 | ) CompileError!void { |
| 23470 | 24014 | const mod = sema.mod; |
| 23471 | switch (ty.zigTypeTag()) { | |
| 24015 | switch (ty.zigTypeTag(mod)) { | |
| 23472 | 24016 | .Void, |
| 23473 | 24017 | .Bool, |
| 23474 | 24018 | .Float, |
| ... | ... | @@ -23616,7 +24160,6 @@ fn panicWithMsg( |
| 23616 | 24160 | msg_inst: Air.Inst.Ref, |
| 23617 | 24161 | ) !void { |
| 23618 | 24162 | const mod = sema.mod; |
| 23619 | const arena = sema.arena; | |
| 23620 | 24163 | |
| 23621 | 24164 | if (!mod.backendSupportsFeature(.panic_fn)) { |
| 23622 | 24165 | _ = try block.addNoOp(.trap); |
| ... | ... | @@ -23626,16 +24169,24 @@ fn panicWithMsg( |
| 23626 | 24169 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 23627 | 24170 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 23628 | 24171 | const target = mod.getTarget(); |
| 23629 | const ptr_stack_trace_ty = try Type.ptr(arena, mod, .{ | |
| 23630 | .pointee_type = stack_trace_ty, | |
| 23631 | .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic | |
| 24172 | const ptr_stack_trace_ty = try mod.ptrType(.{ | |
| 24173 | .child = stack_trace_ty.toIntern(), | |
| 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( | |
| 23634 | try Type.optional(arena, ptr_stack_trace_ty), | |
| 23635 | Value.null, | |
| 23636 | ); | |
| 23637 | const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value }; | |
| 23638 | try sema.callBuiltin(block, panic_fn, .auto, &args); | |
| 24178 | const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern()); | |
| 24179 | const null_stack_trace = try sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{ | |
| 24180 | .ty = opt_ptr_stack_trace_ty.toIntern(), | |
| 24181 | .val = .none, | |
| 24182 | } })).toValue()); | |
| 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 | 24192 | fn panicUnwrapError( |
| ... | ... | @@ -23694,20 +24245,6 @@ fn panicIndexOutOfBounds( |
| 23694 | 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 | 24248 | fn panicInactiveUnionField( |
| 23712 | 24249 | sema: *Sema, |
| 23713 | 24250 | parent_block: *Block, |
| ... | ... | @@ -23731,11 +24268,12 @@ fn panicSentinelMismatch( |
| 23731 | 24268 | sentinel_index: Air.Inst.Ref, |
| 23732 | 24269 | ) !void { |
| 23733 | 24270 | assert(!parent_block.is_comptime); |
| 24271 | const mod = sema.mod; | |
| 23734 | 24272 | const expected_sentinel_val = maybe_sentinel orelse return; |
| 23735 | 24273 | const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val); |
| 23736 | 24274 | |
| 23737 | 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 | 24277 | try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) |
| 23740 | 24278 | else blk: { |
| 23741 | 24279 | const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null); |
| ... | ... | @@ -23743,7 +24281,7 @@ fn panicSentinelMismatch( |
| 23743 | 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 | 24285 | const eql = |
| 23748 | 24286 | try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); |
| 23749 | 24287 | break :ok try parent_block.addInst(.{ |
| ... | ... | @@ -23753,7 +24291,7 @@ fn panicSentinelMismatch( |
| 23753 | 24291 | .operation = .And, |
| 23754 | 24292 | } }, |
| 23755 | 24293 | }); |
| 23756 | } else if (sentinel_ty.isSelfComparable(true)) | |
| 24294 | } else if (sentinel_ty.isSelfComparable(mod, true)) | |
| 23757 | 24295 | try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel) |
| 23758 | 24296 | else { |
| 23759 | 24297 | const panic_fn = try sema.getBuiltin("checkNonScalarSentinel"); |
| ... | ... | @@ -23805,12 +24343,14 @@ fn safetyPanic( |
| 23805 | 24343 | block: *Block, |
| 23806 | 24344 | panic_id: PanicId, |
| 23807 | 24345 | ) CompileError!void { |
| 24346 | const mod = sema.mod; | |
| 24347 | const gpa = sema.gpa; | |
| 23808 | 24348 | const panic_messages_ty = try sema.getBuiltinType("panic_messages"); |
| 23809 | 24349 | const msg_decl_index = (try sema.namespaceLookup( |
| 23810 | 24350 | block, |
| 23811 | 24351 | sema.src, |
| 23812 | panic_messages_ty.getNamespace().?, | |
| 23813 | @tagName(panic_id), | |
| 24352 | panic_messages_ty.getNamespaceIndex(mod).unwrap().?, | |
| 24353 | try mod.intern_pool.getOrPutString(gpa, @tagName(panic_id)), | |
| 23814 | 24354 | )).?; |
| 23815 | 24355 | |
| 23816 | 24356 | const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index); |
| ... | ... | @@ -23842,37 +24382,38 @@ fn fieldVal( |
| 23842 | 24382 | block: *Block, |
| 23843 | 24383 | src: LazySrcLoc, |
| 23844 | 24384 | object: Air.Inst.Ref, |
| 23845 | field_name: []const u8, | |
| 24385 | field_name: InternPool.NullTerminatedString, | |
| 23846 | 24386 | field_name_src: LazySrcLoc, |
| 23847 | 24387 | ) CompileError!Air.Inst.Ref { |
| 23848 | 24388 | // When editing this function, note that there is corresponding logic to be edited |
| 23849 | 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 | 24393 | const object_src = src; // TODO better source location |
| 23853 | 24394 | const object_ty = sema.typeOf(object); |
| 23854 | 24395 | |
| 23855 | 24396 | // Zig allows dereferencing a single pointer during field lookup. Note that |
| 23856 | 24397 | // we don't actually need to generate the dereference some field lookups, like the |
| 23857 | 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 | 24401 | const inner_ty = if (is_pointer_to) |
| 23861 | object_ty.childType() | |
| 24402 | object_ty.childType(mod) | |
| 23862 | 24403 | else |
| 23863 | 24404 | object_ty; |
| 23864 | 24405 | |
| 23865 | switch (inner_ty.zigTypeTag()) { | |
| 24406 | switch (inner_ty.zigTypeTag(mod)) { | |
| 23866 | 24407 | .Array => { |
| 23867 | if (mem.eql(u8, field_name, "len")) { | |
| 24408 | if (ip.stringEqlSlice(field_name, "len")) { | |
| 23868 | 24409 | return sema.addConstant( |
| 23869 | 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) { | |
| 23873 | const ptr_info = object_ty.ptrInfo().data; | |
| 23874 | const result_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 23875 | .pointee_type = ptr_info.pointee_type.childType(), | |
| 24413 | } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) { | |
| 24414 | const ptr_info = object_ty.ptrInfo(mod); | |
| 24415 | const result_ty = try Type.ptr(sema.arena, mod, .{ | |
| 24416 | .pointee_type = ptr_info.pointee_type.childType(mod), | |
| 23876 | 24417 | .sentinel = ptr_info.sentinel, |
| 23877 | 24418 | .@"align" = ptr_info.@"align", |
| 23878 | 24419 | .@"addrspace" = ptr_info.@"addrspace", |
| ... | ... | @@ -23889,21 +24430,21 @@ fn fieldVal( |
| 23889 | 24430 | return sema.fail( |
| 23890 | 24431 | block, |
| 23891 | 24432 | field_name_src, |
| 23892 | "no member named '{s}' in '{}'", | |
| 23893 | .{ field_name, object_ty.fmt(sema.mod) }, | |
| 24433 | "no member named '{}' in '{}'", | |
| 24434 | .{ field_name.fmt(ip), object_ty.fmt(mod) }, | |
| 23894 | 24435 | ); |
| 23895 | 24436 | } |
| 23896 | 24437 | }, |
| 23897 | 24438 | .Pointer => { |
| 23898 | const ptr_info = inner_ty.ptrInfo().data; | |
| 24439 | const ptr_info = inner_ty.ptrInfo(mod); | |
| 23899 | 24440 | if (ptr_info.size == .Slice) { |
| 23900 | if (mem.eql(u8, field_name, "ptr")) { | |
| 24441 | if (ip.stringEqlSlice(field_name, "ptr")) { | |
| 23901 | 24442 | const slice = if (is_pointer_to) |
| 23902 | 24443 | try sema.analyzeLoad(block, src, object, object_src) |
| 23903 | 24444 | else |
| 23904 | 24445 | object; |
| 23905 | 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 | 24448 | const slice = if (is_pointer_to) |
| 23908 | 24449 | try sema.analyzeLoad(block, src, object, object_src) |
| 23909 | 24450 | else |
| ... | ... | @@ -23913,8 +24454,8 @@ fn fieldVal( |
| 23913 | 24454 | return sema.fail( |
| 23914 | 24455 | block, |
| 23915 | 24456 | field_name_src, |
| 23916 | "no member named '{s}' in '{}'", | |
| 23917 | .{ field_name, object_ty.fmt(sema.mod) }, | |
| 24457 | "no member named '{}' in '{}'", | |
| 24458 | .{ field_name.fmt(ip), object_ty.fmt(mod) }, | |
| 23918 | 24459 | ); |
| 23919 | 24460 | } |
| 23920 | 24461 | } |
| ... | ... | @@ -23926,66 +24467,74 @@ fn fieldVal( |
| 23926 | 24467 | object; |
| 23927 | 24468 | |
| 23928 | 24469 | const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; |
| 23929 | var to_type_buffer: Value.ToTypeBuffer = undefined; | |
| 23930 | const child_type = val.toType(&to_type_buffer); | |
| 24470 | const child_type = val.toType(); | |
| 23931 | 24471 | |
| 23932 | switch (try child_type.zigTypeTagOrPoison()) { | |
| 24472 | switch (try child_type.zigTypeTagOrPoison(mod)) { | |
| 23933 | 24473 | .ErrorSet => { |
| 23934 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { | |
| 23935 | if (payload.data.names.getEntry(field_name)) |entry| { | |
| 23936 | break :blk entry.key_ptr.*; | |
| 23937 | } | |
| 23938 | const msg = msg: { | |
| 23939 | const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{ | |
| 23940 | field_name, child_type.fmt(sema.mod), | |
| 23941 | }); | |
| 23942 | errdefer msg.destroy(sema.gpa); | |
| 23943 | try sema.addDeclaredHereNote(msg, child_type); | |
| 23944 | break :msg msg; | |
| 23945 | }; | |
| 23946 | return sema.failWithOwnedErrorMsg(msg); | |
| 23947 | } else (try sema.mod.getErrorValue(field_name)).key; | |
| 24474 | switch (ip.indexToKey(child_type.toIntern())) { | |
| 24475 | .error_set_type => |error_set_type| blk: { | |
| 24476 | if (error_set_type.nameIndex(ip, field_name) != null) break :blk; | |
| 24477 | const msg = msg: { | |
| 24478 | const msg = try sema.errMsg(block, src, "no error named '{}' in '{}'", .{ | |
| 24479 | field_name.fmt(ip), child_type.fmt(mod), | |
| 24480 | }); | |
| 24481 | errdefer msg.destroy(sema.gpa); | |
| 24482 | try sema.addDeclaredHereNote(msg, child_type); | |
| 24483 | break :msg msg; | |
| 24484 | }; | |
| 24485 | return sema.failWithOwnedErrorMsg(msg); | |
| 24486 | }, | |
| 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( | |
| 23950 | if (!child_type.isAnyError()) | |
| 23951 | try child_type.copy(arena) | |
| 23952 | else | |
| 23953 | try Type.Tag.error_set_single.create(arena, name), | |
| 23954 | try Value.Tag.@"error".create(arena, .{ .name = name }), | |
| 23955 | ); | |
| 24497 | const error_set_type = if (!child_type.isAnyError(mod)) | |
| 24498 | child_type | |
| 24499 | else | |
| 24500 | try mod.singleErrorSetType(field_name); | |
| 24501 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ | |
| 24502 | .ty = error_set_type.toIntern(), | |
| 24503 | .name = field_name, | |
| 24504 | } })).toValue()); | |
| 23956 | 24505 | }, |
| 23957 | 24506 | .Union => { |
| 23958 | if (child_type.getNamespace()) |namespace| { | |
| 24507 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { | |
| 23959 | 24508 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { |
| 23960 | 24509 | return inst; |
| 23961 | 24510 | } |
| 23962 | 24511 | } |
| 23963 | 24512 | const union_ty = try sema.resolveTypeFields(child_type); |
| 23964 | if (union_ty.unionTagType()) |enum_ty| { | |
| 23965 | if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| { | |
| 24513 | if (union_ty.unionTagType(mod)) |enum_ty| { | |
| 24514 | if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| { | |
| 23966 | 24515 | const field_index = @intCast(u32, field_index_usize); |
| 23967 | 24516 | return sema.addConstant( |
| 23968 | 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 | 24522 | return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name); |
| 23974 | 24523 | }, |
| 23975 | 24524 | .Enum => { |
| 23976 | if (child_type.getNamespace()) |namespace| { | |
| 24525 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { | |
| 23977 | 24526 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { |
| 23978 | 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 | 24531 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 23983 | 24532 | const field_index = @intCast(u32, field_index_usize); |
| 23984 | const enum_val = try Value.Tag.enum_field_index.create(arena, field_index); | |
| 23985 | return sema.addConstant(try child_type.copy(arena), enum_val); | |
| 24533 | const enum_val = try mod.enumValueFieldIndex(child_type, field_index); | |
| 24534 | return sema.addConstant(child_type, enum_val); | |
| 23986 | 24535 | }, |
| 23987 | 24536 | .Struct, .Opaque => { |
| 23988 | if (child_type.getNamespace()) |namespace| { | |
| 24537 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { | |
| 23989 | 24538 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { |
| 23990 | 24539 | return inst; |
| 23991 | 24540 | } |
| ... | ... | @@ -23994,10 +24543,10 @@ fn fieldVal( |
| 23994 | 24543 | }, |
| 23995 | 24544 | else => { |
| 23996 | 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 | 24547 | errdefer msg.destroy(sema.gpa); |
| 23999 | if (child_type.isSlice()) 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", .{}); | |
| 24548 | if (child_type.isSlice(mod)) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{}); | |
| 24549 | if (child_type.zigTypeTag(mod) == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{}); | |
| 24001 | 24550 | break :msg msg; |
| 24002 | 24551 | }; |
| 24003 | 24552 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -24028,50 +24577,52 @@ fn fieldPtr( |
| 24028 | 24577 | block: *Block, |
| 24029 | 24578 | src: LazySrcLoc, |
| 24030 | 24579 | object_ptr: Air.Inst.Ref, |
| 24031 | field_name: []const u8, | |
| 24580 | field_name: InternPool.NullTerminatedString, | |
| 24032 | 24581 | field_name_src: LazySrcLoc, |
| 24033 | 24582 | initializing: bool, |
| 24034 | 24583 | ) CompileError!Air.Inst.Ref { |
| 24035 | 24584 | // When editing this function, note that there is corresponding logic to be edited |
| 24036 | 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 | 24589 | const object_ptr_src = src; // TODO better source location |
| 24039 | 24590 | const object_ptr_ty = sema.typeOf(object_ptr); |
| 24040 | const object_ty = switch (object_ptr_ty.zigTypeTag()) { | |
| 24041 | .Pointer => object_ptr_ty.elemType(), | |
| 24042 | else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(sema.mod)}), | |
| 24591 | const object_ty = switch (object_ptr_ty.zigTypeTag(mod)) { | |
| 24592 | .Pointer => object_ptr_ty.childType(mod), | |
| 24593 | else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(mod)}), | |
| 24043 | 24594 | }; |
| 24044 | 24595 | |
| 24045 | 24596 | // Zig allows dereferencing a single pointer during field lookup. Note that |
| 24046 | 24597 | // we don't actually need to generate the dereference some field lookups, like the |
| 24047 | 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 | 24601 | const inner_ty = if (is_pointer_to) |
| 24051 | object_ty.childType() | |
| 24602 | object_ty.childType(mod) | |
| 24052 | 24603 | else |
| 24053 | 24604 | object_ty; |
| 24054 | 24605 | |
| 24055 | switch (inner_ty.zigTypeTag()) { | |
| 24606 | switch (inner_ty.zigTypeTag(mod)) { | |
| 24056 | 24607 | .Array => { |
| 24057 | if (mem.eql(u8, field_name, "len")) { | |
| 24608 | if (ip.stringEqlSlice(field_name, "len")) { | |
| 24058 | 24609 | var anon_decl = try block.startAnonDecl(); |
| 24059 | 24610 | defer anon_decl.deinit(); |
| 24060 | 24611 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24061 | 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 | 24614 | 0, // default alignment |
| 24064 | 24615 | )); |
| 24065 | 24616 | } else { |
| 24066 | 24617 | return sema.fail( |
| 24067 | 24618 | block, |
| 24068 | 24619 | field_name_src, |
| 24069 | "no member named '{s}' in '{}'", | |
| 24070 | .{ field_name, object_ty.fmt(sema.mod) }, | |
| 24620 | "no member named '{}' in '{}'", | |
| 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 | 24626 | const inner_ptr = if (is_pointer_to) |
| 24076 | 24627 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| 24077 | 24628 | else |
| ... | ... | @@ -24079,47 +24630,44 @@ fn fieldPtr( |
| 24079 | 24630 | |
| 24080 | 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")) { | |
| 24083 | const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); | |
| 24084 | const slice_ptr_ty = inner_ty.slicePtrFieldType(buf); | |
| 24633 | if (ip.stringEqlSlice(field_name, "ptr")) { | |
| 24634 | const slice_ptr_ty = inner_ty.slicePtrFieldType(mod); | |
| 24085 | 24635 | |
| 24086 | const result_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 24636 | const result_ty = try Type.ptr(sema.arena, mod, .{ | |
| 24087 | 24637 | .pointee_type = slice_ptr_ty, |
| 24088 | .mutable = attr_ptr_ty.ptrIsMutable(), | |
| 24089 | .@"volatile" = attr_ptr_ty.isVolatilePtr(), | |
| 24090 | .@"addrspace" = attr_ptr_ty.ptrAddressSpace(), | |
| 24638 | .mutable = attr_ptr_ty.ptrIsMutable(mod), | |
| 24639 | .@"volatile" = attr_ptr_ty.isVolatilePtr(mod), | |
| 24640 | .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod), | |
| 24091 | 24641 | }); |
| 24092 | 24642 | |
| 24093 | 24643 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { |
| 24094 | return sema.addConstant( | |
| 24095 | result_ty, | |
| 24096 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 24097 | .container_ptr = val, | |
| 24098 | .container_ty = inner_ty, | |
| 24099 | .field_index = Value.Payload.Slice.ptr_index, | |
| 24100 | }), | |
| 24101 | ); | |
| 24644 | return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{ | |
| 24645 | .ty = result_ty.toIntern(), | |
| 24646 | .addr = .{ .field = .{ | |
| 24647 | .base = val.toIntern(), | |
| 24648 | .index = Value.slice_ptr_index, | |
| 24649 | } }, | |
| 24650 | } })).toValue()); | |
| 24102 | 24651 | } |
| 24103 | 24652 | try sema.requireRuntimeBlock(block, src, null); |
| 24104 | 24653 | |
| 24105 | 24654 | return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); |
| 24106 | } else if (mem.eql(u8, field_name, "len")) { | |
| 24107 | const result_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 24655 | } else if (ip.stringEqlSlice(field_name, "len")) { | |
| 24656 | const result_ty = try Type.ptr(sema.arena, mod, .{ | |
| 24108 | 24657 | .pointee_type = Type.usize, |
| 24109 | .mutable = attr_ptr_ty.ptrIsMutable(), | |
| 24110 | .@"volatile" = attr_ptr_ty.isVolatilePtr(), | |
| 24111 | .@"addrspace" = attr_ptr_ty.ptrAddressSpace(), | |
| 24658 | .mutable = attr_ptr_ty.ptrIsMutable(mod), | |
| 24659 | .@"volatile" = attr_ptr_ty.isVolatilePtr(mod), | |
| 24660 | .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod), | |
| 24112 | 24661 | }); |
| 24113 | 24662 | |
| 24114 | 24663 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { |
| 24115 | return sema.addConstant( | |
| 24116 | result_ty, | |
| 24117 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 24118 | .container_ptr = val, | |
| 24119 | .container_ty = inner_ty, | |
| 24120 | .field_index = Value.Payload.Slice.len_index, | |
| 24121 | }), | |
| 24122 | ); | |
| 24664 | return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{ | |
| 24665 | .ty = result_ty.toIntern(), | |
| 24666 | .addr = .{ .field = .{ | |
| 24667 | .base = val.toIntern(), | |
| 24668 | .index = Value.slice_len_index, | |
| 24669 | } }, | |
| 24670 | } })).toValue()); | |
| 24123 | 24671 | } |
| 24124 | 24672 | try sema.requireRuntimeBlock(block, src, null); |
| 24125 | 24673 | |
| ... | ... | @@ -24128,8 +24676,8 @@ fn fieldPtr( |
| 24128 | 24676 | return sema.fail( |
| 24129 | 24677 | block, |
| 24130 | 24678 | field_name_src, |
| 24131 | "no member named '{s}' in '{}'", | |
| 24132 | .{ field_name, object_ty.fmt(sema.mod) }, | |
| 24679 | "no member named '{}' in '{}'", | |
| 24680 | .{ field_name.fmt(ip), object_ty.fmt(mod) }, | |
| 24133 | 24681 | ); |
| 24134 | 24682 | } |
| 24135 | 24683 | }, |
| ... | ... | @@ -24142,47 +24690,59 @@ fn fieldPtr( |
| 24142 | 24690 | result; |
| 24143 | 24691 | |
| 24144 | 24692 | const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; |
| 24145 | var to_type_buffer: Value.ToTypeBuffer = undefined; | |
| 24146 | const child_type = val.toType(&to_type_buffer); | |
| 24693 | const child_type = val.toType(); | |
| 24147 | 24694 | |
| 24148 | switch (child_type.zigTypeTag()) { | |
| 24695 | switch (child_type.zigTypeTag(mod)) { | |
| 24149 | 24696 | .ErrorSet => { |
| 24150 | // TODO resolve inferred error sets | |
| 24151 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { | |
| 24152 | if (payload.data.names.getEntry(field_name)) |entry| { | |
| 24153 | break :blk entry.key_ptr.*; | |
| 24154 | } | |
| 24155 | return sema.fail(block, src, "no error named '{s}' in '{}'", .{ | |
| 24156 | field_name, child_type.fmt(sema.mod), | |
| 24157 | }); | |
| 24158 | } else (try sema.mod.getErrorValue(field_name)).key; | |
| 24697 | switch (ip.indexToKey(child_type.toIntern())) { | |
| 24698 | .error_set_type => |error_set_type| blk: { | |
| 24699 | if (error_set_type.nameIndex(ip, field_name) != null) { | |
| 24700 | break :blk; | |
| 24701 | } | |
| 24702 | return sema.fail(block, src, "no error named '{}' in '{}'", .{ | |
| 24703 | field_name.fmt(ip), child_type.fmt(mod), | |
| 24704 | }); | |
| 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 | 24716 | var anon_decl = try block.startAnonDecl(); |
| 24161 | 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 | 24722 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24163 | if (!child_type.isAnyError()) | |
| 24164 | try child_type.copy(anon_decl.arena()) | |
| 24165 | else | |
| 24166 | try Type.Tag.error_set_single.create(anon_decl.arena(), name), | |
| 24167 | try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), | |
| 24723 | error_set_type, | |
| 24724 | (try mod.intern(.{ .err = .{ | |
| 24725 | .ty = error_set_type.toIntern(), | |
| 24726 | .name = field_name, | |
| 24727 | } })).toValue(), | |
| 24168 | 24728 | 0, // default alignment |
| 24169 | 24729 | )); |
| 24170 | 24730 | }, |
| 24171 | 24731 | .Union => { |
| 24172 | if (child_type.getNamespace()) |namespace| { | |
| 24732 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { | |
| 24173 | 24733 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { |
| 24174 | 24734 | return inst; |
| 24175 | 24735 | } |
| 24176 | 24736 | } |
| 24177 | 24737 | const union_ty = try sema.resolveTypeFields(child_type); |
| 24178 | if (union_ty.unionTagType()) |enum_ty| { | |
| 24179 | if (enum_ty.enumFieldIndex(field_name)) |field_index| { | |
| 24738 | if (union_ty.unionTagType(mod)) |enum_ty| { | |
| 24739 | if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| { | |
| 24180 | 24740 | const field_index_u32 = @intCast(u32, field_index); |
| 24181 | 24741 | var anon_decl = try block.startAnonDecl(); |
| 24182 | 24742 | defer anon_decl.deinit(); |
| 24183 | 24743 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24184 | try enum_ty.copy(anon_decl.arena()), | |
| 24185 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), | |
| 24744 | enum_ty, | |
| 24745 | try mod.enumValueFieldIndex(enum_ty, field_index_u32), | |
| 24186 | 24746 | 0, // default alignment |
| 24187 | 24747 | )); |
| 24188 | 24748 | } |
| ... | ... | @@ -24190,32 +24750,32 @@ fn fieldPtr( |
| 24190 | 24750 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 24191 | 24751 | }, |
| 24192 | 24752 | .Enum => { |
| 24193 | if (child_type.getNamespace()) |namespace| { | |
| 24753 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { | |
| 24194 | 24754 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { |
| 24195 | 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 | 24759 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 24200 | 24760 | }; |
| 24201 | 24761 | const field_index_u32 = @intCast(u32, field_index); |
| 24202 | 24762 | var anon_decl = try block.startAnonDecl(); |
| 24203 | 24763 | defer anon_decl.deinit(); |
| 24204 | 24764 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24205 | try child_type.copy(anon_decl.arena()), | |
| 24206 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), | |
| 24765 | child_type, | |
| 24766 | try mod.enumValueFieldIndex(child_type, field_index_u32), | |
| 24207 | 24767 | 0, // default alignment |
| 24208 | 24768 | )); |
| 24209 | 24769 | }, |
| 24210 | 24770 | .Struct, .Opaque => { |
| 24211 | if (child_type.getNamespace()) |namespace| { | |
| 24771 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { | |
| 24212 | 24772 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { |
| 24213 | 24773 | return inst; |
| 24214 | 24774 | } |
| 24215 | 24775 | } |
| 24216 | 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 | 24781 | .Struct => { |
| ... | ... | @@ -24252,22 +24812,24 @@ fn fieldCallBind( |
| 24252 | 24812 | block: *Block, |
| 24253 | 24813 | src: LazySrcLoc, |
| 24254 | 24814 | raw_ptr: Air.Inst.Ref, |
| 24255 | field_name: []const u8, | |
| 24815 | field_name: InternPool.NullTerminatedString, | |
| 24256 | 24816 | field_name_src: LazySrcLoc, |
| 24257 | 24817 | ) CompileError!ResolvedFieldCallee { |
| 24258 | 24818 | // When editing this function, note that there is corresponding logic to be edited |
| 24259 | 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 | 24823 | const raw_ptr_src = src; // TODO better source location |
| 24262 | 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)) | |
| 24264 | raw_ptr_ty.childType() | |
| 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)) | |
| 24826 | raw_ptr_ty.childType(mod) | |
| 24265 | 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 | 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; | |
| 24270 | const concrete_ty = if (is_double_ptr) inner_ty.childType() else inner_ty; | |
| 24831 | const is_double_ptr = inner_ty.zigTypeTag(mod) == .Pointer and inner_ty.ptrSize(mod) == .One; | |
| 24832 | const concrete_ty = if (is_double_ptr) inner_ty.childType(mod) else inner_ty; | |
| 24271 | 24833 | const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty; |
| 24272 | 24834 | const object_ptr = if (is_double_ptr) |
| 24273 | 24835 | try sema.analyzeLoad(block, src, raw_ptr, src) |
| ... | ... | @@ -24275,37 +24837,37 @@ fn fieldCallBind( |
| 24275 | 24837 | raw_ptr; |
| 24276 | 24838 | |
| 24277 | 24839 | find_field: { |
| 24278 | switch (concrete_ty.zigTypeTag()) { | |
| 24840 | switch (concrete_ty.zigTypeTag(mod)) { | |
| 24279 | 24841 | .Struct => { |
| 24280 | 24842 | const struct_ty = try sema.resolveTypeFields(concrete_ty); |
| 24281 | if (struct_ty.castTag(.@"struct")) |struct_obj| { | |
| 24282 | const field_index_usize = struct_obj.data.fields.getIndex(field_name) orelse | |
| 24843 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | |
| 24844 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | |
| 24283 | 24845 | break :find_field; |
| 24284 | 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 | 24849 | return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); |
| 24288 | } else if (struct_ty.isTuple()) { | |
| 24289 | if (mem.eql(u8, field_name, "len")) { | |
| 24290 | return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount()) }; | |
| 24850 | } else if (struct_ty.isTuple(mod)) { | |
| 24851 | if (ip.stringEqlSlice(field_name, "len")) { | |
| 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 | 24858 | } else { |
| 24297 | const max = struct_ty.structFieldCount(); | |
| 24298 | var i: u32 = 0; | |
| 24299 | while (i < max) : (i += 1) { | |
| 24300 | if (mem.eql(u8, struct_ty.structFieldName(i), field_name)) { | |
| 24301 | return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i), i, object_ptr); | |
| 24859 | const max = struct_ty.structFieldCount(mod); | |
| 24860 | for (0..max) |i_usize| { | |
| 24861 | const i = @intCast(u32, i_usize); | |
| 24862 | if (field_name == struct_ty.structFieldName(i, mod)) { | |
| 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 | 24868 | .Union => { |
| 24307 | 24869 | const union_ty = try sema.resolveTypeFields(concrete_ty); |
| 24308 | const fields = union_ty.unionFields(); | |
| 24870 | const fields = union_ty.unionFields(mod); | |
| 24309 | 24871 | const field_index_usize = fields.getIndex(field_name) orelse break :find_field; |
| 24310 | 24872 | const field_index = @intCast(u32, field_index_usize); |
| 24311 | 24873 | const field = fields.values()[field_index]; |
| ... | ... | @@ -24321,24 +24883,23 @@ fn fieldCallBind( |
| 24321 | 24883 | } |
| 24322 | 24884 | |
| 24323 | 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 | 24887 | .Struct, .Opaque, .Union, .Enum => found_decl: { |
| 24326 | if (concrete_ty.getNamespace()) |namespace| { | |
| 24888 | if (concrete_ty.getNamespaceIndex(mod).unwrap()) |namespace| { | |
| 24327 | 24889 | if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| { |
| 24328 | 24890 | try sema.addReferencedBy(block, src, decl_idx); |
| 24329 | 24891 | const decl_val = try sema.analyzeDeclVal(block, src, decl_idx); |
| 24330 | 24892 | const decl_type = sema.typeOf(decl_val); |
| 24331 | if (decl_type.zigTypeTag() == .Fn and | |
| 24332 | decl_type.fnParamLen() >= 1) | |
| 24333 | { | |
| 24334 | const first_param_type = decl_type.fnParamType(0); | |
| 24335 | const first_param_tag = first_param_type.tag(); | |
| 24893 | if (mod.typeToFunc(decl_type)) |func_type| f: { | |
| 24894 | if (func_type.param_types.len == 0) break :f; | |
| 24895 | ||
| 24896 | const first_param_type = func_type.param_types[0].toType(); | |
| 24336 | 24897 | // zig fmt: off |
| 24337 | if (first_param_tag == .generic_poison or ( | |
| 24338 | first_param_type.zigTypeTag() == .Pointer and | |
| 24339 | (first_param_type.ptrSize() == .One or | |
| 24340 | first_param_type.ptrSize() == .C) and | |
| 24341 | first_param_type.childType().eql(concrete_ty, sema.mod))) | |
| 24898 | if (first_param_type.isGenericPoison() or ( | |
| 24899 | first_param_type.zigTypeTag(mod) == .Pointer and | |
| 24900 | (first_param_type.ptrSize(mod) == .One or | |
| 24901 | first_param_type.ptrSize(mod) == .C) and | |
| 24902 | first_param_type.childType(mod).eql(concrete_ty, mod))) | |
| 24342 | 24903 | { |
| 24343 | 24904 | // zig fmt: on |
| 24344 | 24905 | // Note that if the param type is generic poison, we know that it must |
| ... | ... | @@ -24350,32 +24911,31 @@ fn fieldCallBind( |
| 24350 | 24911 | .func_inst = decl_val, |
| 24351 | 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 | 24915 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24355 | 24916 | return .{ .method = .{ |
| 24356 | 24917 | .func_inst = decl_val, |
| 24357 | 24918 | .arg0_inst = deref, |
| 24358 | 24919 | } }; |
| 24359 | } else if (first_param_type.zigTypeTag() == .Optional) { | |
| 24360 | var opt_buf: Type.Payload.ElemType = undefined; | |
| 24361 | const child = first_param_type.optionalChild(&opt_buf); | |
| 24362 | if (child.eql(concrete_ty, sema.mod)) { | |
| 24920 | } else if (first_param_type.zigTypeTag(mod) == .Optional) { | |
| 24921 | const child = first_param_type.optionalChild(mod); | |
| 24922 | if (child.eql(concrete_ty, mod)) { | |
| 24363 | 24923 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24364 | 24924 | return .{ .method = .{ |
| 24365 | 24925 | .func_inst = decl_val, |
| 24366 | 24926 | .arg0_inst = deref, |
| 24367 | 24927 | } }; |
| 24368 | } else if (child.zigTypeTag() == .Pointer and | |
| 24369 | child.ptrSize() == .One and | |
| 24370 | child.childType().eql(concrete_ty, sema.mod)) | |
| 24928 | } else if (child.zigTypeTag(mod) == .Pointer and | |
| 24929 | child.ptrSize(mod) == .One and | |
| 24930 | child.childType(mod).eql(concrete_ty, mod)) | |
| 24371 | 24931 | { |
| 24372 | 24932 | return .{ .method = .{ |
| 24373 | 24933 | .func_inst = decl_val, |
| 24374 | 24934 | .arg0_inst = object_ptr, |
| 24375 | 24935 | } }; |
| 24376 | 24936 | } |
| 24377 | } else if (first_param_type.zigTypeTag() == .ErrorUnion and | |
| 24378 | first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod)) | |
| 24937 | } else if (first_param_type.zigTypeTag(mod) == .ErrorUnion and | |
| 24938 | first_param_type.errorUnionPayload(mod).eql(concrete_ty, mod)) | |
| 24379 | 24939 | { |
| 24380 | 24940 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24381 | 24941 | return .{ .method = .{ |
| ... | ... | @@ -24393,12 +24953,15 @@ fn fieldCallBind( |
| 24393 | 24953 | }; |
| 24394 | 24954 | |
| 24395 | 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 | 24960 | errdefer msg.destroy(sema.gpa); |
| 24398 | 24961 | try sema.addDeclaredHereNote(msg, concrete_ty); |
| 24399 | 24962 | if (found_decl) |decl_idx| { |
| 24400 | const decl = sema.mod.declPtr(decl_idx); | |
| 24401 | try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "'{s}' is not a member function", .{field_name}); | |
| 24963 | const decl = mod.declPtr(decl_idx); | |
| 24964 | try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{}' is not a member function", .{field_name.fmt(ip)}); | |
| 24402 | 24965 | } |
| 24403 | 24966 | break :msg msg; |
| 24404 | 24967 | }; |
| ... | ... | @@ -24414,29 +24977,29 @@ fn finishFieldCallBind( |
| 24414 | 24977 | field_index: u32, |
| 24415 | 24978 | object_ptr: Air.Inst.Ref, |
| 24416 | 24979 | ) CompileError!ResolvedFieldCallee { |
| 24980 | const mod = sema.mod; | |
| 24417 | 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 | 24983 | .pointee_type = field_ty, |
| 24420 | .mutable = ptr_ty.ptrIsMutable(), | |
| 24421 | .@"addrspace" = ptr_ty.ptrAddressSpace(), | |
| 24984 | .mutable = ptr_ty.ptrIsMutable(mod), | |
| 24985 | .@"addrspace" = ptr_ty.ptrAddressSpace(mod), | |
| 24422 | 24986 | }); |
| 24423 | 24987 | |
| 24424 | const container_ty = ptr_ty.childType(); | |
| 24425 | if (container_ty.zigTypeTag() == .Struct) { | |
| 24426 | if (container_ty.structFieldValueComptime(field_index)) |default_val| { | |
| 24988 | const container_ty = ptr_ty.childType(mod); | |
| 24989 | if (container_ty.zigTypeTag(mod) == .Struct) { | |
| 24990 | if (try container_ty.structFieldValueComptime(mod, field_index)) |default_val| { | |
| 24427 | 24991 | return .{ .direct = try sema.addConstant(field_ty, default_val) }; |
| 24428 | 24992 | } |
| 24429 | 24993 | } |
| 24430 | 24994 | |
| 24431 | 24995 | if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { |
| 24432 | const pointer = try sema.addConstant( | |
| 24433 | ptr_field_ty, | |
| 24434 | try Value.Tag.field_ptr.create(arena, .{ | |
| 24435 | .container_ptr = struct_ptr_val, | |
| 24436 | .container_ty = container_ty, | |
| 24437 | .field_index = field_index, | |
| 24438 | }), | |
| 24439 | ); | |
| 24996 | const pointer = try sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 24997 | .ty = ptr_field_ty.toIntern(), | |
| 24998 | .addr = .{ .field = .{ | |
| 24999 | .base = struct_ptr_val.toIntern(), | |
| 25000 | .index = field_index, | |
| 25001 | } }, | |
| 25002 | } })).toValue()); | |
| 24440 | 25003 | return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) }; |
| 24441 | 25004 | } |
| 24442 | 25005 | |
| ... | ... | @@ -24449,19 +25012,20 @@ fn namespaceLookup( |
| 24449 | 25012 | sema: *Sema, |
| 24450 | 25013 | block: *Block, |
| 24451 | 25014 | src: LazySrcLoc, |
| 24452 | namespace: *Namespace, | |
| 24453 | decl_name: []const u8, | |
| 25015 | namespace: Namespace.Index, | |
| 25016 | decl_name: InternPool.NullTerminatedString, | |
| 24454 | 25017 | ) CompileError!?Decl.Index { |
| 25018 | const mod = sema.mod; | |
| 24455 | 25019 | const gpa = sema.gpa; |
| 24456 | 25020 | if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { |
| 24457 | const decl = sema.mod.declPtr(decl_index); | |
| 24458 | if (!decl.is_pub and decl.getFileScope() != block.getFileScope()) { | |
| 25021 | const decl = mod.declPtr(decl_index); | |
| 25022 | if (!decl.is_pub and decl.getFileScope(mod) != block.getFileScope(mod)) { | |
| 24459 | 25023 | const msg = msg: { |
| 24460 | const msg = try sema.errMsg(block, src, "'{s}' is not marked 'pub'", .{ | |
| 24461 | decl_name, | |
| 25024 | const msg = try sema.errMsg(block, src, "'{}' is not marked 'pub'", .{ | |
| 25025 | decl_name.fmt(&mod.intern_pool), | |
| 24462 | 25026 | }); |
| 24463 | 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 | 25029 | break :msg msg; |
| 24466 | 25030 | }; |
| 24467 | 25031 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -24475,8 +25039,8 @@ fn namespaceLookupRef( |
| 24475 | 25039 | sema: *Sema, |
| 24476 | 25040 | block: *Block, |
| 24477 | 25041 | src: LazySrcLoc, |
| 24478 | namespace: *Namespace, | |
| 24479 | decl_name: []const u8, | |
| 25042 | namespace: Namespace.Index, | |
| 25043 | decl_name: InternPool.NullTerminatedString, | |
| 24480 | 25044 | ) CompileError!?Air.Inst.Ref { |
| 24481 | 25045 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; |
| 24482 | 25046 | try sema.addReferencedBy(block, src, decl); |
| ... | ... | @@ -24487,8 +25051,8 @@ fn namespaceLookupVal( |
| 24487 | 25051 | sema: *Sema, |
| 24488 | 25052 | block: *Block, |
| 24489 | 25053 | src: LazySrcLoc, |
| 24490 | namespace: *Namespace, | |
| 24491 | decl_name: []const u8, | |
| 25054 | namespace: Namespace.Index, | |
| 25055 | decl_name: InternPool.NullTerminatedString, | |
| 24492 | 25056 | ) CompileError!?Air.Inst.Ref { |
| 24493 | 25057 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; |
| 24494 | 25058 | return try sema.analyzeDeclVal(block, src, decl); |
| ... | ... | @@ -24499,29 +25063,30 @@ fn structFieldPtr( |
| 24499 | 25063 | block: *Block, |
| 24500 | 25064 | src: LazySrcLoc, |
| 24501 | 25065 | struct_ptr: Air.Inst.Ref, |
| 24502 | field_name: []const u8, | |
| 25066 | field_name: InternPool.NullTerminatedString, | |
| 24503 | 25067 | field_name_src: LazySrcLoc, |
| 24504 | 25068 | unresolved_struct_ty: Type, |
| 24505 | 25069 | initializing: bool, |
| 24506 | 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 | 25074 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 24510 | 25075 | try sema.resolveStructLayout(struct_ty); |
| 24511 | 25076 | |
| 24512 | if (struct_ty.isTuple()) { | |
| 24513 | if (mem.eql(u8, field_name, "len")) { | |
| 24514 | const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount()); | |
| 25077 | if (struct_ty.isTuple(mod)) { | |
| 25078 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { | |
| 25079 | const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)); | |
| 24515 | 25080 | return sema.analyzeRef(block, src, len_inst); |
| 24516 | 25081 | } |
| 24517 | 25082 | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); |
| 24518 | 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 | 25085 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); |
| 24521 | 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 | 25091 | const field_index_big = struct_obj.fields.getIndex(field_name) orelse |
| 24527 | 25092 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); |
| ... | ... | @@ -24540,14 +25105,15 @@ fn structFieldPtrByIndex( |
| 24540 | 25105 | struct_ty: Type, |
| 24541 | 25106 | initializing: bool, |
| 24542 | 25107 | ) CompileError!Air.Inst.Ref { |
| 24543 | if (struct_ty.isAnonStruct()) { | |
| 25108 | const mod = sema.mod; | |
| 25109 | if (struct_ty.isAnonStruct(mod)) { | |
| 24544 | 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 | 25114 | const field = struct_obj.fields.values()[field_index]; |
| 24549 | 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 | 25118 | var ptr_ty_data: Type.Payload.Pointer.Data = .{ |
| 24553 | 25119 | .pointee_type = field.ty, |
| ... | ... | @@ -24556,7 +25122,7 @@ fn structFieldPtrByIndex( |
| 24556 | 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 | 25127 | if (struct_obj.layout == .Packed) { |
| 24562 | 25128 | comptime assert(Type.packed_struct_layout_version == 2); |
| ... | ... | @@ -24568,7 +25134,7 @@ fn structFieldPtrByIndex( |
| 24568 | 25134 | if (i == field_index) { |
| 24569 | 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 | 25139 | ptr_ty_data.host_size = (running_bits + 7) / 8; |
| 24574 | 25140 | |
| ... | ... | @@ -24582,7 +25148,7 @@ fn structFieldPtrByIndex( |
| 24582 | 25148 | const parent_align = if (struct_ptr_ty_info.@"align" != 0) |
| 24583 | 25149 | struct_ptr_ty_info.@"align" |
| 24584 | 25150 | else |
| 24585 | struct_ptr_ty_info.pointee_type.abiAlignment(target); | |
| 25151 | struct_ptr_ty_info.pointee_type.abiAlignment(mod); | |
| 24586 | 25152 | ptr_ty_data.@"align" = parent_align; |
| 24587 | 25153 | |
| 24588 | 25154 | // If the field happens to be byte-aligned, simplify the pointer type. |
| ... | ... | @@ -24596,8 +25162,8 @@ fn structFieldPtrByIndex( |
| 24596 | 25162 | if (parent_align != 0 and ptr_ty_data.bit_offset % 8 == 0 and |
| 24597 | 25163 | target.cpu.arch.endian() == .Little) |
| 24598 | 25164 | { |
| 24599 | const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(target); | |
| 24600 | const elem_size_bits = ptr_ty_data.pointee_type.bitSize(target); | |
| 25165 | const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(mod); | |
| 25166 | const elem_size_bits = ptr_ty_data.pointee_type.bitSize(mod); | |
| 24601 | 25167 | if (elem_size_bytes * 8 == elem_size_bits) { |
| 24602 | 25168 | const byte_offset = ptr_ty_data.bit_offset / 8; |
| 24603 | 25169 | const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align)); |
| ... | ... | @@ -24610,25 +25176,25 @@ fn structFieldPtrByIndex( |
| 24610 | 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 | 25181 | if (field.is_comptime) { |
| 24616 | const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ | |
| 24617 | .field_ty = try field.ty.copy(sema.arena), | |
| 24618 | .field_val = try field.default_val.copy(sema.arena), | |
| 24619 | }); | |
| 24620 | return sema.addConstant(ptr_field_ty, val); | |
| 25182 | const val = try mod.intern(.{ .ptr = .{ | |
| 25183 | .ty = ptr_field_ty.toIntern(), | |
| 25184 | .addr = .{ .comptime_field = field.default_val }, | |
| 25185 | } }); | |
| 25186 | return sema.addConstant(ptr_field_ty, val.toValue()); | |
| 24621 | 25187 | } |
| 24622 | 25188 | |
| 24623 | 25189 | if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { |
| 24624 | return sema.addConstant( | |
| 24625 | ptr_field_ty, | |
| 24626 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 24627 | .container_ptr = struct_ptr_val, | |
| 24628 | .container_ty = struct_ptr_ty.childType(), | |
| 24629 | .field_index = field_index, | |
| 24630 | }), | |
| 24631 | ); | |
| 25190 | const val = try mod.intern(.{ .ptr = .{ | |
| 25191 | .ty = ptr_field_ty.toIntern(), | |
| 25192 | .addr = .{ .field = .{ | |
| 25193 | .base = try struct_ptr_val.intern(struct_ptr_ty, mod), | |
| 25194 | .index = field_index, | |
| 25195 | } }, | |
| 25196 | } }); | |
| 25197 | return sema.addConstant(ptr_field_ty, val.toValue()); | |
| 24632 | 25198 | } |
| 24633 | 25199 | |
| 24634 | 25200 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -24640,21 +25206,17 @@ fn structFieldVal( |
| 24640 | 25206 | block: *Block, |
| 24641 | 25207 | src: LazySrcLoc, |
| 24642 | 25208 | struct_byval: Air.Inst.Ref, |
| 24643 | field_name: []const u8, | |
| 25209 | field_name: InternPool.NullTerminatedString, | |
| 24644 | 25210 | field_name_src: LazySrcLoc, |
| 24645 | 25211 | unresolved_struct_ty: Type, |
| 24646 | 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 | 25216 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 24650 | switch (struct_ty.tag()) { | |
| 24651 | .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty), | |
| 24652 | .anon_struct => { | |
| 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; | |
| 25217 | switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { | |
| 25218 | .struct_type => |struct_type| { | |
| 25219 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 24658 | 25220 | if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); |
| 24659 | 25221 | |
| 24660 | 25222 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| ... | ... | @@ -24663,22 +25225,28 @@ fn structFieldVal( |
| 24663 | 25225 | const field = struct_obj.fields.values()[field_index]; |
| 24664 | 25226 | |
| 24665 | 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 | 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 | 25233 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { |
| 24672 | 25234 | return sema.addConstant(field.ty, opv); |
| 24673 | 25235 | } |
| 24674 | ||
| 24675 | const field_values = struct_val.castTag(.aggregate).?.data; | |
| 24676 | return sema.addConstant(field.ty, field_values[field_index]); | |
| 25236 | return sema.addConstant(field.ty, try struct_val.fieldValue(mod, field_index)); | |
| 24677 | 25237 | } |
| 24678 | 25238 | |
| 24679 | 25239 | try sema.requireRuntimeBlock(block, src, null); |
| 24680 | 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 | 25250 | else => unreachable, |
| 24683 | 25251 | } |
| 24684 | 25252 | } |
| ... | ... | @@ -24688,12 +25256,13 @@ fn tupleFieldVal( |
| 24688 | 25256 | block: *Block, |
| 24689 | 25257 | src: LazySrcLoc, |
| 24690 | 25258 | tuple_byval: Air.Inst.Ref, |
| 24691 | field_name: []const u8, | |
| 25259 | field_name: InternPool.NullTerminatedString, | |
| 24692 | 25260 | field_name_src: LazySrcLoc, |
| 24693 | 25261 | tuple_ty: Type, |
| 24694 | 25262 | ) CompileError!Air.Inst.Ref { |
| 24695 | if (mem.eql(u8, field_name, "len")) { | |
| 24696 | return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount()); | |
| 25263 | const mod = sema.mod; | |
| 25264 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { | |
| 25265 | return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount(mod)); | |
| 24697 | 25266 | } |
| 24698 | 25267 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src); |
| 24699 | 25268 | return sema.tupleFieldValByIndex(block, src, tuple_byval, field_index, tuple_ty); |
| ... | ... | @@ -24704,19 +25273,20 @@ fn tupleFieldIndex( |
| 24704 | 25273 | sema: *Sema, |
| 24705 | 25274 | block: *Block, |
| 24706 | 25275 | tuple_ty: Type, |
| 24707 | field_name: []const u8, | |
| 25276 | field_name: InternPool.NullTerminatedString, | |
| 24708 | 25277 | field_name_src: LazySrcLoc, |
| 24709 | 25278 | ) CompileError!u32 { |
| 24710 | assert(!std.mem.eql(u8, field_name, "len")); | |
| 24711 | if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { | |
| 24712 | if (field_index < tuple_ty.structFieldCount()) return field_index; | |
| 24713 | return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{ | |
| 24714 | field_name, tuple_ty.fmt(sema.mod), | |
| 25279 | const mod = sema.mod; | |
| 25280 | assert(!mod.intern_pool.stringEqlSlice(field_name, "len")); | |
| 25281 | if (field_name.toUnsigned(&mod.intern_pool)) |field_index| { | |
| 25282 | if (field_index < tuple_ty.structFieldCount(mod)) return field_index; | |
| 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 '{}'", .{ | |
| 24719 | field_name, tuple_ty.fmt(sema.mod), | |
| 25288 | return sema.fail(block, field_name_src, "no field named '{}' in tuple '{}'", .{ | |
| 25289 | field_name.fmt(&mod.intern_pool), tuple_ty.fmt(mod), | |
| 24720 | 25290 | }); |
| 24721 | 25291 | } |
| 24722 | 25292 | |
| ... | ... | @@ -24728,22 +25298,29 @@ fn tupleFieldValByIndex( |
| 24728 | 25298 | field_index: u32, |
| 24729 | 25299 | tuple_ty: Type, |
| 24730 | 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 | 25305 | return sema.addConstant(field_ty, default_value); |
| 24735 | 25306 | } |
| 24736 | 25307 | |
| 24737 | 25308 | if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| { |
| 24738 | if (tuple_val.isUndef()) return sema.addConstUndef(field_ty); | |
| 24739 | 25309 | if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| { |
| 24740 | 25310 | return sema.addConstant(field_ty, opv); |
| 24741 | 25311 | } |
| 24742 | const field_values = tuple_val.castTag(.aggregate).?.data; | |
| 24743 | return sema.addConstant(field_ty, field_values[field_index]); | |
| 25312 | return switch (mod.intern_pool.indexToKey(tuple_val.toIntern())) { | |
| 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 | 25324 | return sema.addConstant(field_ty, default_val); |
| 24748 | 25325 | } |
| 24749 | 25326 | |
| ... | ... | @@ -24756,33 +25333,38 @@ fn unionFieldPtr( |
| 24756 | 25333 | block: *Block, |
| 24757 | 25334 | src: LazySrcLoc, |
| 24758 | 25335 | union_ptr: Air.Inst.Ref, |
| 24759 | field_name: []const u8, | |
| 25336 | field_name: InternPool.NullTerminatedString, | |
| 24760 | 25337 | field_name_src: LazySrcLoc, |
| 24761 | 25338 | unresolved_union_ty: Type, |
| 24762 | 25339 | initializing: bool, |
| 24763 | 25340 | ) CompileError!Air.Inst.Ref { |
| 24764 | 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 | 25347 | const union_ptr_ty = sema.typeOf(union_ptr); |
| 24768 | 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 | 25350 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 24771 | 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 | 25353 | .pointee_type = field.ty, |
| 24774 | .mutable = union_ptr_ty.ptrIsMutable(), | |
| 24775 | .@"volatile" = union_ptr_ty.isVolatilePtr(), | |
| 24776 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), | |
| 25354 | .mutable = union_ptr_ty.ptrIsMutable(mod), | |
| 25355 | .@"volatile" = union_ptr_ty.isVolatilePtr(mod), | |
| 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 | 25361 | const msg = msg: { |
| 24782 | 25362 | const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); |
| 24783 | 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 | 25368 | try sema.addDeclaredHereNote(msg, union_ty); |
| 24787 | 25369 | break :msg msg; |
| 24788 | 25370 | }; |
| ... | ... | @@ -24794,21 +25376,20 @@ fn unionFieldPtr( |
| 24794 | 25376 | .Auto => if (!initializing) { |
| 24795 | 25377 | const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse |
| 24796 | 25378 | break :ct; |
| 24797 | if (union_val.isUndef()) { | |
| 25379 | if (union_val.isUndef(mod)) { | |
| 24798 | 25380 | return sema.failWithUseOfUndef(block, src); |
| 24799 | 25381 | } |
| 24800 | const tag_and_val = union_val.castTag(.@"union").?.data; | |
| 24801 | var field_tag_buf: Value.Payload.U32 = .{ | |
| 24802 | .base = .{ .tag = .enum_field_index }, | |
| 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); | |
| 25382 | const un = ip.indexToKey(union_val.toIntern()).un; | |
| 25383 | const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); | |
| 25384 | const tag_matches = un.tag == field_tag.toIntern(); | |
| 24807 | 25385 | if (!tag_matches) { |
| 24808 | 25386 | const msg = msg: { |
| 24809 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; | |
| 24810 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index); | |
| 24811 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); | |
| 25387 | const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?; | |
| 25388 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod); | |
| 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 | 25393 | errdefer msg.destroy(sema.gpa); |
| 24813 | 25394 | try sema.addDeclaredHereNote(msg, union_ty); |
| 24814 | 25395 | break :msg msg; |
| ... | ... | @@ -24818,28 +25399,27 @@ fn unionFieldPtr( |
| 24818 | 25399 | }, |
| 24819 | 25400 | .Packed, .Extern => {}, |
| 24820 | 25401 | } |
| 24821 | return sema.addConstant( | |
| 24822 | ptr_field_ty, | |
| 24823 | try Value.Tag.field_ptr.create(arena, .{ | |
| 24824 | .container_ptr = union_ptr_val, | |
| 24825 | .container_ty = union_ty, | |
| 24826 | .field_index = field_index, | |
| 24827 | }), | |
| 24828 | ); | |
| 25402 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 25403 | .ty = ptr_field_ty.toIntern(), | |
| 25404 | .addr = .{ .field = .{ | |
| 25405 | .base = union_ptr_val.toIntern(), | |
| 25406 | .index = field_index, | |
| 25407 | } }, | |
| 25408 | } })).toValue()); | |
| 24829 | 25409 | } |
| 24830 | 25410 | |
| 24831 | 25411 | try sema.requireRuntimeBlock(block, src, null); |
| 24832 | 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 | 25416 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 24837 | 25417 | // TODO would it be better if get_union_tag supported pointers to unions? |
| 24838 | 25418 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); |
| 24839 | 25419 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val); |
| 24840 | 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 | 25423 | _ = try block.addNoOp(.unreach); |
| 24844 | 25424 | return Air.Inst.Ref.unreachable_value; |
| 24845 | 25425 | } |
| ... | ... | @@ -24851,37 +25431,37 @@ fn unionFieldVal( |
| 24851 | 25431 | block: *Block, |
| 24852 | 25432 | src: LazySrcLoc, |
| 24853 | 25433 | union_byval: Air.Inst.Ref, |
| 24854 | field_name: []const u8, | |
| 25434 | field_name: InternPool.NullTerminatedString, | |
| 24855 | 25435 | field_name_src: LazySrcLoc, |
| 24856 | 25436 | unresolved_union_ty: Type, |
| 24857 | 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 | 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 | 25444 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 24863 | 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 | 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; | |
| 24870 | var field_tag_buf: Value.Payload.U32 = .{ | |
| 24871 | .base = .{ .tag = .enum_field_index }, | |
| 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); | |
| 25451 | const un = ip.indexToKey(union_val.toIntern()).un; | |
| 25452 | const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); | |
| 25453 | const tag_matches = un.tag == field_tag.toIntern(); | |
| 24876 | 25454 | switch (union_obj.layout) { |
| 24877 | 25455 | .Auto => { |
| 24878 | 25456 | if (tag_matches) { |
| 24879 | return sema.addConstant(field.ty, tag_and_val.val); | |
| 25457 | return sema.addConstant(field.ty, un.val.toValue()); | |
| 24880 | 25458 | } else { |
| 24881 | 25459 | const msg = msg: { |
| 24882 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; | |
| 24883 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index); | |
| 24884 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); | |
| 25460 | const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?; | |
| 25461 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod); | |
| 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 | 25465 | errdefer msg.destroy(sema.gpa); |
| 24886 | 25466 | try sema.addDeclaredHereNote(msg, union_ty); |
| 24887 | 25467 | break :msg msg; |
| ... | ... | @@ -24891,10 +25471,10 @@ fn unionFieldVal( |
| 24891 | 25471 | }, |
| 24892 | 25472 | .Packed, .Extern => { |
| 24893 | 25473 | if (tag_matches) { |
| 24894 | return sema.addConstant(field.ty, tag_and_val.val); | |
| 25474 | return sema.addConstant(field.ty, un.val.toValue()); | |
| 24895 | 25475 | } else { |
| 24896 | const old_ty = union_ty.unionFieldType(tag_and_val.tag, sema.mod); | |
| 24897 | if (try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0)) |new_val| { | |
| 25476 | const old_ty = union_ty.unionFieldType(un.tag.toValue(), mod); | |
| 25477 | if (try sema.bitCastVal(block, src, un.val.toValue(), old_ty, field.ty, 0)) |new_val| { | |
| 24898 | 25478 | return sema.addConstant(field.ty, new_val); |
| 24899 | 25479 | } |
| 24900 | 25480 | } |
| ... | ... | @@ -24904,14 +25484,14 @@ fn unionFieldVal( |
| 24904 | 25484 | |
| 24905 | 25485 | try sema.requireRuntimeBlock(block, src, null); |
| 24906 | 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 | 25490 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 24911 | 25491 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); |
| 24912 | 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 | 25495 | _ = try block.addNoOp(.unreach); |
| 24916 | 25496 | return Air.Inst.Ref.unreachable_value; |
| 24917 | 25497 | } |
| ... | ... | @@ -24928,22 +25508,22 @@ fn elemPtr( |
| 24928 | 25508 | init: bool, |
| 24929 | 25509 | oob_safety: bool, |
| 24930 | 25510 | ) CompileError!Air.Inst.Ref { |
| 25511 | const mod = sema.mod; | |
| 24931 | 25512 | const indexable_ptr_src = src; // TODO better source location |
| 24932 | 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()) { | |
| 24936 | .Pointer => indexable_ptr_ty.elemType(), | |
| 24937 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}), | |
| 25515 | const indexable_ty = switch (indexable_ptr_ty.zigTypeTag(mod)) { | |
| 25516 | .Pointer => indexable_ptr_ty.childType(mod), | |
| 25517 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(mod)}), | |
| 24938 | 25518 | }; |
| 24939 | 25519 | try checkIndexable(sema, block, src, indexable_ty); |
| 24940 | 25520 | |
| 24941 | switch (indexable_ty.zigTypeTag()) { | |
| 25521 | switch (indexable_ty.zigTypeTag(mod)) { | |
| 24942 | 25522 | .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), |
| 24943 | 25523 | .Struct => { |
| 24944 | 25524 | // Tuple field access. |
| 24945 | 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 | 25527 | return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); |
| 24948 | 25528 | }, |
| 24949 | 25529 | else => { |
| ... | ... | @@ -24966,11 +25546,11 @@ fn elemPtrOneLayerOnly( |
| 24966 | 25546 | ) CompileError!Air.Inst.Ref { |
| 24967 | 25547 | const indexable_src = src; // TODO better source location |
| 24968 | 25548 | const indexable_ty = sema.typeOf(indexable); |
| 24969 | const target = sema.mod.getTarget(); | |
| 25549 | const mod = sema.mod; | |
| 24970 | 25550 | |
| 24971 | 25551 | try checkIndexable(sema, block, src, indexable_ty); |
| 24972 | 25552 | |
| 24973 | switch (indexable_ty.ptrSize()) { | |
| 25553 | switch (indexable_ty.ptrSize(mod)) { | |
| 24974 | 25554 | .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), |
| 24975 | 25555 | .Many, .C => { |
| 24976 | 25556 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); |
| ... | ... | @@ -24978,9 +25558,9 @@ fn elemPtrOneLayerOnly( |
| 24978 | 25558 | const runtime_src = rs: { |
| 24979 | 25559 | const ptr_val = maybe_ptr_val orelse break :rs indexable_src; |
| 24980 | 25560 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 24981 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | |
| 24982 | const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); | |
| 25561 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); | |
| 24983 | 25562 | const result_ty = try sema.elemPtrType(indexable_ty, index); |
| 25563 | const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod); | |
| 24984 | 25564 | return sema.addConstant(result_ty, elem_ptr); |
| 24985 | 25565 | }; |
| 24986 | 25566 | const result_ty = try sema.elemPtrType(indexable_ty, null); |
| ... | ... | @@ -24989,7 +25569,7 @@ fn elemPtrOneLayerOnly( |
| 24989 | 25569 | return block.addPtrElemPtr(indexable, elem_index, result_ty); |
| 24990 | 25570 | }, |
| 24991 | 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 | 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 | 25586 | ) CompileError!Air.Inst.Ref { |
| 25007 | 25587 | const indexable_src = src; // TODO better source location |
| 25008 | 25588 | const indexable_ty = sema.typeOf(indexable); |
| 25009 | const target = sema.mod.getTarget(); | |
| 25589 | const mod = sema.mod; | |
| 25010 | 25590 | |
| 25011 | 25591 | try checkIndexable(sema, block, src, indexable_ty); |
| 25012 | 25592 | |
| ... | ... | @@ -25014,8 +25594,8 @@ fn elemVal( |
| 25014 | 25594 | // index is a scalar or vector instead of unconditionally casting to usize. |
| 25015 | 25595 | const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src); |
| 25016 | 25596 | |
| 25017 | switch (indexable_ty.zigTypeTag()) { | |
| 25018 | .Pointer => switch (indexable_ty.ptrSize()) { | |
| 25597 | switch (indexable_ty.zigTypeTag(mod)) { | |
| 25598 | .Pointer => switch (indexable_ty.ptrSize(mod)) { | |
| 25019 | 25599 | .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), |
| 25020 | 25600 | .Many, .C => { |
| 25021 | 25601 | const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); |
| ... | ... | @@ -25024,10 +25604,14 @@ fn elemVal( |
| 25024 | 25604 | const runtime_src = rs: { |
| 25025 | 25605 | const indexable_val = maybe_indexable_val orelse break :rs indexable_src; |
| 25026 | 25606 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 25027 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | |
| 25028 | const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); | |
| 25029 | if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| { | |
| 25030 | return sema.addConstant(indexable_ty.elemType2(), elem_val); | |
| 25607 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); | |
| 25608 | const elem_ty = indexable_ty.elemType2(mod); | |
| 25609 | const many_ptr_ty = try mod.manyConstPtrType(elem_ty); | |
| 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 | 25616 | break :rs indexable_src; |
| 25033 | 25617 | }; |
| ... | ... | @@ -25036,7 +25620,19 @@ fn elemVal( |
| 25036 | 25620 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); |
| 25037 | 25621 | }, |
| 25038 | 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 | 25636 | const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety); |
| 25041 | 25637 | return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); |
| 25042 | 25638 | }, |
| ... | ... | @@ -25049,7 +25645,7 @@ fn elemVal( |
| 25049 | 25645 | .Struct => { |
| 25050 | 25646 | // Tuple field access. |
| 25051 | 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 | 25649 | return sema.tupleField(block, indexable_src, indexable, elem_index_src, index); |
| 25054 | 25650 | }, |
| 25055 | 25651 | else => unreachable, |
| ... | ... | @@ -25064,6 +25660,7 @@ fn validateRuntimeElemAccess( |
| 25064 | 25660 | parent_ty: Type, |
| 25065 | 25661 | parent_src: LazySrcLoc, |
| 25066 | 25662 | ) CompileError!void { |
| 25663 | const mod = sema.mod; | |
| 25067 | 25664 | const valid_rt = try sema.validateRunTimeType(elem_ty, false); |
| 25068 | 25665 | if (!valid_rt) { |
| 25069 | 25666 | const msg = msg: { |
| ... | ... | @@ -25071,12 +25668,12 @@ fn validateRuntimeElemAccess( |
| 25071 | 25668 | block, |
| 25072 | 25669 | elem_index_src, |
| 25073 | 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 | 25673 | errdefer msg.destroy(sema.gpa); |
| 25077 | 25674 | |
| 25078 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 25079 | try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl), parent_ty); | |
| 25675 | const src_decl = mod.declPtr(block.src_decl); | |
| 25676 | try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl, mod), parent_ty); | |
| 25080 | 25677 | |
| 25081 | 25678 | break :msg msg; |
| 25082 | 25679 | }; |
| ... | ... | @@ -25093,10 +25690,11 @@ fn tupleFieldPtr( |
| 25093 | 25690 | field_index: u32, |
| 25094 | 25691 | init: bool, |
| 25095 | 25692 | ) CompileError!Air.Inst.Ref { |
| 25693 | const mod = sema.mod; | |
| 25096 | 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 | 25696 | _ = try sema.resolveTypeFields(tuple_ty); |
| 25099 | const field_count = tuple_ty.structFieldCount(); | |
| 25697 | const field_count = tuple_ty.structFieldCount(mod); | |
| 25100 | 25698 | |
| 25101 | 25699 | if (field_count == 0) { |
| 25102 | 25700 | return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{}); |
| ... | ... | @@ -25108,31 +25706,29 @@ fn tupleFieldPtr( |
| 25108 | 25706 | }); |
| 25109 | 25707 | } |
| 25110 | 25708 | |
| 25111 | const field_ty = tuple_ty.structFieldType(field_index); | |
| 25112 | const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 25709 | const field_ty = tuple_ty.structFieldType(field_index, mod); | |
| 25710 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ | |
| 25113 | 25711 | .pointee_type = field_ty, |
| 25114 | .mutable = tuple_ptr_ty.ptrIsMutable(), | |
| 25115 | .@"volatile" = tuple_ptr_ty.isVolatilePtr(), | |
| 25116 | .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(), | |
| 25712 | .mutable = tuple_ptr_ty.ptrIsMutable(mod), | |
| 25713 | .@"volatile" = tuple_ptr_ty.isVolatilePtr(mod), | |
| 25714 | .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(mod), | |
| 25117 | 25715 | }); |
| 25118 | 25716 | |
| 25119 | if (tuple_ty.structFieldValueComptime(field_index)) |default_val| { | |
| 25120 | const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ | |
| 25121 | .field_ty = field_ty, | |
| 25122 | .field_val = default_val, | |
| 25123 | }); | |
| 25124 | return sema.addConstant(ptr_field_ty, val); | |
| 25717 | if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| { | |
| 25718 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 25719 | .ty = ptr_field_ty.toIntern(), | |
| 25720 | .addr = .{ .comptime_field = default_val.toIntern() }, | |
| 25721 | } })).toValue()); | |
| 25125 | 25722 | } |
| 25126 | 25723 | |
| 25127 | 25724 | if (try sema.resolveMaybeUndefVal(tuple_ptr)) |tuple_ptr_val| { |
| 25128 | return sema.addConstant( | |
| 25129 | ptr_field_ty, | |
| 25130 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 25131 | .container_ptr = tuple_ptr_val, | |
| 25132 | .container_ty = tuple_ty, | |
| 25133 | .field_index = field_index, | |
| 25134 | }), | |
| 25135 | ); | |
| 25725 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 25726 | .ty = ptr_field_ty.toIntern(), | |
| 25727 | .addr = .{ .field = .{ | |
| 25728 | .base = tuple_ptr_val.toIntern(), | |
| 25729 | .index = field_index, | |
| 25730 | } }, | |
| 25731 | } })).toValue()); | |
| 25136 | 25732 | } |
| 25137 | 25733 | |
| 25138 | 25734 | if (!init) { |
| ... | ... | @@ -25151,8 +25747,9 @@ fn tupleField( |
| 25151 | 25747 | field_index_src: LazySrcLoc, |
| 25152 | 25748 | field_index: u32, |
| 25153 | 25749 | ) CompileError!Air.Inst.Ref { |
| 25750 | const mod = sema.mod; | |
| 25154 | 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 | 25754 | if (field_count == 0) { |
| 25158 | 25755 | return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{}); |
| ... | ... | @@ -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 | 25767 | return sema.addConstant(field_ty, default_value); // comptime field |
| 25171 | 25768 | } |
| 25172 | 25769 | |
| 25173 | 25770 | if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| { |
| 25174 | if (tuple_val.isUndef()) return sema.addConstUndef(field_ty); | |
| 25175 | return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index)); | |
| 25771 | if (tuple_val.isUndef(mod)) return sema.addConstUndef(field_ty); | |
| 25772 | return sema.addConstant(field_ty, try tuple_val.fieldValue(mod, field_index)); | |
| 25176 | 25773 | } |
| 25177 | 25774 | |
| 25178 | 25775 | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); |
| ... | ... | @@ -25191,11 +25788,12 @@ fn elemValArray( |
| 25191 | 25788 | elem_index: Air.Inst.Ref, |
| 25192 | 25789 | oob_safety: bool, |
| 25193 | 25790 | ) CompileError!Air.Inst.Ref { |
| 25791 | const mod = sema.mod; | |
| 25194 | 25792 | const array_ty = sema.typeOf(array); |
| 25195 | const array_sent = array_ty.sentinel(); | |
| 25196 | const array_len = array_ty.arrayLen(); | |
| 25793 | const array_sent = array_ty.sentinel(mod); | |
| 25794 | const array_len = array_ty.arrayLen(mod); | |
| 25197 | 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 | 25798 | if (array_len_s == 0) { |
| 25201 | 25799 | return sema.fail(block, array_src, "indexing into empty array is not allowed", .{}); |
| ... | ... | @@ -25204,10 +25802,9 @@ fn elemValArray( |
| 25204 | 25802 | const maybe_undef_array_val = try sema.resolveMaybeUndefVal(array); |
| 25205 | 25803 | // index must be defined since it can access out of bounds |
| 25206 | 25804 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 25207 | const target = sema.mod.getTarget(); | |
| 25208 | 25805 | |
| 25209 | 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 | 25808 | if (array_sent) |s| { |
| 25212 | 25809 | if (index == array_len) { |
| 25213 | 25810 | return sema.addConstant(elem_ty, s); |
| ... | ... | @@ -25219,12 +25816,12 @@ fn elemValArray( |
| 25219 | 25816 | } |
| 25220 | 25817 | } |
| 25221 | 25818 | if (maybe_undef_array_val) |array_val| { |
| 25222 | if (array_val.isUndef()) { | |
| 25819 | if (array_val.isUndef(mod)) { | |
| 25223 | 25820 | return sema.addConstUndef(elem_ty); |
| 25224 | 25821 | } |
| 25225 | 25822 | if (maybe_index_val) |index_val| { |
| 25226 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | |
| 25227 | const elem_val = try array_val.elemValue(sema.mod, sema.arena, index); | |
| 25823 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); | |
| 25824 | const elem_val = try array_val.elemValue(mod, index); | |
| 25228 | 25825 | return sema.addConstant(elem_ty, elem_val); |
| 25229 | 25826 | } |
| 25230 | 25827 | } |
| ... | ... | @@ -25255,11 +25852,11 @@ fn elemPtrArray( |
| 25255 | 25852 | init: bool, |
| 25256 | 25853 | oob_safety: bool, |
| 25257 | 25854 | ) CompileError!Air.Inst.Ref { |
| 25258 | const target = sema.mod.getTarget(); | |
| 25855 | const mod = sema.mod; | |
| 25259 | 25856 | const array_ptr_ty = sema.typeOf(array_ptr); |
| 25260 | const array_ty = array_ptr_ty.childType(); | |
| 25261 | const array_sent = array_ty.sentinel() != null; | |
| 25262 | const array_len = array_ty.arrayLen(); | |
| 25857 | const array_ty = array_ptr_ty.childType(mod); | |
| 25858 | const array_sent = array_ty.sentinel(mod) != null; | |
| 25859 | const array_len = array_ty.arrayLen(mod); | |
| 25263 | 25860 | const array_len_s = array_len + @boolToInt(array_sent); |
| 25264 | 25861 | |
| 25265 | 25862 | if (array_len_s == 0) { |
| ... | ... | @@ -25269,7 +25866,7 @@ fn elemPtrArray( |
| 25269 | 25866 | const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(array_ptr); |
| 25270 | 25867 | // The index must not be undefined since it can be out of bounds. |
| 25271 | 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 | 25870 | if (index >= array_len_s) { |
| 25274 | 25871 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; |
| 25275 | 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 | 25877 | const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset); |
| 25281 | 25878 | |
| 25282 | 25879 | if (maybe_undef_array_ptr_val) |array_ptr_val| { |
| 25283 | if (array_ptr_val.isUndef()) { | |
| 25880 | if (array_ptr_val.isUndef(mod)) { | |
| 25284 | 25881 | return sema.addConstUndef(elem_ptr_ty); |
| 25285 | 25882 | } |
| 25286 | 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 | 25885 | return sema.addConstant(elem_ptr_ty, elem_ptr); |
| 25289 | 25886 | } |
| 25290 | 25887 | } |
| 25291 | 25888 | |
| 25292 | 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 | 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 | 25913 | elem_index: Air.Inst.Ref, |
| 25317 | 25914 | oob_safety: bool, |
| 25318 | 25915 | ) CompileError!Air.Inst.Ref { |
| 25916 | const mod = sema.mod; | |
| 25319 | 25917 | const slice_ty = sema.typeOf(slice); |
| 25320 | const slice_sent = slice_ty.sentinel() != null; | |
| 25321 | const elem_ty = slice_ty.elemType2(); | |
| 25918 | const slice_sent = slice_ty.sentinel(mod) != null; | |
| 25919 | const elem_ty = slice_ty.elemType2(mod); | |
| 25322 | 25920 | var runtime_src = slice_src; |
| 25323 | 25921 | |
| 25324 | 25922 | // slice must be defined since it can dereferenced as null |
| 25325 | 25923 | const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice); |
| 25326 | 25924 | // index must be defined since it can index out of bounds |
| 25327 | 25925 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 25328 | const target = sema.mod.getTarget(); | |
| 25329 | 25926 | |
| 25330 | 25927 | if (maybe_slice_val) |slice_val| { |
| 25331 | 25928 | runtime_src = elem_index_src; |
| 25332 | const slice_len = slice_val.sliceLen(sema.mod); | |
| 25929 | const slice_len = slice_val.sliceLen(mod); | |
| 25333 | 25930 | const slice_len_s = slice_len + @boolToInt(slice_sent); |
| 25334 | 25931 | if (slice_len_s == 0) { |
| 25335 | 25932 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| 25336 | 25933 | } |
| 25337 | 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 | 25936 | if (index >= slice_len_s) { |
| 25340 | 25937 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 25341 | 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); | |
| 25344 | if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| { | |
| 25940 | const elem_ptr_ty = try sema.elemPtrType(slice_ty, index); | |
| 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 | 25943 | return sema.addConstant(elem_ty, elem_val); |
| 25346 | 25944 | } |
| 25347 | 25945 | runtime_src = slice_src; |
| ... | ... | @@ -25353,7 +25951,7 @@ fn elemValSlice( |
| 25353 | 25951 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 25354 | 25952 | if (oob_safety and block.wantSafety()) { |
| 25355 | 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 | 25955 | else |
| 25358 | 25956 | try block.addTyOp(.slice_len, Type.usize, slice); |
| 25359 | 25957 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | ... | @@ -25373,24 +25971,24 @@ fn elemPtrSlice( |
| 25373 | 25971 | elem_index: Air.Inst.Ref, |
| 25374 | 25972 | oob_safety: bool, |
| 25375 | 25973 | ) CompileError!Air.Inst.Ref { |
| 25376 | const target = sema.mod.getTarget(); | |
| 25974 | const mod = sema.mod; | |
| 25377 | 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 | 25978 | const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(slice); |
| 25381 | 25979 | // The index must not be undefined since it can be out of bounds. |
| 25382 | 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 | 25982 | break :o index; |
| 25385 | 25983 | } else null; |
| 25386 | 25984 | |
| 25387 | 25985 | const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset); |
| 25388 | 25986 | |
| 25389 | 25987 | if (maybe_undef_slice_val) |slice_val| { |
| 25390 | if (slice_val.isUndef()) { | |
| 25988 | if (slice_val.isUndef(mod)) { | |
| 25391 | 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 | 25992 | const slice_len_s = slice_len + @boolToInt(slice_sent); |
| 25395 | 25993 | if (slice_len_s == 0) { |
| 25396 | 25994 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| ... | ... | @@ -25400,7 +25998,7 @@ fn elemPtrSlice( |
| 25400 | 25998 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 25401 | 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 | 26002 | return sema.addConstant(elem_ptr_ty, elem_ptr_val); |
| 25405 | 26003 | } |
| 25406 | 26004 | } |
| ... | ... | @@ -25412,8 +26010,8 @@ fn elemPtrSlice( |
| 25412 | 26010 | if (oob_safety and block.wantSafety()) { |
| 25413 | 26011 | const len_inst = len: { |
| 25414 | 26012 | if (maybe_undef_slice_val) |slice_val| |
| 25415 | if (!slice_val.isUndef()) | |
| 25416 | break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)); | |
| 26013 | if (!slice_val.isUndef(mod)) | |
| 26014 | break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod)); | |
| 25417 | 26015 | break :len try block.addTyOp(.slice_len, Type.usize, slice); |
| 25418 | 26016 | }; |
| 25419 | 26017 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | ... | @@ -25455,16 +26053,17 @@ const CoerceOpts = struct { |
| 25455 | 26053 | |
| 25456 | 26054 | fn get(info: @This(), sema: *Sema) !?Module.SrcLoc { |
| 25457 | 26055 | if (info.func_inst == .none) return null; |
| 26056 | const mod = sema.mod; | |
| 25458 | 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 | 26059 | if (param_src == .node_offset_param) { |
| 25461 | 26060 | return Module.SrcLoc{ |
| 25462 | .file_scope = fn_decl.getFileScope(), | |
| 26061 | .file_scope = fn_decl.getFileScope(mod), | |
| 25463 | 26062 | .parent_decl_node = fn_decl.src_node, |
| 25464 | 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 | 26076 | inst_src: LazySrcLoc, |
| 25478 | 26077 | opts: CoerceOpts, |
| 25479 | 26078 | ) CoersionError!Air.Inst.Ref { |
| 25480 | switch (dest_ty_unresolved.tag()) { | |
| 25481 | .generic_poison => return inst, | |
| 25482 | else => {}, | |
| 25483 | } | |
| 26079 | if (dest_ty_unresolved.isGenericPoison()) return inst; | |
| 26080 | const mod = sema.mod; | |
| 25484 | 26081 | const dest_ty_src = inst_src; // TODO better source location |
| 25485 | 26082 | const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); |
| 25486 | 26083 | const inst_ty = try sema.resolveTypeFields(sema.typeOf(inst)); |
| 25487 | const target = sema.mod.getTarget(); | |
| 26084 | const target = mod.getTarget(); | |
| 25488 | 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 | 26087 | return inst; |
| 25491 | 26088 | |
| 25492 | const arena = sema.arena; | |
| 25493 | 26089 | const maybe_inst_val = try sema.resolveMaybeUndefVal(inst); |
| 25494 | 26090 | |
| 25495 | 26091 | var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); |
| 25496 | 26092 | if (in_memory_result == .ok) { |
| 25497 | 26093 | if (maybe_inst_val) |val| { |
| 25498 | // Keep the comptime Value representation; take the new type. | |
| 25499 | return sema.addConstant(dest_ty, val); | |
| 26094 | return sema.coerceInMemory(block, val, inst_ty, dest_ty, dest_ty_src); | |
| 25500 | 26095 | } |
| 25501 | 26096 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 25502 | 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 | 26103 | .Optional => optional: { |
| 25509 | 26104 | // undefined sets the optional bit also to undefined. |
| 25510 | 26105 | if (is_undef) { |
| ... | ... | @@ -25512,18 +26107,22 @@ fn coerceExtra( |
| 25512 | 26107 | } |
| 25513 | 26108 | |
| 25514 | 26109 | // null to ?T |
| 25515 | if (inst_ty.zigTypeTag() == .Null) { | |
| 25516 | return sema.addConstant(dest_ty, Value.null); | |
| 26110 | if (inst_ty.zigTypeTag(mod) == .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 | 26117 | // cast from ?*T and ?[*]T to ?*anyopaque |
| 25520 | 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 | |
| 25522 | inst_ty.isPtrAtRuntime()) | |
| 26119 | if (dest_ty.isPtrLikeOptional(mod) and | |
| 26120 | dest_ty.elemType2(mod).toIntern() == .anyopaque_type and | |
| 26121 | inst_ty.isPtrAtRuntime(mod)) | |
| 25523 | 26122 | anyopaque_check: { |
| 25524 | 26123 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional; |
| 25525 | const elem_ty = inst_ty.elemType2(); | |
| 25526 | if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) { | |
| 26124 | const elem_ty = inst_ty.elemType2(mod); | |
| 26125 | if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) { | |
| 25527 | 26126 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ |
| 25528 | 26127 | .actual = inst_ty, |
| 25529 | 26128 | .wanted = dest_ty, |
| ... | ... | @@ -25532,12 +26131,12 @@ fn coerceExtra( |
| 25532 | 26131 | } |
| 25533 | 26132 | // Let the logic below handle wrapping the optional now that |
| 25534 | 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 | 26135 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 25537 | 26136 | } |
| 25538 | 26137 | |
| 25539 | 26138 | // T to ?T |
| 25540 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); | |
| 26139 | const child_type = dest_ty.optionalChild(mod); | |
| 25541 | 26140 | const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { |
| 25542 | 26141 | error.NotCoercible => { |
| 25543 | 26142 | if (in_memory_result == .no_match) { |
| ... | ... | @@ -25551,12 +26150,12 @@ fn coerceExtra( |
| 25551 | 26150 | return try sema.wrapOptional(block, dest_ty, intermediate, inst_src); |
| 25552 | 26151 | }, |
| 25553 | 26152 | .Pointer => pointer: { |
| 25554 | const dest_info = dest_ty.ptrInfo().data; | |
| 26153 | const dest_info = dest_ty.ptrInfo(mod); | |
| 25555 | 26154 | |
| 25556 | 26155 | // Function body to function pointer. |
| 25557 | if (inst_ty.zigTypeTag() == .Fn) { | |
| 26156 | if (inst_ty.zigTypeTag(mod) == .Fn) { | |
| 25558 | 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 | 26159 | const inst_as_ptr = try sema.analyzeDeclRef(fn_decl); |
| 25561 | 26160 | return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); |
| 25562 | 26161 | } |
| ... | ... | @@ -25564,13 +26163,13 @@ fn coerceExtra( |
| 25564 | 26163 | // *T to *[1]T |
| 25565 | 26164 | single_item: { |
| 25566 | 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 | 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 | 26169 | const array_ty = dest_info.pointee_type; |
| 25571 | if (array_ty.zigTypeTag() != .Array) break :single_item; | |
| 25572 | const array_elem_ty = array_ty.childType(); | |
| 25573 | if (array_ty.arrayLen() != 1) break :single_item; | |
| 26170 | if (array_ty.zigTypeTag(mod) != .Array) break :single_item; | |
| 26171 | const array_elem_ty = array_ty.childType(mod); | |
| 26172 | if (array_ty.arrayLen(mod) != 1) break :single_item; | |
| 25574 | 26173 | const dest_is_mut = dest_info.mutable; |
| 25575 | 26174 | switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 25576 | 26175 | .ok => {}, |
| ... | ... | @@ -25581,11 +26180,11 @@ fn coerceExtra( |
| 25581 | 26180 | |
| 25582 | 26181 | // Coercions where the source is a single pointer to an array. |
| 25583 | 26182 | src_array_ptr: { |
| 25584 | if (!inst_ty.isSinglePointer()) break :src_array_ptr; | |
| 26183 | if (!inst_ty.isSinglePointer(mod)) break :src_array_ptr; | |
| 25585 | 26184 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; |
| 25586 | const array_ty = inst_ty.childType(); | |
| 25587 | if (array_ty.zigTypeTag() != .Array) break :src_array_ptr; | |
| 25588 | const array_elem_type = array_ty.childType(); | |
| 26185 | const array_ty = inst_ty.childType(mod); | |
| 26186 | if (array_ty.zigTypeTag(mod) != .Array) break :src_array_ptr; | |
| 26187 | const array_elem_type = array_ty.childType(mod); | |
| 25589 | 26188 | const dest_is_mut = dest_info.mutable; |
| 25590 | 26189 | |
| 25591 | 26190 | const dst_elem_type = dest_info.pointee_type; |
| ... | ... | @@ -25603,8 +26202,8 @@ fn coerceExtra( |
| 25603 | 26202 | } |
| 25604 | 26203 | |
| 25605 | 26204 | if (dest_info.sentinel) |dest_sent| { |
| 25606 | if (array_ty.sentinel()) |inst_sent| { | |
| 25607 | if (!dest_sent.eql(inst_sent, dst_elem_type, sema.mod)) { | |
| 26205 | if (array_ty.sentinel(mod)) |inst_sent| { | |
| 26206 | if (!dest_sent.eql(inst_sent, dst_elem_type, mod)) { | |
| 25608 | 26207 | in_memory_result = .{ .ptr_sentinel = .{ |
| 25609 | 26208 | .actual = inst_sent, |
| 25610 | 26209 | .wanted = dest_sent, |
| ... | ... | @@ -25614,7 +26213,7 @@ fn coerceExtra( |
| 25614 | 26213 | } |
| 25615 | 26214 | } else { |
| 25616 | 26215 | in_memory_result = .{ .ptr_sentinel = .{ |
| 25617 | .actual = Value.initTag(.unreachable_value), | |
| 26216 | .actual = Value.@"unreachable", | |
| 25618 | 26217 | .wanted = dest_sent, |
| 25619 | 26218 | .ty = dst_elem_type, |
| 25620 | 26219 | } }; |
| ... | ... | @@ -25640,11 +26239,11 @@ fn coerceExtra( |
| 25640 | 26239 | } |
| 25641 | 26240 | |
| 25642 | 26241 | // coercion from C pointer |
| 25643 | if (inst_ty.isCPtr()) src_c_ptr: { | |
| 26242 | if (inst_ty.isCPtr(mod)) src_c_ptr: { | |
| 25644 | 26243 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr; |
| 25645 | 26244 | // In this case we must add a safety check because the C pointer |
| 25646 | 26245 | // could be null. |
| 25647 | const src_elem_ty = inst_ty.childType(); | |
| 26246 | const src_elem_ty = inst_ty.childType(mod); | |
| 25648 | 26247 | const dest_is_mut = dest_info.mutable; |
| 25649 | 26248 | const dst_elem_type = dest_info.pointee_type; |
| 25650 | 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 | 26255 | |
| 25657 | 26256 | // cast from *T and [*]T to *anyopaque |
| 25658 | 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 | 26259 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; |
| 25661 | const elem_ty = inst_ty.elemType2(); | |
| 25662 | if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) { | |
| 26260 | const elem_ty = inst_ty.elemType2(mod); | |
| 26261 | if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) { | |
| 25663 | 26262 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ |
| 25664 | 26263 | .actual = inst_ty, |
| 25665 | 26264 | .wanted = dest_ty, |
| 25666 | 26265 | } }; |
| 25667 | 26266 | break :pointer; |
| 25668 | 26267 | } |
| 25669 | if (dest_ty.isSlice()) break :to_anyopaque; | |
| 25670 | if (inst_ty.isSlice()) { | |
| 26268 | if (dest_ty.isSlice(mod)) break :to_anyopaque; | |
| 26269 | if (inst_ty.isSlice(mod)) { | |
| 25671 | 26270 | in_memory_result = .{ .slice_to_anyopaque = .{ |
| 25672 | 26271 | .actual = inst_ty, |
| 25673 | 26272 | .wanted = dest_ty, |
| ... | ... | @@ -25679,9 +26278,9 @@ fn coerceExtra( |
| 25679 | 26278 | |
| 25680 | 26279 | switch (dest_info.size) { |
| 25681 | 26280 | // coercion to C pointer |
| 25682 | .C => switch (inst_ty.zigTypeTag()) { | |
| 26281 | .C => switch (inst_ty.zigTypeTag(mod)) { | |
| 25683 | 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 | 26285 | .ComptimeInt => { |
| 25687 | 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 | 26290 | return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); |
| 25692 | 26291 | }, |
| 25693 | 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 | 26294 | .signed => Type.isize, |
| 25696 | 26295 | .unsigned => Type.usize, |
| 25697 | 26296 | }; |
| ... | ... | @@ -25707,7 +26306,7 @@ fn coerceExtra( |
| 25707 | 26306 | }, |
| 25708 | 26307 | .Pointer => p: { |
| 25709 | 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 | 26310 | switch (try sema.coerceInMemoryAllowed( |
| 25712 | 26311 | block, |
| 25713 | 26312 | dest_info.pointee_type, |
| ... | ... | @@ -25723,7 +26322,7 @@ fn coerceExtra( |
| 25723 | 26322 | if (inst_info.size == .Slice) { |
| 25724 | 26323 | assert(dest_info.sentinel == null); |
| 25725 | 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 | 26326 | break :p; |
| 25728 | 26327 | |
| 25729 | 26328 | const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); |
| ... | ... | @@ -25733,11 +26332,11 @@ fn coerceExtra( |
| 25733 | 26332 | }, |
| 25734 | 26333 | else => {}, |
| 25735 | 26334 | }, |
| 25736 | .One => switch (dest_info.pointee_type.zigTypeTag()) { | |
| 26335 | .One => switch (dest_info.pointee_type.zigTypeTag(mod)) { | |
| 25737 | 26336 | .Union => { |
| 25738 | 26337 | // pointer to anonymous struct to pointer to union |
| 25739 | if (inst_ty.isSinglePointer() and | |
| 25740 | inst_ty.childType().isAnonStruct() and | |
| 26338 | if (inst_ty.isSinglePointer(mod) and | |
| 26339 | inst_ty.childType(mod).isAnonStruct(mod) and | |
| 25741 | 26340 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25742 | 26341 | { |
| 25743 | 26342 | return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| ... | ... | @@ -25745,8 +26344,8 @@ fn coerceExtra( |
| 25745 | 26344 | }, |
| 25746 | 26345 | .Struct => { |
| 25747 | 26346 | // pointer to anonymous struct to pointer to struct |
| 25748 | if (inst_ty.isSinglePointer() and | |
| 25749 | inst_ty.childType().isAnonStruct() and | |
| 26347 | if (inst_ty.isSinglePointer(mod) and | |
| 26348 | inst_ty.childType(mod).isAnonStruct(mod) and | |
| 25750 | 26349 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25751 | 26350 | { |
| 25752 | 26351 | return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) { |
| ... | ... | @@ -25757,8 +26356,8 @@ fn coerceExtra( |
| 25757 | 26356 | }, |
| 25758 | 26357 | .Array => { |
| 25759 | 26358 | // pointer to tuple to pointer to array |
| 25760 | if (inst_ty.isSinglePointer() and | |
| 25761 | inst_ty.childType().isTuple() and | |
| 26359 | if (inst_ty.isSinglePointer(mod) and | |
| 26360 | inst_ty.childType(mod).isTuple(mod) and | |
| 25762 | 26361 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25763 | 26362 | { |
| 25764 | 26363 | return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| ... | ... | @@ -25767,38 +26366,38 @@ fn coerceExtra( |
| 25767 | 26366 | else => {}, |
| 25768 | 26367 | }, |
| 25769 | 26368 | .Slice => to_slice: { |
| 25770 | if (inst_ty.zigTypeTag() == .Array) { | |
| 26369 | if (inst_ty.zigTypeTag(mod) == .Array) { | |
| 25771 | 26370 | return sema.fail( |
| 25772 | 26371 | block, |
| 25773 | 26372 | inst_src, |
| 25774 | 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; | |
| 25780 | const inst_child_ty = inst_ty.childType(); | |
| 25781 | if (!inst_child_ty.isTuple()) break :to_slice; | |
| 26378 | if (!inst_ty.isSinglePointer(mod)) break :to_slice; | |
| 26379 | const inst_child_ty = inst_ty.childType(mod); | |
| 26380 | if (!inst_child_ty.isTuple(mod)) break :to_slice; | |
| 25782 | 26381 | |
| 25783 | 26382 | // empty tuple to zero-length slice |
| 25784 | 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 | 26385 | // Optional slice is represented with a null pointer so |
| 25787 | 26386 | // we use a dummy pointer value with the required alignment. |
| 25788 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | |
| 25789 | .ptr = if (dest_info.@"align" != 0) | |
| 25790 | try Value.Tag.int_u64.create(sema.arena, dest_info.@"align") | |
| 26387 | return sema.addConstant(dest_ty, (try mod.intern(.{ .ptr = .{ | |
| 26388 | .ty = dest_ty.toIntern(), | |
| 26389 | .addr = .{ .int = (if (dest_info.@"align" != 0) | |
| 26390 | try mod.intValue(Type.usize, dest_info.@"align") | |
| 25791 | 26391 | else |
| 25792 | try dest_info.pointee_type.lazyAbiAlignment(target, sema.arena), | |
| 25793 | .len = Value.zero, | |
| 25794 | }); | |
| 25795 | return sema.addConstant(dest_ty, slice_val); | |
| 26392 | try mod.getCoerced(try dest_info.pointee_type.lazyAbiAlignment(mod), Type.usize)).toIntern() }, | |
| 26393 | .len = (try mod.intValue(Type.usize, 0)).toIntern(), | |
| 26394 | } })).toValue()); | |
| 25796 | 26395 | } |
| 25797 | 26396 | |
| 25798 | 26397 | // pointer to tuple to slice |
| 25799 | 26398 | if (dest_info.mutable) { |
| 25800 | 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 | 26401 | errdefer err_msg.deinit(sema.gpa); |
| 25803 | 26402 | try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{}); |
| 25804 | 26403 | break :err_msg err_msg; |
| ... | ... | @@ -25808,9 +26407,9 @@ fn coerceExtra( |
| 25808 | 26407 | return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| 25809 | 26408 | }, |
| 25810 | 26409 | .Many => p: { |
| 25811 | if (!inst_ty.isSlice()) break :p; | |
| 26410 | if (!inst_ty.isSlice(mod)) break :p; | |
| 25812 | 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 | 26414 | switch (try sema.coerceInMemoryAllowed( |
| 25816 | 26415 | block, |
| ... | ... | @@ -25826,7 +26425,11 @@ fn coerceExtra( |
| 25826 | 26425 | } |
| 25827 | 26426 | |
| 25828 | 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 | 26433 | break :p; |
| 25831 | 26434 | |
| 25832 | 26435 | const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); |
| ... | ... | @@ -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 | 26441 | .Float, .ComptimeFloat => float: { |
| 25839 | 26442 | if (is_undef) { |
| 25840 | 26443 | return sema.addConstUndef(dest_ty); |
| 25841 | 26444 | } |
| 25842 | 26445 | const val = (try sema.resolveMaybeUndefVal(inst)) orelse { |
| 25843 | if (dest_ty.zigTypeTag() == .ComptimeInt) { | |
| 26446 | if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { | |
| 25844 | 26447 | if (!opts.report_err) return error.NotCoercible; |
| 25845 | 26448 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known"); |
| 25846 | 26449 | } |
| 25847 | 26450 | break :float; |
| 25848 | 26451 | }; |
| 25849 | 26452 | |
| 25850 | if (val.floatHasFraction()) { | |
| 26453 | if (val.floatHasFraction(mod)) { | |
| 25851 | 26454 | return sema.fail( |
| 25852 | 26455 | block, |
| 25853 | 26456 | inst_src, |
| 25854 | 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 | 26461 | const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty); |
| ... | ... | @@ -25866,19 +26469,19 @@ fn coerceExtra( |
| 25866 | 26469 | // comptime-known integer to other number |
| 25867 | 26470 | if (!(try sema.intFitsInType(val, dest_ty, null))) { |
| 25868 | 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 | 26477 | if (!opts.report_err) return error.NotCoercible; |
| 25875 | 26478 | if (opts.no_cast_to_comptime_int) return inst; |
| 25876 | 26479 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known"); |
| 25877 | 26480 | } |
| 25878 | 26481 | |
| 25879 | 26482 | // integer widening |
| 25880 | const dst_info = dest_ty.intInfo(target); | |
| 25881 | const src_info = inst_ty.intInfo(target); | |
| 26483 | const dst_info = dest_ty.intInfo(mod); | |
| 26484 | const src_info = inst_ty.intInfo(mod); | |
| 25882 | 26485 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or |
| 25883 | 26486 | // small enough unsigned ints can get casted to large enough signed ints |
| 25884 | 26487 | (dst_info.signedness == .signed and dst_info.bits > src_info.bits)) |
| ... | ... | @@ -25892,10 +26495,10 @@ fn coerceExtra( |
| 25892 | 26495 | }, |
| 25893 | 26496 | else => {}, |
| 25894 | 26497 | }, |
| 25895 | .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) { | |
| 26498 | .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) { | |
| 25896 | 26499 | .ComptimeFloat => { |
| 25897 | 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 | 26502 | return try sema.addConstant(dest_ty, result_val); |
| 25900 | 26503 | }, |
| 25901 | 26504 | .Float => { |
| ... | ... | @@ -25903,17 +26506,17 @@ fn coerceExtra( |
| 25903 | 26506 | return sema.addConstUndef(dest_ty); |
| 25904 | 26507 | } |
| 25905 | 26508 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 25906 | const result_val = try val.floatCast(sema.arena, dest_ty, target); | |
| 25907 | if (!val.eql(result_val, inst_ty, sema.mod)) { | |
| 26509 | const result_val = try val.floatCast(dest_ty, mod); | |
| 26510 | if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) { | |
| 25908 | 26511 | return sema.fail( |
| 25909 | 26512 | block, |
| 25910 | 26513 | inst_src, |
| 25911 | 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 | 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 | 26520 | if (!opts.report_err) return error.NotCoercible; |
| 25918 | 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 | 26534 | return sema.addConstUndef(dest_ty); |
| 25932 | 26535 | } |
| 25933 | 26536 | const val = (try sema.resolveMaybeUndefVal(inst)) orelse { |
| 25934 | if (dest_ty.zigTypeTag() == .ComptimeFloat) { | |
| 26537 | if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) { | |
| 25935 | 26538 | if (!opts.report_err) return error.NotCoercible; |
| 25936 | 26539 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known"); |
| 25937 | 26540 | } |
| 25938 | 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 | 26544 | // TODO implement this compile error |
| 25942 | 26545 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); |
| 25943 | 26546 | //if (!int_again_val.eql(val, inst_ty, mod)) { |
| ... | ... | @@ -25945,7 +26548,7 @@ fn coerceExtra( |
| 25945 | 26548 | // block, |
| 25946 | 26549 | // inst_src, |
| 25947 | 26550 | // "type '{}' cannot represent integer value '{}'", |
| 25948 | // .{ dest_ty.fmt(sema.mod), val }, | |
| 26551 | // .{ dest_ty.fmt(mod), val }, | |
| 25949 | 26552 | // ); |
| 25950 | 26553 | //} |
| 25951 | 26554 | return try sema.addConstant(dest_ty, result_val); |
| ... | ... | @@ -25955,18 +26558,18 @@ fn coerceExtra( |
| 25955 | 26558 | }, |
| 25956 | 26559 | else => {}, |
| 25957 | 26560 | }, |
| 25958 | .Enum => switch (inst_ty.zigTypeTag()) { | |
| 26561 | .Enum => switch (inst_ty.zigTypeTag(mod)) { | |
| 25959 | 26562 | .EnumLiteral => { |
| 25960 | 26563 | // enum literal to enum |
| 25961 | 26564 | const val = try sema.resolveConstValue(block, .unneeded, inst, ""); |
| 25962 | const bytes = val.castTag(.enum_literal).?.data; | |
| 25963 | const field_index = dest_ty.enumFieldIndex(bytes) orelse { | |
| 26565 | const string = mod.intern_pool.indexToKey(val.toIntern()).enum_literal; | |
| 26566 | const field_index = dest_ty.enumFieldIndex(string, mod) orelse { | |
| 25964 | 26567 | const msg = msg: { |
| 25965 | 26568 | const msg = try sema.errMsg( |
| 25966 | 26569 | block, |
| 25967 | 26570 | inst_src, |
| 25968 | "no field named '{s}' in enum '{}'", | |
| 25969 | .{ bytes, dest_ty.fmt(sema.mod) }, | |
| 26571 | "no field named '{}' in enum '{}'", | |
| 26572 | .{ string.fmt(&mod.intern_pool), dest_ty.fmt(mod) }, | |
| 25970 | 26573 | ); |
| 25971 | 26574 | errdefer msg.destroy(sema.gpa); |
| 25972 | 26575 | try sema.addDeclaredHereNote(msg, dest_ty); |
| ... | ... | @@ -25976,13 +26579,13 @@ fn coerceExtra( |
| 25976 | 26579 | }; |
| 25977 | 26580 | return sema.addConstant( |
| 25978 | 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 | 26585 | .Union => blk: { |
| 25983 | 26586 | // union to its own tag type |
| 25984 | const union_tag_ty = inst_ty.unionTagType() orelse break :blk; | |
| 25985 | if (union_tag_ty.eql(dest_ty, sema.mod)) { | |
| 26587 | const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk; | |
| 26588 | if (union_tag_ty.eql(dest_ty, mod)) { | |
| 25986 | 26589 | return sema.unionToTag(block, dest_ty, inst, inst_src); |
| 25987 | 26590 | } |
| 25988 | 26591 | }, |
| ... | ... | @@ -25991,27 +26594,33 @@ fn coerceExtra( |
| 25991 | 26594 | }, |
| 25992 | 26595 | else => {}, |
| 25993 | 26596 | }, |
| 25994 | .ErrorUnion => switch (inst_ty.zigTypeTag()) { | |
| 26597 | .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) { | |
| 25995 | 26598 | .ErrorUnion => eu: { |
| 25996 | 26599 | if (maybe_inst_val) |inst_val| { |
| 25997 | switch (inst_val.tag()) { | |
| 26600 | switch (inst_val.toIntern()) { | |
| 25998 | 26601 | .undef => return sema.addConstUndef(dest_ty), |
| 25999 | .eu_payload => { | |
| 26000 | const payload = try sema.addConstant( | |
| 26001 | inst_ty.errorUnionPayload(), | |
| 26002 | inst_val.castTag(.eu_payload).?.data, | |
| 26003 | ); | |
| 26004 | return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) { | |
| 26005 | error.NotCoercible => break :eu, | |
| 26006 | else => |e| return e, | |
| 26007 | }; | |
| 26008 | }, | |
| 26009 | else => { | |
| 26010 | const error_set = try sema.addConstant( | |
| 26011 | inst_ty.errorUnionSet(), | |
| 26012 | inst_val, | |
| 26013 | ); | |
| 26014 | return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src); | |
| 26602 | else => switch (mod.intern_pool.indexToKey(inst_val.toIntern())) { | |
| 26603 | .error_union => |error_union| switch (error_union.val) { | |
| 26604 | .err_name => |err_name| { | |
| 26605 | const error_set_ty = inst_ty.errorUnionSet(mod); | |
| 26606 | const error_set_val = try sema.addConstant(error_set_ty, (try mod.intern(.{ .err = .{ | |
| 26607 | .ty = error_set_ty.toIntern(), | |
| 26608 | .name = err_name, | |
| 26609 | } })).toValue()); | |
| 26610 | return sema.wrapErrorUnionSet(block, dest_ty, error_set_val, inst_src); | |
| 26611 | }, | |
| 26612 | .payload => |payload| { | |
| 26613 | const payload_val = try sema.addConstant( | |
| 26614 | inst_ty.errorUnionPayload(mod), | |
| 26615 | payload.toValue(), | |
| 26616 | ); | |
| 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 | 26640 | }; |
| 26032 | 26641 | }, |
| 26033 | 26642 | }, |
| 26034 | .Union => switch (inst_ty.zigTypeTag()) { | |
| 26643 | .Union => switch (inst_ty.zigTypeTag(mod)) { | |
| 26035 | 26644 | .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), |
| 26036 | 26645 | .Struct => { |
| 26037 | if (inst_ty.isAnonStruct()) { | |
| 26646 | if (inst_ty.isAnonStruct(mod)) { | |
| 26038 | 26647 | return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src); |
| 26039 | 26648 | } |
| 26040 | 26649 | }, |
| ... | ... | @@ -26043,13 +26652,13 @@ fn coerceExtra( |
| 26043 | 26652 | }, |
| 26044 | 26653 | else => {}, |
| 26045 | 26654 | }, |
| 26046 | .Array => switch (inst_ty.zigTypeTag()) { | |
| 26655 | .Array => switch (inst_ty.zigTypeTag(mod)) { | |
| 26047 | 26656 | .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), |
| 26048 | 26657 | .Struct => { |
| 26049 | 26658 | if (inst == .empty_struct) { |
| 26050 | 26659 | return sema.arrayInitEmpty(block, inst_src, dest_ty); |
| 26051 | 26660 | } |
| 26052 | if (inst_ty.isTuple()) { | |
| 26661 | if (inst_ty.isTuple(mod)) { | |
| 26053 | 26662 | return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); |
| 26054 | 26663 | } |
| 26055 | 26664 | }, |
| ... | ... | @@ -26058,10 +26667,10 @@ fn coerceExtra( |
| 26058 | 26667 | }, |
| 26059 | 26668 | else => {}, |
| 26060 | 26669 | }, |
| 26061 | .Vector => switch (inst_ty.zigTypeTag()) { | |
| 26670 | .Vector => switch (inst_ty.zigTypeTag(mod)) { | |
| 26062 | 26671 | .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), |
| 26063 | 26672 | .Struct => { |
| 26064 | if (inst_ty.isTuple()) { | |
| 26673 | if (inst_ty.isTuple(mod)) { | |
| 26065 | 26674 | return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); |
| 26066 | 26675 | } |
| 26067 | 26676 | }, |
| ... | ... | @@ -26074,7 +26683,7 @@ fn coerceExtra( |
| 26074 | 26683 | if (inst == .empty_struct) { |
| 26075 | 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 | 26687 | return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) { |
| 26079 | 26688 | error.NotCoercible => break :blk, |
| 26080 | 26689 | else => |e| return e, |
| ... | ... | @@ -26093,35 +26702,34 @@ fn coerceExtra( |
| 26093 | 26702 | |
| 26094 | 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 | 26706 | const msg = msg: { |
| 26098 | 26707 | const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); |
| 26099 | 26708 | errdefer msg.destroy(sema.gpa); |
| 26100 | 26709 | |
| 26101 | 26710 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 26102 | const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); | |
| 26103 | try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "'noreturn' declared here", .{}); | |
| 26711 | const src_decl = mod.declPtr(sema.func.?.owner_decl); | |
| 26712 | try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "'noreturn' declared here", .{}); | |
| 26104 | 26713 | break :msg msg; |
| 26105 | 26714 | }; |
| 26106 | 26715 | return sema.failWithOwnedErrorMsg(msg); |
| 26107 | 26716 | } |
| 26108 | 26717 | |
| 26109 | 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 | 26720 | errdefer msg.destroy(sema.gpa); |
| 26112 | 26721 | |
| 26113 | 26722 | // E!T to T |
| 26114 | if (inst_ty.zigTypeTag() == .ErrorUnion and | |
| 26115 | (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) | |
| 26723 | if (inst_ty.zigTypeTag(mod) == .ErrorUnion and | |
| 26724 | (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) | |
| 26116 | 26725 | { |
| 26117 | 26726 | try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); |
| 26118 | 26727 | try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 26119 | 26728 | } |
| 26120 | 26729 | |
| 26121 | 26730 | // ?T to T |
| 26122 | var buf: Type.Payload.ElemType = undefined; | |
| 26123 | if (inst_ty.zigTypeTag() == .Optional and | |
| 26124 | (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) | |
| 26731 | if (inst_ty.zigTypeTag(mod) == .Optional and | |
| 26732 | (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) | |
| 26125 | 26733 | { |
| 26126 | 26734 | try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); |
| 26127 | 26735 | try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{}); |
| ... | ... | @@ -26130,18 +26738,18 @@ fn coerceExtra( |
| 26130 | 26738 | try in_memory_result.report(sema, block, inst_src, msg); |
| 26131 | 26739 | |
| 26132 | 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 | 26742 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 26135 | const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); | |
| 26136 | if (inst_ty.isError() and !dest_ty.isError()) { | |
| 26137 | try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function cannot return an error", .{}); | |
| 26743 | const src_decl = mod.declPtr(sema.func.?.owner_decl); | |
| 26744 | if (inst_ty.isError(mod) and !dest_ty.isError(mod)) { | |
| 26745 | try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function cannot return an error", .{}); | |
| 26138 | 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 | 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 | 26755 | // TODO maybe add "cannot store an error in type '{}'" note |
| ... | ... | @@ -26151,6 +26759,84 @@ fn coerceExtra( |
| 26151 | 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 | 26840 | const InMemoryCoercionResult = union(enum) { |
| 26155 | 26841 | ok, |
| 26156 | 26842 | no_match: Pair, |
| ... | ... | @@ -26164,7 +26850,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26164 | 26850 | optional_shape: Pair, |
| 26165 | 26851 | optional_child: PairAndChild, |
| 26166 | 26852 | from_anyerror, |
| 26167 | missing_error: []const []const u8, | |
| 26853 | missing_error: []const InternPool.NullTerminatedString, | |
| 26168 | 26854 | /// true if wanted is var args |
| 26169 | 26855 | fn_var_args: bool, |
| 26170 | 26856 | /// true if wanted is generic |
| ... | ... | @@ -26264,6 +26950,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26264 | 26950 | } |
| 26265 | 26951 | |
| 26266 | 26952 | fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void { |
| 26953 | const mod = sema.mod; | |
| 26267 | 26954 | var cur = res; |
| 26268 | 26955 | while (true) switch (cur.*) { |
| 26269 | 26956 | .ok => unreachable, |
| ... | ... | @@ -26280,7 +26967,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26280 | 26967 | }, |
| 26281 | 26968 | .error_union_payload => |pair| { |
| 26282 | 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 | 26972 | cur = pair.child; |
| 26286 | 26973 | }, |
| ... | ... | @@ -26291,20 +26978,20 @@ const InMemoryCoercionResult = union(enum) { |
| 26291 | 26978 | break; |
| 26292 | 26979 | }, |
| 26293 | 26980 | .array_sentinel => |sentinel| { |
| 26294 | if (sentinel.actual.tag() != .unreachable_value) { | |
| 26981 | if (sentinel.actual.toIntern() != .unreachable_value) { | |
| 26295 | 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 | 26985 | } else { |
| 26299 | 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 | 26990 | break; |
| 26304 | 26991 | }, |
| 26305 | 26992 | .array_elem => |pair| { |
| 26306 | 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 | 26996 | cur = pair.child; |
| 26310 | 26997 | }, |
| ... | ... | @@ -26316,21 +27003,19 @@ const InMemoryCoercionResult = union(enum) { |
| 26316 | 27003 | }, |
| 26317 | 27004 | .vector_elem => |pair| { |
| 26318 | 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 | 27008 | cur = pair.child; |
| 26322 | 27009 | }, |
| 26323 | 27010 | .optional_shape => |pair| { |
| 26324 | var buf_actual: Type.Payload.ElemType = undefined; | |
| 26325 | var buf_wanted: Type.Payload.ElemType = undefined; | |
| 26326 | 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 | 27014 | break; |
| 26330 | 27015 | }, |
| 26331 | 27016 | .optional_child => |pair| { |
| 26332 | 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 | 27020 | cur = pair.child; |
| 26336 | 27021 | }, |
| ... | ... | @@ -26340,7 +27025,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26340 | 27025 | }, |
| 26341 | 27026 | .missing_error => |missing_errors| { |
| 26342 | 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 | 27030 | break; |
| 26346 | 27031 | }, |
| ... | ... | @@ -26394,7 +27079,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26394 | 27079 | }, |
| 26395 | 27080 | .fn_param => |param| { |
| 26396 | 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 | 27084 | cur = param.child; |
| 26400 | 27085 | }, |
| ... | ... | @@ -26404,13 +27089,13 @@ const InMemoryCoercionResult = union(enum) { |
| 26404 | 27089 | }, |
| 26405 | 27090 | .fn_return_type => |pair| { |
| 26406 | 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 | 27094 | cur = pair.child; |
| 26410 | 27095 | }, |
| 26411 | 27096 | .ptr_child => |pair| { |
| 26412 | 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 | 27100 | cur = pair.child; |
| 26416 | 27101 | }, |
| ... | ... | @@ -26419,13 +27104,13 @@ const InMemoryCoercionResult = union(enum) { |
| 26419 | 27104 | break; |
| 26420 | 27105 | }, |
| 26421 | 27106 | .ptr_sentinel => |sentinel| { |
| 26422 | if (sentinel.actual.tag() != .unreachable_value) { | |
| 27107 | if (sentinel.actual.toIntern() != .unreachable_value) { | |
| 26423 | 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 | 27111 | } else { |
| 26427 | 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 | 27116 | break; |
| ... | ... | @@ -26445,15 +27130,15 @@ const InMemoryCoercionResult = union(enum) { |
| 26445 | 27130 | break; |
| 26446 | 27131 | }, |
| 26447 | 27132 | .ptr_allowzero => |pair| { |
| 26448 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(); | |
| 26449 | const actual_allow_zero = pair.actual.ptrAllowsZero(); | |
| 27133 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(mod); | |
| 27134 | const actual_allow_zero = pair.actual.ptrAllowsZero(mod); | |
| 26450 | 27135 | if (actual_allow_zero and !wanted_allow_zero) { |
| 26451 | 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 | 27139 | } else { |
| 26455 | 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 | 27144 | break; |
| ... | ... | @@ -26479,13 +27164,13 @@ const InMemoryCoercionResult = union(enum) { |
| 26479 | 27164 | }, |
| 26480 | 27165 | .double_ptr_to_anyopaque => |pair| { |
| 26481 | 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 | 27169 | break; |
| 26485 | 27170 | }, |
| 26486 | 27171 | .slice_to_anyopaque => |pair| { |
| 26487 | 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 | 27175 | try sema.errNote(block, src, msg, "consider using '.ptr'", .{}); |
| 26491 | 27176 | break; |
| ... | ... | @@ -26522,13 +27207,18 @@ fn coerceInMemoryAllowed( |
| 26522 | 27207 | dest_src: LazySrcLoc, |
| 26523 | 27208 | src_src: LazySrcLoc, |
| 26524 | 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 | 27213 | return .ok; |
| 26527 | 27214 | |
| 27215 | const dest_tag = dest_ty.zigTypeTag(mod); | |
| 27216 | const src_tag = src_ty.zigTypeTag(mod); | |
| 27217 | ||
| 26528 | 27218 | // Differently-named integers with the same number of bits. |
| 26529 | if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { | |
| 26530 | const dest_info = dest_ty.intInfo(target); | |
| 26531 | const src_info = src_ty.intInfo(target); | |
| 27219 | if (dest_tag == .Int and src_tag == .Int) { | |
| 27220 | const dest_info = dest_ty.intInfo(mod); | |
| 27221 | const src_info = src_ty.intInfo(mod); | |
| 26532 | 27222 | |
| 26533 | 27223 | if (dest_info.signedness == src_info.signedness and |
| 26534 | 27224 | dest_info.bits == src_info.bits) |
| ... | ... | @@ -26551,7 +27241,7 @@ fn coerceInMemoryAllowed( |
| 26551 | 27241 | } |
| 26552 | 27242 | |
| 26553 | 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 | 27245 | const dest_bits = dest_ty.floatBits(target); |
| 26556 | 27246 | const src_bits = src_ty.floatBits(target); |
| 26557 | 27247 | if (dest_bits == src_bits) { |
| ... | ... | @@ -26560,10 +27250,8 @@ fn coerceInMemoryAllowed( |
| 26560 | 27250 | } |
| 26561 | 27251 | |
| 26562 | 27252 | // Pointers / Pointer-like Optionals |
| 26563 | var dest_buf: Type.Payload.ElemType = undefined; | |
| 26564 | var src_buf: Type.Payload.ElemType = undefined; | |
| 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); | |
| 27253 | const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty); | |
| 27254 | const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty); | |
| 26567 | 27255 | if (maybe_dest_ptr_ty) |dest_ptr_ty| { |
| 26568 | 27256 | if (maybe_src_ptr_ty) |src_ptr_ty| { |
| 26569 | 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 | 27259 | } |
| 26572 | 27260 | |
| 26573 | 27261 | // Slices |
| 26574 | if (dest_ty.isSlice() and src_ty.isSlice()) { | |
| 27262 | if (dest_ty.isSlice(mod) and src_ty.isSlice(mod)) { | |
| 26575 | 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 | 27266 | // Functions |
| 26582 | 27267 | if (dest_tag == .Fn and src_tag == .Fn) { |
| 26583 | 27268 | return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src); |
| ... | ... | @@ -26585,8 +27270,8 @@ fn coerceInMemoryAllowed( |
| 26585 | 27270 | |
| 26586 | 27271 | // Error Unions |
| 26587 | 27272 | if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { |
| 26588 | const dest_payload = dest_ty.errorUnionPayload(); | |
| 26589 | const src_payload = src_ty.errorUnionPayload(); | |
| 27273 | const dest_payload = dest_ty.errorUnionPayload(mod); | |
| 27274 | const src_payload = src_ty.errorUnionPayload(mod); | |
| 26590 | 27275 | const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); |
| 26591 | 27276 | if (child != .ok) { |
| 26592 | 27277 | return InMemoryCoercionResult{ .error_union_payload = .{ |
| ... | ... | @@ -26595,7 +27280,7 @@ fn coerceInMemoryAllowed( |
| 26595 | 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 | 27286 | // Error Sets |
| ... | ... | @@ -26605,8 +27290,8 @@ fn coerceInMemoryAllowed( |
| 26605 | 27290 | |
| 26606 | 27291 | // Arrays |
| 26607 | 27292 | if (dest_tag == .Array and src_tag == .Array) { |
| 26608 | const dest_info = dest_ty.arrayInfo(); | |
| 26609 | const src_info = src_ty.arrayInfo(); | |
| 27293 | const dest_info = dest_ty.arrayInfo(mod); | |
| 27294 | const src_info = src_ty.arrayInfo(mod); | |
| 26610 | 27295 | if (dest_info.len != src_info.len) { |
| 26611 | 27296 | return InMemoryCoercionResult{ .array_len = .{ |
| 26612 | 27297 | .actual = src_info.len, |
| ... | ... | @@ -26624,11 +27309,15 @@ fn coerceInMemoryAllowed( |
| 26624 | 27309 | } |
| 26625 | 27310 | const ok_sent = dest_info.sentinel == null or |
| 26626 | 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 | 27317 | if (!ok_sent) { |
| 26629 | 27318 | return InMemoryCoercionResult{ .array_sentinel = .{ |
| 26630 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), | |
| 26631 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), | |
| 27319 | .actual = src_info.sentinel orelse Value.@"unreachable", | |
| 27320 | .wanted = dest_info.sentinel orelse Value.@"unreachable", | |
| 26632 | 27321 | .ty = dest_info.elem_type, |
| 26633 | 27322 | } }; |
| 26634 | 27323 | } |
| ... | ... | @@ -26637,8 +27326,8 @@ fn coerceInMemoryAllowed( |
| 26637 | 27326 | |
| 26638 | 27327 | // Vectors |
| 26639 | 27328 | if (dest_tag == .Vector and src_tag == .Vector) { |
| 26640 | const dest_len = dest_ty.vectorLen(); | |
| 26641 | const src_len = src_ty.vectorLen(); | |
| 27329 | const dest_len = dest_ty.vectorLen(mod); | |
| 27330 | const src_len = src_ty.vectorLen(mod); | |
| 26642 | 27331 | if (dest_len != src_len) { |
| 26643 | 27332 | return InMemoryCoercionResult{ .vector_len = .{ |
| 26644 | 27333 | .actual = src_len, |
| ... | ... | @@ -26646,8 +27335,8 @@ fn coerceInMemoryAllowed( |
| 26646 | 27335 | } }; |
| 26647 | 27336 | } |
| 26648 | 27337 | |
| 26649 | const dest_elem_ty = dest_ty.scalarType(); | |
| 26650 | const src_elem_ty = src_ty.scalarType(); | |
| 27338 | const dest_elem_ty = dest_ty.scalarType(mod); | |
| 27339 | const src_elem_ty = src_ty.scalarType(mod); | |
| 26651 | 27340 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); |
| 26652 | 27341 | if (child != .ok) { |
| 26653 | 27342 | return InMemoryCoercionResult{ .vector_elem = .{ |
| ... | ... | @@ -26668,15 +27357,15 @@ fn coerceInMemoryAllowed( |
| 26668 | 27357 | .wanted = dest_ty, |
| 26669 | 27358 | } }; |
| 26670 | 27359 | } |
| 26671 | const dest_child_type = dest_ty.optionalChild(&dest_buf); | |
| 26672 | const src_child_type = src_ty.optionalChild(&src_buf); | |
| 27360 | const dest_child_type = dest_ty.optionalChild(mod); | |
| 27361 | const src_child_type = src_ty.optionalChild(mod); | |
| 26673 | 27362 | |
| 26674 | 27363 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); |
| 26675 | 27364 | if (child != .ok) { |
| 26676 | 27365 | return InMemoryCoercionResult{ .optional_child = .{ |
| 26677 | 27366 | .child = try child.dupe(sema.arena), |
| 26678 | .actual = try src_child_type.copy(sema.arena), | |
| 26679 | .wanted = try dest_child_type.copy(sema.arena), | |
| 27367 | .actual = src_child_type, | |
| 27368 | .wanted = dest_child_type, | |
| 26680 | 27369 | } }; |
| 26681 | 27370 | } |
| 26682 | 27371 | |
| ... | ... | @@ -26697,138 +27386,108 @@ fn coerceInMemoryAllowedErrorSets( |
| 26697 | 27386 | dest_src: LazySrcLoc, |
| 26698 | 27387 | src_src: LazySrcLoc, |
| 26699 | 27388 | ) !InMemoryCoercionResult { |
| 27389 | const mod = sema.mod; | |
| 27390 | const gpa = sema.gpa; | |
| 27391 | const ip = &mod.intern_pool; | |
| 27392 | ||
| 26700 | 27393 | // Coercion to `anyerror`. Note that this check can return false negatives |
| 26701 | 27394 | // in case the error sets did not get resolved. |
| 26702 | if (dest_ty.isAnyError()) { | |
| 27395 | if (dest_ty.isAnyError(mod)) { | |
| 26703 | 27396 | return .ok; |
| 26704 | 27397 | } |
| 26705 | 27398 | |
| 26706 | if (dest_ty.castTag(.error_set_inferred)) |dst_payload| { | |
| 26707 | const dst_ies = dst_payload.data; | |
| 27399 | if (mod.typeToInferredErrorSetIndex(dest_ty).unwrap()) |dst_ies_index| { | |
| 27400 | const dst_ies = mod.inferredErrorSetPtr(dst_ies_index); | |
| 26708 | 27401 | // We will make an effort to return `ok` without resolving either error set, to |
| 26709 | 27402 | // avoid unnecessary "unable to resolve error set" dependency loop errors. |
| 26710 | switch (src_ty.tag()) { | |
| 26711 | .error_set_inferred => { | |
| 26712 | // If both are inferred error sets of functions, and | |
| 26713 | // the dest includes the source function, the coercion is OK. | |
| 26714 | // This check is important because it works without forcing a full resolution | |
| 26715 | // of inferred error sets. | |
| 26716 | const src_ies = src_ty.castTag(.error_set_inferred).?.data; | |
| 26717 | ||
| 26718 | if (dst_ies.inferred_error_sets.contains(src_ies)) { | |
| 26719 | return .ok; | |
| 26720 | } | |
| 26721 | }, | |
| 26722 | .error_set_single => { | |
| 26723 | const name = src_ty.castTag(.error_set_single).?.data; | |
| 26724 | if (dst_ies.errors.contains(name)) return .ok; | |
| 26725 | }, | |
| 26726 | .error_set_merged => { | |
| 26727 | const names = src_ty.castTag(.error_set_merged).?.data.keys(); | |
| 26728 | for (names) |name| { | |
| 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, | |
| 27403 | switch (src_ty.toIntern()) { | |
| 27404 | .anyerror_type => {}, | |
| 27405 | else => switch (ip.indexToKey(src_ty.toIntern())) { | |
| 27406 | .inferred_error_set_type => |src_index| { | |
| 27407 | // If both are inferred error sets of functions, and | |
| 27408 | // the dest includes the source function, the coercion is OK. | |
| 27409 | // This check is important because it works without forcing a full resolution | |
| 27410 | // of inferred error sets. | |
| 27411 | if (dst_ies.inferred_error_sets.contains(src_index)) { | |
| 27412 | return .ok; | |
| 27413 | } | |
| 27414 | }, | |
| 27415 | .error_set_type => |error_set_type| { | |
| 27416 | for (error_set_type.names) |name| { | |
| 27417 | if (!dst_ies.errors.contains(name)) break; | |
| 27418 | } else return .ok; | |
| 27419 | }, | |
| 27420 | else => unreachable, | |
| 27421 | }, | |
| 26740 | 27422 | } |
| 26741 | 27423 | |
| 26742 | if (dst_ies.func == sema.owner_func) { | |
| 27424 | if (dst_ies.func == sema.owner_func_index.unwrap()) { | |
| 26743 | 27425 | // We are trying to coerce an error set to the current function's |
| 26744 | 27426 | // inferred error set. |
| 26745 | try dst_ies.addErrorSet(sema.gpa, src_ty); | |
| 27427 | try dst_ies.addErrorSet(src_ty, ip, gpa); | |
| 26746 | 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 | 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 | 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 | 27439 | defer missing_error_buf.deinit(); |
| 26758 | 27440 | |
| 26759 | switch (src_ty.tag()) { | |
| 26760 | .error_set_inferred => { | |
| 26761 | const src_data = src_ty.castTag(.error_set_inferred).?.data; | |
| 27441 | switch (src_ty.toIntern()) { | |
| 27442 | .anyerror_type => switch (ip.indexToKey(dest_ty.toIntern())) { | |
| 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); | |
| 26764 | // src anyerror status might have changed after the resolution. | |
| 26765 | if (src_ty.isAnyError()) { | |
| 26766 | // dest_ty.isAnyError() == true is already checked for at this point. | |
| 26767 | return .from_anyerror; | |
| 26768 | } | |
| 27453 | try sema.resolveInferredErrorSet(block, src_src, src_index); | |
| 27454 | // src anyerror status might have changed after the resolution. | |
| 27455 | if (src_ty.isAnyError(mod)) { | |
| 27456 | // dest_ty.isAnyError(mod) == true is already checked for at this point. | |
| 27457 | return .from_anyerror; | |
| 27458 | } | |
| 26769 | 27459 | |
| 26770 | for (src_data.errors.keys()) |key| { | |
| 26771 | if (!dest_ty.errorSetHasField(key)) { | |
| 26772 | try missing_error_buf.append(key); | |
| 27460 | for (src_data.errors.keys()) |key| { | |
| 27461 | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), key)) { | |
| 27462 | try missing_error_buf.append(key); | |
| 27463 | } | |
| 26773 | 27464 | } |
| 26774 | } | |
| 26775 | 27465 | |
| 26776 | if (missing_error_buf.items.len != 0) { | |
| 26777 | return InMemoryCoercionResult{ | |
| 26778 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), | |
| 26779 | }; | |
| 26780 | } | |
| 27466 | if (missing_error_buf.items.len != 0) { | |
| 27467 | return InMemoryCoercionResult{ | |
| 27468 | .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), | |
| 27469 | }; | |
| 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 | 27472 | return .ok; |
| 26788 | } | |
| 26789 | const list = try sema.arena.alloc([]const u8, 1); | |
| 26790 | list[0] = name; | |
| 26791 | return InMemoryCoercionResult{ .missing_error = list }; | |
| 26792 | }, | |
| 26793 | .error_set_merged => { | |
| 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); | |
| 27473 | }, | |
| 27474 | .error_set_type => |error_set_type| { | |
| 27475 | for (error_set_type.names) |name| { | |
| 27476 | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) { | |
| 27477 | try missing_error_buf.append(name); | |
| 27478 | } | |
| 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; | |
| 26808 | }, | |
| 26809 | .error_set => { | |
| 26810 | const names = src_ty.castTag(.error_set).?.data.names.keys(); | |
| 26811 | for (names) |name| { | |
| 26812 | if (!dest_ty.errorSetHasField(name)) { | |
| 26813 | try missing_error_buf.append(name); | |
| 27481 | if (missing_error_buf.items.len != 0) { | |
| 27482 | return InMemoryCoercionResult{ | |
| 27483 | .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), | |
| 27484 | }; | |
| 26814 | 27485 | } |
| 26815 | } | |
| 26816 | 27486 | |
| 26817 | if (missing_error_buf.items.len != 0) { | |
| 26818 | return InMemoryCoercionResult{ | |
| 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. | |
| 27487 | return .ok; | |
| 27488 | }, | |
| 26829 | 27489 | else => unreachable, |
| 26830 | 27490 | }, |
| 26831 | else => unreachable, | |
| 26832 | 27491 | } |
| 26833 | 27492 | |
| 26834 | 27493 | unreachable; |
| ... | ... | @@ -26843,69 +27502,95 @@ fn coerceInMemoryAllowedFns( |
| 26843 | 27502 | dest_src: LazySrcLoc, |
| 26844 | 27503 | src_src: LazySrcLoc, |
| 26845 | 27504 | ) !InMemoryCoercionResult { |
| 26846 | const dest_info = dest_ty.fnInfo(); | |
| 26847 | const src_info = src_ty.fnInfo(); | |
| 27505 | const mod = sema.mod; | |
| 26848 | 27506 | |
| 26849 | if (dest_info.is_var_args != src_info.is_var_args) { | |
| 26850 | return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; | |
| 26851 | } | |
| 27507 | { | |
| 27508 | const dest_info = mod.typeToFunc(dest_ty).?; | |
| 27509 | const src_info = mod.typeToFunc(src_ty).?; | |
| 26852 | 27510 | |
| 26853 | if (dest_info.is_generic != src_info.is_generic) { | |
| 26854 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; | |
| 26855 | } | |
| 27511 | if (dest_info.is_var_args != src_info.is_var_args) { | |
| 27512 | return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; | |
| 27513 | } | |
| 26856 | 27514 | |
| 26857 | if (dest_info.cc != src_info.cc) { | |
| 26858 | return InMemoryCoercionResult{ .fn_cc = .{ | |
| 26859 | .actual = src_info.cc, | |
| 26860 | .wanted = dest_info.cc, | |
| 26861 | } }; | |
| 26862 | } | |
| 27515 | if (dest_info.is_generic != src_info.is_generic) { | |
| 27516 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; | |
| 27517 | } | |
| 26863 | 27518 | |
| 26864 | if (!src_info.return_type.isNoReturn()) { | |
| 26865 | const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src); | |
| 26866 | if (rt != .ok) { | |
| 26867 | return InMemoryCoercionResult{ .fn_return_type = .{ | |
| 26868 | .child = try rt.dupe(sema.arena), | |
| 26869 | .actual = src_info.return_type, | |
| 26870 | .wanted = dest_info.return_type, | |
| 27519 | if (dest_info.cc != src_info.cc) { | |
| 27520 | return InMemoryCoercionResult{ .fn_cc = .{ | |
| 27521 | .actual = src_info.cc, | |
| 27522 | .wanted = dest_info.cc, | |
| 26871 | 27523 | } }; |
| 26872 | 27524 | } |
| 26873 | } | |
| 26874 | 27525 | |
| 26875 | if (dest_info.param_types.len != src_info.param_types.len) { | |
| 26876 | return InMemoryCoercionResult{ .fn_param_count = .{ | |
| 26877 | .actual = src_info.param_types.len, | |
| 26878 | .wanted = dest_info.param_types.len, | |
| 26879 | } }; | |
| 27526 | switch (src_info.return_type) { | |
| 27527 | .noreturn_type, .generic_poison_type => {}, | |
| 27528 | else => { | |
| 27529 | const dest_return_type = dest_info.return_type.toType(); | |
| 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) { | |
| 26883 | return InMemoryCoercionResult{ .fn_param_noalias = .{ | |
| 26884 | .actual = src_info.noalias_bits, | |
| 26885 | .wanted = dest_info.noalias_bits, | |
| 26886 | } }; | |
| 26887 | } | |
| 27543 | const params_len = params_len: { | |
| 27544 | const dest_info = mod.typeToFunc(dest_ty).?; | |
| 27545 | const src_info = mod.typeToFunc(src_ty).?; | |
| 26888 | 27546 | |
| 26889 | for (dest_info.param_types, 0..) |dest_param_ty, i| { | |
| 26890 | const src_param_ty = src_info.param_types[i]; | |
| 27547 | if (dest_info.param_types.len != src_info.param_types.len) { | |
| 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]) { | |
| 26893 | return InMemoryCoercionResult{ .fn_param_comptime = .{ | |
| 26894 | .index = i, | |
| 26895 | .wanted = dest_info.comptime_params[i], | |
| 27554 | if (dest_info.noalias_bits != src_info.noalias_bits) { | |
| 27555 | return InMemoryCoercionResult{ .fn_param_noalias = .{ | |
| 27556 | .actual = src_info.noalias_bits, | |
| 27557 | .wanted = dest_info.noalias_bits, | |
| 26896 | 27558 | } }; |
| 26897 | 27559 | } |
| 26898 | 27560 | |
| 26899 | // Note: Cast direction is reversed here. | |
| 26900 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); | |
| 26901 | if (param != .ok) { | |
| 26902 | return InMemoryCoercionResult{ .fn_param = .{ | |
| 26903 | .child = try param.dupe(sema.arena), | |
| 26904 | .actual = src_param_ty, | |
| 26905 | .wanted = dest_param_ty, | |
| 26906 | .index = i, | |
| 27561 | break :params_len dest_info.param_types.len; | |
| 27562 | }; | |
| 27563 | ||
| 27564 | for (0..params_len) |param_i| { | |
| 27565 | const dest_info = mod.typeToFunc(dest_ty).?; | |
| 27566 | const src_info = mod.typeToFunc(src_ty).?; | |
| 27567 | ||
| 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 | 27596 | return .ok; |
| ... | ... | @@ -26923,8 +27608,9 @@ fn coerceInMemoryAllowedPtrs( |
| 26923 | 27608 | dest_src: LazySrcLoc, |
| 26924 | 27609 | src_src: LazySrcLoc, |
| 26925 | 27610 | ) !InMemoryCoercionResult { |
| 26926 | const dest_info = dest_ptr_ty.ptrInfo().data; | |
| 26927 | const src_info = src_ptr_ty.ptrInfo().data; | |
| 27611 | const mod = sema.mod; | |
| 27612 | const dest_info = dest_ptr_ty.ptrInfo(mod); | |
| 27613 | const src_info = src_ptr_ty.ptrInfo(mod); | |
| 26928 | 27614 | |
| 26929 | 27615 | const ok_ptr_size = src_info.size == dest_info.size or |
| 26930 | 27616 | src_info.size == .C or dest_info.size == .C; |
| ... | ... | @@ -26964,8 +27650,8 @@ fn coerceInMemoryAllowedPtrs( |
| 26964 | 27650 | } }; |
| 26965 | 27651 | } |
| 26966 | 27652 | |
| 26967 | const dest_allow_zero = dest_ty.ptrAllowsZero(); | |
| 26968 | const src_allow_zero = src_ty.ptrAllowsZero(); | |
| 27653 | const dest_allow_zero = dest_ty.ptrAllowsZero(mod); | |
| 27654 | const src_allow_zero = src_ty.ptrAllowsZero(mod); | |
| 26969 | 27655 | |
| 26970 | 27656 | const ok_allows_zero = (dest_allow_zero and |
| 26971 | 27657 | (src_allow_zero or !dest_is_mut)) or |
| ... | ... | @@ -26989,12 +27675,15 @@ fn coerceInMemoryAllowedPtrs( |
| 26989 | 27675 | } |
| 26990 | 27676 | |
| 26991 | 27677 | const ok_sent = dest_info.sentinel == null or src_info.size == .C or |
| 26992 | (src_info.sentinel != null and | |
| 26993 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); | |
| 27678 | (src_info.sentinel != null and dest_info.sentinel.?.eql( | |
| 27679 | try mod.getCoerced(src_info.sentinel.?, dest_info.pointee_type), | |
| 27680 | dest_info.pointee_type, | |
| 27681 | sema.mod, | |
| 27682 | )); | |
| 26994 | 27683 | if (!ok_sent) { |
| 26995 | 27684 | return InMemoryCoercionResult{ .ptr_sentinel = .{ |
| 26996 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), | |
| 26997 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), | |
| 27685 | .actual = src_info.sentinel orelse Value.@"unreachable", | |
| 27686 | .wanted = dest_info.sentinel orelse Value.@"unreachable", | |
| 26998 | 27687 | .ty = dest_info.pointee_type, |
| 26999 | 27688 | } }; |
| 27000 | 27689 | } |
| ... | ... | @@ -27013,12 +27702,12 @@ fn coerceInMemoryAllowedPtrs( |
| 27013 | 27702 | const src_align = if (src_info.@"align" != 0) |
| 27014 | 27703 | src_info.@"align" |
| 27015 | 27704 | else |
| 27016 | src_info.pointee_type.abiAlignment(target); | |
| 27705 | src_info.pointee_type.abiAlignment(mod); | |
| 27017 | 27706 | |
| 27018 | 27707 | const dest_align = if (dest_info.@"align" != 0) |
| 27019 | 27708 | dest_info.@"align" |
| 27020 | 27709 | else |
| 27021 | dest_info.pointee_type.abiAlignment(target); | |
| 27710 | dest_info.pointee_type.abiAlignment(mod); | |
| 27022 | 27711 | |
| 27023 | 27712 | if (dest_align > src_align) { |
| 27024 | 27713 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| ... | ... | @@ -27041,8 +27730,9 @@ fn coerceVarArgParam( |
| 27041 | 27730 | ) !Air.Inst.Ref { |
| 27042 | 27731 | if (block.is_typeof) return inst; |
| 27043 | 27732 | |
| 27733 | const mod = sema.mod; | |
| 27044 | 27734 | const uncasted_ty = sema.typeOf(inst); |
| 27045 | const coerced = switch (uncasted_ty.zigTypeTag()) { | |
| 27735 | const coerced = switch (uncasted_ty.zigTypeTag(mod)) { | |
| 27046 | 27736 | // TODO consider casting to c_int/f64 if they fit |
| 27047 | 27737 | .ComptimeInt, .ComptimeFloat => return sema.fail( |
| 27048 | 27738 | block, |
| ... | ... | @@ -27052,7 +27742,7 @@ fn coerceVarArgParam( |
| 27052 | 27742 | ), |
| 27053 | 27743 | .Fn => blk: { |
| 27054 | 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 | 27746 | break :blk try sema.analyzeDeclRef(fn_decl); |
| 27057 | 27747 | }, |
| 27058 | 27748 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), |
| ... | ... | @@ -27077,7 +27767,7 @@ fn coerceVarArgParam( |
| 27077 | 27767 | errdefer msg.destroy(sema.gpa); |
| 27078 | 27768 | |
| 27079 | 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 | 27772 | try sema.addDeclaredHereNote(msg, coerced_ty); |
| 27083 | 27773 | break :msg msg; |
| ... | ... | @@ -27109,11 +27799,12 @@ fn storePtr2( |
| 27109 | 27799 | operand_src: LazySrcLoc, |
| 27110 | 27800 | air_tag: Air.Inst.Tag, |
| 27111 | 27801 | ) CompileError!void { |
| 27802 | const mod = sema.mod; | |
| 27112 | 27803 | const ptr_ty = sema.typeOf(ptr); |
| 27113 | if (ptr_ty.isConstPtr()) | |
| 27804 | if (ptr_ty.isConstPtr(mod)) | |
| 27114 | 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 | 27809 | // To generate better code for tuples, we detect a tuple operand here, and |
| 27119 | 27810 | // analyze field loads and stores directly. This avoids an extra allocation + memcpy |
| ... | ... | @@ -27124,8 +27815,8 @@ fn storePtr2( |
| 27124 | 27815 | // this code does not handle tuple-to-struct coercion which requires dealing with missing |
| 27125 | 27816 | // fields. |
| 27126 | 27817 | const operand_ty = sema.typeOf(uncasted_operand); |
| 27127 | if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) { | |
| 27128 | const field_count = operand_ty.structFieldCount(); | |
| 27818 | if (operand_ty.isTuple(mod) and elem_ty.zigTypeTag(mod) == .Array) { | |
| 27819 | const field_count = operand_ty.structFieldCount(mod); | |
| 27129 | 27820 | var i: u32 = 0; |
| 27130 | 27821 | while (i < field_count) : (i += 1) { |
| 27131 | 27822 | const elem_src = operand_src; // TODO better source location |
| ... | ... | @@ -27149,7 +27840,7 @@ fn storePtr2( |
| 27149 | 27840 | // as well as working around an LLVM bug: |
| 27150 | 27841 | // https://github.com/ziglang/zig/issues/11154 |
| 27151 | 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 | 27844 | const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { |
| 27154 | 27845 | error.NotCoercible => unreachable, |
| 27155 | 27846 | else => |e| return e, |
| ... | ... | @@ -27169,7 +27860,7 @@ fn storePtr2( |
| 27169 | 27860 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); |
| 27170 | 27861 | break :rs operand_src; |
| 27171 | 27862 | }; |
| 27172 | if (ptr_val.isComptimeMutablePtr()) { | |
| 27863 | if (ptr_val.isComptimeMutablePtr(mod)) { | |
| 27173 | 27864 | try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); |
| 27174 | 27865 | return; |
| 27175 | 27866 | } else break :rs ptr_src; |
| ... | ... | @@ -27190,7 +27881,7 @@ fn storePtr2( |
| 27190 | 27881 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 27191 | 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 | 27885 | const ptr_inst = Air.refToIndex(ptr).?; |
| 27195 | 27886 | const air_tags = sema.air_instructions.items(.tag); |
| 27196 | 27887 | if (air_tags[ptr_inst] == .ptr_elem_ptr) { |
| ... | ... | @@ -27224,30 +27915,27 @@ fn storePtr2( |
| 27224 | 27915 | /// pointer. Only if the final element type matches the vector element type, and the |
| 27225 | 27916 | /// lengths match. |
| 27226 | 27917 | fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref { |
| 27227 | const array_ty = sema.typeOf(ptr).childType(); | |
| 27228 | if (array_ty.zigTypeTag() != .Array) return null; | |
| 27229 | var ptr_inst = Air.refToIndex(ptr) orelse return null; | |
| 27918 | const mod = sema.mod; | |
| 27919 | const array_ty = sema.typeOf(ptr).childType(mod); | |
| 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 | 27923 | const air_datas = sema.air_instructions.items(.data); |
| 27231 | 27924 | const air_tags = sema.air_instructions.items(.tag); |
| 27232 | const prev_ptr = while (air_tags[ptr_inst] == .bitcast) { | |
| 27233 | const prev_ptr = air_datas[ptr_inst].ty_op.operand; | |
| 27234 | const prev_ptr_ty = sema.typeOf(prev_ptr); | |
| 27235 | const prev_ptr_child_ty = switch (prev_ptr_ty.tag()) { | |
| 27236 | .single_mut_pointer => prev_ptr_ty.castTag(.single_mut_pointer).?.data, | |
| 27237 | .pointer => prev_ptr_ty.castTag(.pointer).?.data.pointee_type, | |
| 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; | |
| 27925 | const vector_ty = while (air_tags[ptr_inst] == .bitcast) { | |
| 27926 | ptr_ref = air_datas[ptr_inst].ty_op.operand; | |
| 27927 | if (!sema.isKnownZigType(ptr_ref, .Pointer)) return null; | |
| 27928 | const child_ty = sema.typeOf(ptr_ref).childType(mod); | |
| 27929 | if (child_ty.zigTypeTag(mod) == .Vector) break child_ty; | |
| 27930 | ptr_inst = Air.refToIndex(ptr_ref) orelse return null; | |
| 27242 | 27931 | } else return null; |
| 27243 | 27932 | |
| 27244 | 27933 | // We have a pointer-to-array and a pointer-to-vector. If the elements and |
| 27245 | 27934 | // lengths match, return the result. |
| 27246 | const vector_ty = sema.typeOf(prev_ptr).childType(); | |
| 27247 | if (array_ty.childType().eql(vector_ty.childType(), sema.mod) and | |
| 27248 | array_ty.arrayLen() == vector_ty.vectorLen()) | |
| 27935 | if (array_ty.childType(mod).eql(vector_ty.childType(mod), sema.mod) and | |
| 27936 | array_ty.arrayLen(mod) == vector_ty.vectorLen(mod)) | |
| 27249 | 27937 | { |
| 27250 | return prev_ptr; | |
| 27938 | return ptr_ref; | |
| 27251 | 27939 | } else { |
| 27252 | 27940 | return null; |
| 27253 | 27941 | } |
| ... | ... | @@ -27263,54 +27951,55 @@ fn storePtrVal( |
| 27263 | 27951 | operand_val: Value, |
| 27264 | 27952 | operand_ty: Type, |
| 27265 | 27953 | ) !void { |
| 27954 | const mod = sema.mod; | |
| 27266 | 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 | 27958 | switch (mut_kit.pointee) { |
| 27270 | 27959 | .direct => |val_ptr| { |
| 27271 | if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) { | |
| 27272 | if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) { | |
| 27960 | if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) { | |
| 27961 | if (!operand_val.eql(val_ptr.*, operand_ty, mod)) { | |
| 27273 | 27962 | // TODO use failWithInvalidComptimeFieldStore |
| 27274 | 27963 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); |
| 27275 | 27964 | } |
| 27276 | 27965 | return; |
| 27277 | 27966 | } |
| 27278 | const arena = mut_kit.beginArena(sema.mod); | |
| 27279 | defer mut_kit.finishArena(sema.mod); | |
| 27280 | ||
| 27281 | val_ptr.* = try operand_val.copy(arena); | |
| 27967 | val_ptr.* = (try operand_val.intern(operand_ty, mod)).toValue(); | |
| 27282 | 27968 | }, |
| 27283 | 27969 | .reinterpret => |reinterpret| { |
| 27284 | const target = sema.mod.getTarget(); | |
| 27285 | const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target)); | |
| 27970 | const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod)); | |
| 27286 | 27971 | const buffer = try sema.gpa.alloc(u8, abi_size); |
| 27287 | 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 | 27975 | error.ReinterpretDeclRef => unreachable, |
| 27290 | 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 | 27981 | error.ReinterpretDeclRef => unreachable, |
| 27295 | 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); | |
| 27300 | defer mut_kit.finishArena(sema.mod); | |
| 27301 | ||
| 27302 | reinterpret.val_ptr.* = try Value.readFromMemory(mut_kit.ty, sema.mod, buffer, arena); | |
| 27986 | reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, sema.arena)).intern(mut_kit.ty, mod)).toValue(); | |
| 27303 | 27987 | }, |
| 27304 | 27988 | .bad_decl_ty, .bad_ptr_ty => { |
| 27305 | 27989 | // TODO show the decl declaration site in a note and explain whether the decl |
| 27306 | 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 | 28001 | const ComptimePtrMutationKit = struct { |
| 27313 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | |
| 28002 | mut_decl: InternPool.Key.Ptr.Addr.MutDecl, | |
| 27314 | 28003 | pointee: union(enum) { |
| 27315 | 28004 | /// The pointer type matches the actual comptime Value so a direct |
| 27316 | 28005 | /// modification is possible. |
| ... | ... | @@ -27333,18 +28022,6 @@ const ComptimePtrMutationKit = struct { |
| 27333 | 28022 | bad_ptr_ty, |
| 27334 | 28023 | }, |
| 27335 | 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 | 28027 | fn beginComptimePtrMutation( |
| ... | ... | @@ -27354,201 +28031,251 @@ fn beginComptimePtrMutation( |
| 27354 | 28031 | ptr_val: Value, |
| 27355 | 28032 | ptr_elem_ty: Type, |
| 27356 | 28033 | ) CompileError!ComptimePtrMutationKit { |
| 27357 | const target = sema.mod.getTarget(); | |
| 27358 | switch (ptr_val.tag()) { | |
| 27359 | .decl_ref_mut => { | |
| 27360 | const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data; | |
| 27361 | const decl = sema.mod.declPtr(decl_ref_mut.decl_index); | |
| 27362 | return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut); | |
| 27363 | }, | |
| 27364 | .comptime_field_ptr => { | |
| 27365 | const payload = ptr_val.castTag(.comptime_field_ptr).?.data; | |
| 28034 | const mod = sema.mod; | |
| 28035 | const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr; | |
| 28036 | switch (ptr.addr) { | |
| 28037 | .decl, .int => unreachable, // isComptimeMutablePtr has been checked already | |
| 28038 | .mut_decl => |mut_decl| { | |
| 28039 | const decl = mod.declPtr(mut_decl.decl); | |
| 28040 | return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl); | |
| 28041 | }, | |
| 28042 | .comptime_field => |comptime_field| { | |
| 27366 | 28043 | const duped = try sema.arena.create(Value); |
| 27367 | duped.* = payload.field_val; | |
| 27368 | return sema.beginComptimePtrMutationInner(block, src, payload.field_ty, duped, ptr_elem_ty, .{ | |
| 27369 | .decl_index = @intToEnum(Module.Decl.Index, 0), | |
| 28044 | duped.* = comptime_field.toValue(); | |
| 28045 | return sema.beginComptimePtrMutationInner(block, src, mod.intern_pool.typeOf(comptime_field).toType(), duped, ptr_elem_ty, .{ | |
| 28046 | .decl = undefined, | |
| 27370 | 28047 | .runtime_index = .comptime_field_ptr, |
| 27371 | 28048 | }); |
| 27372 | 28049 | }, |
| 27373 | .elem_ptr => { | |
| 27374 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 27375 | var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.array_ptr, elem_ptr.elem_ty); | |
| 28050 | .eu_payload => |eu_ptr| { | |
| 28051 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); | |
| 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 | 28148 | switch (parent.pointee) { |
| 27378 | .direct => |val_ptr| switch (parent.ty.zigTypeTag()) { | |
| 28149 | .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) { | |
| 27379 | 28150 | .Array, .Vector => { |
| 27380 | const check_len = parent.ty.arrayLenIncludingSentinel(); | |
| 28151 | const check_len = parent.ty.arrayLenIncludingSentinel(mod); | |
| 27381 | 28152 | if (elem_ptr.index >= check_len) { |
| 27382 | 28153 | // TODO have the parent include the decl so we can say "declared here" |
| 27383 | 28154 | return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ |
| 27384 | 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 | 28160 | // We might have a pointer to multiple elements of the array (e.g. a pointer |
| 27390 | 28161 | // to a sub-array). In this case, we just have to reinterpret the relevant |
| 27391 | 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 | 28164 | if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) { |
| 27394 | 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 | 28167 | return .{ |
| 27396 | .decl_ref_mut = parent.decl_ref_mut, | |
| 28168 | .mut_decl = parent.mut_decl, | |
| 27397 | 28169 | .pointee = .{ .reinterpret = .{ |
| 27398 | 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 | 28173 | .ty = parent.ty, |
| 27402 | 28174 | }; |
| 27403 | 28175 | } |
| 27404 | 28176 | |
| 27405 | switch (val_ptr.tag()) { | |
| 27406 | .undef => { | |
| 27407 | // An array has been initialized to undefined at comptime and now we | |
| 27408 | // are for the first time setting an element. We must change the representation | |
| 27409 | // of the array from `undef` to `array`. | |
| 27410 | const arena = parent.beginArena(sema.mod); | |
| 27411 | defer parent.finishArena(sema.mod); | |
| 28177 | switch (val_ptr.ip_index) { | |
| 28178 | .none => switch (val_ptr.tag()) { | |
| 28179 | .bytes => { | |
| 28180 | // An array is memory-optimized to store a slice of bytes, but we are about | |
| 28181 | // to modify an individual field and the representation has to change. | |
| 28182 | // If we wanted to avoid this, there would need to be special detection | |
| 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 = | |
| 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); | |
| 28197 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 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( | |
| 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 | } | |
| 28228 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 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 | 28242 | sema, |
| 27453 | 28243 | block, |
| 27454 | 28244 | src, |
| 27455 | 28245 | elem_ty, |
| 27456 | &elems[elem_ptr.index], | |
| 28246 | &val_ptr.castTag(.aggregate).?.data[@intCast(usize, elem_ptr.index)], | |
| 27457 | 28247 | ptr_elem_ty, |
| 27458 | parent.decl_ref_mut, | |
| 27459 | ); | |
| 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); | |
| 28248 | parent.mut_decl, | |
| 28249 | ), | |
| 27483 | 28250 | |
| 27484 | return beginComptimePtrMutationInner( | |
| 27485 | sema, | |
| 27486 | block, | |
| 27487 | src, | |
| 27488 | elem_ty, | |
| 27489 | &elems[elem_ptr.index], | |
| 27490 | ptr_elem_ty, | |
| 27491 | parent.decl_ref_mut, | |
| 27492 | ); | |
| 28251 | else => unreachable, | |
| 27493 | 28252 | }, |
| 27494 | .repeated => { | |
| 27495 | // An array is memory-optimized to store only a single element value, and | |
| 27496 | // that value is understood to be the same for the entire length of the array. | |
| 27497 | // However, now we want to modify an individual field and so the | |
| 27498 | // representation has to change. If we wanted to avoid this, there would | |
| 27499 | // need to be special detection elsewhere to identify when writing a value to an | |
| 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 | } | |
| 28253 | else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { | |
| 28254 | .undef => { | |
| 28255 | // An array has been initialized to undefined at comptime and now we | |
| 28256 | // are for the first time setting an element. We must change the representation | |
| 28257 | // of the array from `undef` to `array`. | |
| 28258 | const arena = sema.arena; | |
| 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( | |
| 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 | }, | |
| 28265 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 27526 | 28266 | |
| 27527 | .aggregate => return beginComptimePtrMutationInner( | |
| 27528 | sema, | |
| 27529 | block, | |
| 27530 | src, | |
| 27531 | elem_ty, | |
| 27532 | &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], | |
| 27533 | ptr_elem_ty, | |
| 27534 | parent.decl_ref_mut, | |
| 27535 | ), | |
| 27536 | ||
| 27537 | .the_only_possible_value => { | |
| 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 | ); | |
| 28267 | return beginComptimePtrMutationInner( | |
| 28268 | sema, | |
| 28269 | block, | |
| 28270 | src, | |
| 28271 | elem_ty, | |
| 28272 | &elems[@intCast(usize, elem_ptr.index)], | |
| 28273 | ptr_elem_ty, | |
| 28274 | parent.mut_decl, | |
| 28275 | ); | |
| 28276 | }, | |
| 28277 | else => unreachable, | |
| 27549 | 28278 | }, |
| 27550 | ||
| 27551 | else => unreachable, | |
| 27552 | 28279 | } |
| 27553 | 28280 | }, |
| 27554 | 28281 | else => { |
| ... | ... | @@ -27565,28 +28292,29 @@ fn beginComptimePtrMutation( |
| 27565 | 28292 | parent.ty, |
| 27566 | 28293 | val_ptr, |
| 27567 | 28294 | ptr_elem_ty, |
| 27568 | parent.decl_ref_mut, | |
| 28295 | parent.mut_decl, | |
| 27569 | 28296 | ); |
| 27570 | 28297 | }, |
| 27571 | 28298 | }, |
| 27572 | 28299 | .reinterpret => |reinterpret| { |
| 27573 | if (!elem_ptr.elem_ty.hasWellDefinedLayout()) { | |
| 28300 | if (!base_elem_ty.hasWellDefinedLayout(mod)) { | |
| 27574 | 28301 | // Even though the parent value type has well-defined memory layout, our |
| 27575 | 28302 | // pointer type does not. |
| 27576 | 28303 | return ComptimePtrMutationKit{ |
| 27577 | .decl_ref_mut = parent.decl_ref_mut, | |
| 28304 | .mut_decl = parent.mut_decl, | |
| 27578 | 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 | 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 | 28313 | return ComptimePtrMutationKit{ |
| 27586 | .decl_ref_mut = parent.decl_ref_mut, | |
| 28314 | .mut_decl = parent.mut_decl, | |
| 27587 | 28315 | .pointee = .{ .reinterpret = .{ |
| 27588 | 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 | 28319 | .ty = parent.ty, |
| 27592 | 28320 | }; |
| ... | ... | @@ -27594,162 +28322,184 @@ fn beginComptimePtrMutation( |
| 27594 | 28322 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 27595 | 28323 | } |
| 27596 | 28324 | }, |
| 27597 | .field_ptr => { | |
| 27598 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 27599 | const field_index = @intCast(u32, field_ptr.field_index); | |
| 28325 | .field => |field_ptr| { | |
| 28326 | const base_child_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | |
| 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 | 28330 | switch (parent.pointee) { |
| 27603 | .direct => |val_ptr| switch (val_ptr.tag()) { | |
| 27604 | .undef => { | |
| 27605 | // A struct or union has been initialized to undefined at comptime and now we | |
| 27606 | // are for the first time setting a field. We must change the representation | |
| 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 | ||
| 28331 | .direct => |val_ptr| switch (val_ptr.ip_index) { | |
| 28332 | .empty_struct => { | |
| 28333 | const duped = try sema.arena.create(Value); | |
| 28334 | duped.* = val_ptr.*; | |
| 27698 | 28335 | return beginComptimePtrMutationInner( |
| 27699 | 28336 | sema, |
| 27700 | 28337 | block, |
| 27701 | 28338 | src, |
| 27702 | parent.ty.structFieldType(field_index), | |
| 27703 | &payload.val, | |
| 28339 | parent.ty.structFieldType(field_index, mod), | |
| 28340 | duped, | |
| 27704 | 28341 | ptr_elem_ty, |
| 27705 | parent.decl_ref_mut, | |
| 28342 | parent.mut_decl, | |
| 27706 | 28343 | ); |
| 27707 | 28344 | }, |
| 27708 | .slice => switch (field_index) { | |
| 27709 | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( | |
| 28345 | .none => switch (val_ptr.tag()) { | |
| 28346 | .aggregate => return beginComptimePtrMutationInner( | |
| 27710 | 28347 | sema, |
| 27711 | 28348 | block, |
| 27712 | 28349 | src, |
| 27713 | parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | |
| 27714 | &val_ptr.castTag(.slice).?.data.ptr, | |
| 28350 | parent.ty.structFieldType(field_index, mod), | |
| 28351 | &val_ptr.castTag(.aggregate).?.data[field_index], | |
| 27715 | 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( | |
| 27720 | sema, | |
| 27721 | block, | |
| 27722 | src, | |
| 27723 | Type.usize, | |
| 27724 | &val_ptr.castTag(.slice).?.data.len, | |
| 27725 | ptr_elem_ty, | |
| 27726 | parent.decl_ref_mut, | |
| 27727 | ), | |
| 28358 | const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); | |
| 28359 | @memset(elems, val_ptr.castTag(.repeated).?.data); | |
| 28360 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 28361 | ||
| 28362 | return beginComptimePtrMutationInner( | |
| 28363 | sema, | |
| 28364 | block, | |
| 28365 | src, | |
| 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 | 28412 | else => unreachable, |
| 27730 | 28413 | }, |
| 27731 | ||
| 27732 | .empty_struct_value => { | |
| 27733 | const duped = try sema.arena.create(Value); | |
| 27734 | duped.* = Value.initTag(.the_only_possible_value); | |
| 27735 | return beginComptimePtrMutationInner( | |
| 27736 | sema, | |
| 27737 | block, | |
| 27738 | src, | |
| 27739 | parent.ty.structFieldType(field_index), | |
| 27740 | duped, | |
| 27741 | ptr_elem_ty, | |
| 27742 | parent.decl_ref_mut, | |
| 27743 | ); | |
| 28414 | else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { | |
| 28415 | .undef => { | |
| 28416 | // A struct or union has been initialized to undefined at comptime and now we | |
| 28417 | // are for the first time setting a field. We must change the representation | |
| 28418 | // of the struct/union from `undef` to `struct`/`union`. | |
| 28419 | const arena = sema.arena; | |
| 28420 | ||
| 28421 | switch (parent.ty.zigTypeTag(mod)) { | |
| 28422 | .Struct => { | |
| 28423 | const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod)); | |
| 28424 | for (fields, 0..) |*field, i| field.* = (try mod.intern(.{ | |
| 28425 | .undef = parent.ty.structFieldType(i, mod).toIntern(), | |
| 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 | 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 | 28500 | const field_offset = try sema.usizeCast(block, src, field_offset_u64); |
| 27751 | 28501 | return ComptimePtrMutationKit{ |
| 27752 | .decl_ref_mut = parent.decl_ref_mut, | |
| 28502 | .mut_decl = parent.mut_decl, | |
| 27753 | 28503 | .pointee = .{ .reinterpret = .{ |
| 27754 | 28504 | .val_ptr = reinterpret.val_ptr, |
| 27755 | 28505 | .byte_offset = reinterpret.byte_offset + field_offset, |
| ... | ... | @@ -27760,106 +28510,6 @@ fn beginComptimePtrMutation( |
| 27760 | 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 | 28520 | decl_ty: Type, |
| 27871 | 28521 | decl_val: *Value, |
| 27872 | 28522 | ptr_elem_ty: Type, |
| 27873 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | |
| 28523 | mut_decl: InternPool.Key.Ptr.Addr.MutDecl, | |
| 27874 | 28524 | ) CompileError!ComptimePtrMutationKit { |
| 27875 | const target = sema.mod.getTarget(); | |
| 28525 | const mod = sema.mod; | |
| 28526 | const target = mod.getTarget(); | |
| 27876 | 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 | 28531 | if (coerce_ok) { |
| 27878 | 28532 | return ComptimePtrMutationKit{ |
| 27879 | .decl_ref_mut = decl_ref_mut, | |
| 28533 | .mut_decl = mut_decl, | |
| 27880 | 28534 | .pointee = .{ .direct = decl_val }, |
| 27881 | 28535 | .ty = decl_ty, |
| 27882 | 28536 | }; |
| 27883 | 28537 | } |
| 27884 | 28538 | |
| 27885 | 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()) { | |
| 27887 | const decl_elem_ty = decl_ty.childType(); | |
| 28540 | if (decl_ty.isArrayOrVector(mod)) { | |
| 28541 | const decl_elem_ty = decl_ty.childType(mod); | |
| 27888 | 28542 | if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) { |
| 27889 | 28543 | return ComptimePtrMutationKit{ |
| 27890 | .decl_ref_mut = decl_ref_mut, | |
| 28544 | .mut_decl = mut_decl, | |
| 27891 | 28545 | .pointee = .{ .direct = decl_val }, |
| 27892 | 28546 | .ty = decl_ty, |
| 27893 | 28547 | }; |
| 27894 | 28548 | } |
| 27895 | 28549 | } |
| 27896 | 28550 | |
| 27897 | if (!decl_ty.hasWellDefinedLayout()) { | |
| 28551 | if (!decl_ty.hasWellDefinedLayout(mod)) { | |
| 27898 | 28552 | return ComptimePtrMutationKit{ |
| 27899 | .decl_ref_mut = decl_ref_mut, | |
| 27900 | .pointee = .{ .bad_decl_ty = {} }, | |
| 28553 | .mut_decl = mut_decl, | |
| 28554 | .pointee = .bad_decl_ty, | |
| 27901 | 28555 | .ty = decl_ty, |
| 27902 | 28556 | }; |
| 27903 | 28557 | } |
| 27904 | if (!ptr_elem_ty.hasWellDefinedLayout()) { | |
| 28558 | if (!ptr_elem_ty.hasWellDefinedLayout(mod)) { | |
| 27905 | 28559 | return ComptimePtrMutationKit{ |
| 27906 | .decl_ref_mut = decl_ref_mut, | |
| 27907 | .pointee = .{ .bad_ptr_ty = {} }, | |
| 28560 | .mut_decl = mut_decl, | |
| 28561 | .pointee = .bad_ptr_ty, | |
| 27908 | 28562 | .ty = ptr_elem_ty, |
| 27909 | 28563 | }; |
| 27910 | 28564 | } |
| 27911 | 28565 | return ComptimePtrMutationKit{ |
| 27912 | .decl_ref_mut = decl_ref_mut, | |
| 28566 | .mut_decl = mut_decl, | |
| 27913 | 28567 | .pointee = .{ .reinterpret = .{ |
| 27914 | 28568 | .val_ptr = decl_val, |
| 27915 | 28569 | .byte_offset = 0, |
| ... | ... | @@ -27951,237 +28605,227 @@ fn beginComptimePtrLoad( |
| 27951 | 28605 | ptr_val: Value, |
| 27952 | 28606 | maybe_array_ty: ?Type, |
| 27953 | 28607 | ) ComptimePtrLoadError!ComptimePtrLoadKit { |
| 27954 | const target = sema.mod.getTarget(); | |
| 27955 | var deref: ComptimePtrLoadKit = switch (ptr_val.tag()) { | |
| 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 | }, | |
| 28608 | const mod = sema.mod; | |
| 28609 | const target = mod.getTarget(); | |
| 28055 | 28610 | |
| 28056 | .field_ptr => blk: { | |
| 28057 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 28058 | const field_index = @intCast(u32, field_ptr.field_index); | |
| 28059 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.container_ptr, field_ptr.container_ty); | |
| 28611 | var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { | |
| 28612 | .ptr => |ptr| switch (ptr.addr) { | |
| 28613 | .decl, .mut_decl => blk: { | |
| 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()) { | |
| 28062 | const struct_ty = field_ptr.container_ty.castTag(.@"struct"); | |
| 28063 | if (struct_ty != null and struct_ty.?.data.layout == .Packed) { | |
| 28064 | // packed structs are not byte addressable | |
| 28642 | // eu_payload and opt_payload never have a well-defined layout | |
| 28643 | if (deref.parent != null) { | |
| 28065 | 28644 | deref.parent = null; |
| 28066 | } else if (deref.parent) |*parent| { | |
| 28067 | // Update the byte offset (in-place) | |
| 28068 | try sema.resolveTypeLayout(field_ptr.container_ty); | |
| 28069 | const field_offset = field_ptr.container_ty.structFieldOffset(field_index, target); | |
| 28070 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); | |
| 28645 | deref.ty_without_well_defined_layout = container_ty; | |
| 28646 | } | |
| 28647 | ||
| 28648 | if (deref.pointee) |*tv| { | |
| 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 | 28677 | deref.pointee = null; |
| 28086 | 28678 | break :blk deref; |
| 28087 | } | |
| 28088 | ||
| 28089 | if (field_ptr.container_ty.isSlice()) { | |
| 28090 | const slice_val = tv.val.castTag(.slice).?.data; | |
| 28091 | deref.pointee = switch (field_index) { | |
| 28092 | Value.Payload.Slice.ptr_index => TypedValue{ | |
| 28093 | .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | |
| 28094 | .val = slice_val.ptr, | |
| 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), | |
| 28679 | }, | |
| 28680 | .comptime_field => |comptime_field| blk: { | |
| 28681 | const field_ty = mod.intern_pool.typeOf(comptime_field).toType(); | |
| 28682 | break :blk ComptimePtrLoadKit{ | |
| 28683 | .parent = null, | |
| 28684 | .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() }, | |
| 28685 | .is_mutable = false, | |
| 28686 | .ty_without_well_defined_layout = field_ty, | |
| 28107 | 28687 | }; |
| 28108 | } | |
| 28109 | break :blk deref; | |
| 28110 | }, | |
| 28688 | }, | |
| 28689 | .elem => |elem_ptr| blk: { | |
| 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: { | |
| 28113 | const comptime_field_ptr = ptr_val.castTag(.comptime_field_ptr).?.data; | |
| 28114 | break :blk ComptimePtrLoadKit{ | |
| 28115 | .parent = null, | |
| 28116 | .pointee = .{ .ty = comptime_field_ptr.field_ty, .val = comptime_field_ptr.field_val }, | |
| 28117 | .is_mutable = false, | |
| 28118 | .ty_without_well_defined_layout = comptime_field_ptr.field_ty, | |
| 28119 | }; | |
| 28120 | }, | |
| 28704 | if (elem_ptr.index != 0) { | |
| 28705 | if (elem_ty.hasWellDefinedLayout(mod)) { | |
| 28706 | if (deref.parent) |*parent| { | |
| 28707 | // Update the byte offset (in-place) | |
| 28708 | const elem_size = try sema.typeAbiSize(elem_ty); | |
| 28709 | const offset = parent.byte_offset + elem_size * elem_ptr.index; | |
| 28710 | parent.byte_offset = try sema.usizeCast(block, src, offset); | |
| 28711 | } | |
| 28712 | } else { | |
| 28713 | deref.parent = null; | |
| 28714 | deref.ty_without_well_defined_layout = elem_ty; | |
| 28715 | } | |
| 28716 | } | |
| 28121 | 28717 | |
| 28122 | .opt_payload_ptr, | |
| 28123 | .eu_payload_ptr, | |
| 28124 | => blk: { | |
| 28125 | const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; | |
| 28126 | const payload_ty = switch (ptr_val.tag()) { | |
| 28127 | .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(), | |
| 28128 | .opt_payload_ptr => try payload_ptr.container_ty.optionalChildAlloc(sema.arena), | |
| 28129 | else => unreachable, | |
| 28130 | }; | |
| 28131 | var deref = try sema.beginComptimePtrLoad(block, src, payload_ptr.container_ptr, payload_ptr.container_ty); | |
| 28718 | // If we're loading an elem that was derived from a different type | |
| 28719 | // than the true type of the underlying decl, we cannot deref directly | |
| 28720 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { | |
| 28721 | const deref_elem_ty = deref.pointee.?.ty.childType(mod); | |
| 28722 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or | |
| 28723 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; | |
| 28724 | } else false; | |
| 28725 | if (!ty_matches) { | |
| 28726 | deref.pointee = null; | |
| 28727 | break :blk deref; | |
| 28728 | } | |
| 28132 | 28729 | |
| 28133 | // eu_payload_ptr and opt_payload_ptr never have a well-defined layout | |
| 28134 | if (deref.parent != null) { | |
| 28135 | deref.parent = null; | |
| 28136 | deref.ty_without_well_defined_layout = payload_ptr.container_ty; | |
| 28137 | } | |
| 28730 | var array_tv = deref.pointee.?; | |
| 28731 | const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); | |
| 28732 | if (maybe_array_ty) |load_ty| { | |
| 28733 | // It's possible that we're loading a [N]T, in which case we'd like to slice | |
| 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 | 28790 | const coerce_in_mem_ok = |
| 28141 | (try sema.coerceInMemoryAllowed(block, payload_ptr.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; | |
| 28143 | if (coerce_in_mem_ok) { | |
| 28144 | const payload_val = switch (ptr_val.tag()) { | |
| 28145 | .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else { | |
| 28146 | return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name}); | |
| 28791 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28792 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; | |
| 28793 | if (!coerce_in_mem_ok) { | |
| 28794 | deref.pointee = null; | |
| 28795 | break :blk deref; | |
| 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: { | |
| 28149 | if (tv.val.isNull()) return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28150 | break :opt tv.val; | |
| 28804 | Value.slice_len_index => TypedValue{ | |
| 28805 | .ty = Type.usize, | |
| 28806 | .val = mod.intern_pool.indexToKey(tv.val.toIntern()).ptr.len.toValue(), | |
| 28151 | 28807 | }, |
| 28152 | 28808 | else => unreachable, |
| 28153 | 28809 | }; |
| 28154 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; | |
| 28155 | break :blk deref; | |
| 28810 | } else { | |
| 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 | } | |
| 28158 | deref.pointee = null; | |
| 28159 | break :blk deref; | |
| 28160 | }, | |
| 28161 | .null_value => { | |
| 28162 | return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28817 | break :blk deref; | |
| 28818 | }, | |
| 28163 | 28819 | }, |
| 28164 | .opt_payload => blk: { | |
| 28165 | const opt_payload = ptr_val.castTag(.opt_payload).?.data; | |
| 28166 | break :blk try sema.beginComptimePtrLoad(block, src, opt_payload, null); | |
| 28820 | .opt => |opt| switch (opt.val) { | |
| 28821 | .none => return sema.fail(block, src, "attempt to use null value", .{}), | |
| 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 | 28824 | else => unreachable, |
| 28181 | 28825 | }; |
| 28182 | 28826 | |
| 28183 | 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 | 28829 | deref.parent = .{ .tv = tv, .byte_offset = 0 }; |
| 28186 | 28830 | } |
| 28187 | 28831 | } |
| ... | ... | @@ -28196,21 +28840,21 @@ fn bitCast( |
| 28196 | 28840 | inst_src: LazySrcLoc, |
| 28197 | 28841 | operand_src: ?LazySrcLoc, |
| 28198 | 28842 | ) CompileError!Air.Inst.Ref { |
| 28843 | const mod = sema.mod; | |
| 28199 | 28844 | const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); |
| 28200 | 28845 | try sema.resolveTypeLayout(dest_ty); |
| 28201 | 28846 | |
| 28202 | 28847 | const old_ty = try sema.resolveTypeFields(sema.typeOf(inst)); |
| 28203 | 28848 | try sema.resolveTypeLayout(old_ty); |
| 28204 | 28849 | |
| 28205 | const target = sema.mod.getTarget(); | |
| 28206 | const dest_bits = dest_ty.bitSize(target); | |
| 28207 | const old_bits = old_ty.bitSize(target); | |
| 28850 | const dest_bits = dest_ty.bitSize(mod); | |
| 28851 | const old_bits = old_ty.bitSize(mod); | |
| 28208 | 28852 | |
| 28209 | 28853 | if (old_bits != dest_bits) { |
| 28210 | 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 | 28856 | dest_bits, |
| 28213 | old_ty.fmt(sema.mod), | |
| 28857 | old_ty.fmt(mod), | |
| 28214 | 28858 | old_bits, |
| 28215 | 28859 | }); |
| 28216 | 28860 | } |
| ... | ... | @@ -28233,20 +28877,21 @@ fn bitCastVal( |
| 28233 | 28877 | new_ty: Type, |
| 28234 | 28878 | buffer_offset: usize, |
| 28235 | 28879 | ) !?Value { |
| 28236 | const target = sema.mod.getTarget(); | |
| 28237 | if (old_ty.eql(new_ty, sema.mod)) return val; | |
| 28880 | const mod = sema.mod; | |
| 28881 | if (old_ty.eql(new_ty, mod)) return val; | |
| 28238 | 28882 | |
| 28239 | 28883 | // For types with well-defined memory layouts, we serialize them a byte buffer, |
| 28240 | 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 | 28886 | const buffer = try sema.gpa.alloc(u8, abi_size); |
| 28243 | 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 | 28890 | error.ReinterpretDeclRef => return null, |
| 28246 | 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 | 28897 | fn coerceArrayPtrToSlice( |
| ... | ... | @@ -28256,25 +28901,32 @@ fn coerceArrayPtrToSlice( |
| 28256 | 28901 | inst: Air.Inst.Ref, |
| 28257 | 28902 | inst_src: LazySrcLoc, |
| 28258 | 28903 | ) CompileError!Air.Inst.Ref { |
| 28904 | const mod = sema.mod; | |
| 28259 | 28905 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 28260 | 28906 | const ptr_array_ty = sema.typeOf(inst); |
| 28261 | const array_ty = ptr_array_ty.childType(); | |
| 28262 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | |
| 28263 | .ptr = val, | |
| 28264 | .len = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()), | |
| 28265 | }); | |
| 28266 | return sema.addConstant(dest_ty, slice_val); | |
| 28907 | const array_ty = ptr_array_ty.childType(mod); | |
| 28908 | const slice_val = try mod.intern(.{ .ptr = .{ | |
| 28909 | .ty = dest_ty.toIntern(), | |
| 28910 | .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 28911 | .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) }, | |
| 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 | 28919 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28269 | 28920 | return block.addTyOp(.array_to_slice, dest_ty, inst); |
| 28270 | 28921 | } |
| 28271 | 28922 | |
| 28272 | 28923 | fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool { |
| 28273 | const dest_info = dest_ty.ptrInfo().data; | |
| 28274 | const inst_info = inst_ty.ptrInfo().data; | |
| 28275 | const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or | |
| 28276 | (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or | |
| 28277 | (inst_info.pointee_type.isTuple() and inst_info.pointee_type.structFieldCount() == 0); | |
| 28924 | const mod = sema.mod; | |
| 28925 | const dest_info = dest_ty.ptrInfo(mod); | |
| 28926 | const inst_info = inst_ty.ptrInfo(mod); | |
| 28927 | const len0 = (inst_info.pointee_type.zigTypeTag(mod) == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel(mod) == 0 or | |
| 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 | 28931 | const ok_cv_qualifiers = |
| 28280 | 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 | 28950 | } |
| 28299 | 28951 | if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true; |
| 28300 | 28952 | if (len0) return true; |
| 28301 | const target = sema.mod.getTarget(); | |
| 28302 | 28953 | |
| 28303 | 28954 | const inst_align = if (inst_info.@"align" != 0) |
| 28304 | 28955 | inst_info.@"align" |
| 28305 | 28956 | else |
| 28306 | inst_info.pointee_type.abiAlignment(target); | |
| 28957 | inst_info.pointee_type.abiAlignment(mod); | |
| 28307 | 28958 | |
| 28308 | 28959 | const dest_align = if (dest_info.@"align" != 0) |
| 28309 | 28960 | dest_info.@"align" |
| 28310 | 28961 | else |
| 28311 | dest_info.pointee_type.abiAlignment(target); | |
| 28962 | dest_info.pointee_type.abiAlignment(mod); | |
| 28312 | 28963 | |
| 28313 | 28964 | if (dest_align > inst_align) { |
| 28314 | 28965 | in_memory_result.* = .{ .ptr_alignment = .{ |
| ... | ... | @@ -28327,26 +28978,30 @@ fn coerceCompatiblePtrs( |
| 28327 | 28978 | inst: Air.Inst.Ref, |
| 28328 | 28979 | inst_src: LazySrcLoc, |
| 28329 | 28980 | ) !Air.Inst.Ref { |
| 28981 | const mod = sema.mod; | |
| 28330 | 28982 | const inst_ty = sema.typeOf(inst); |
| 28331 | 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 | 28985 | return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); |
| 28334 | 28986 | } |
| 28335 | 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 | 28993 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28339 | const inst_allows_zero = inst_ty.zigTypeTag() != .Pointer or inst_ty.ptrAllowsZero(); | |
| 28340 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and | |
| 28341 | (try sema.typeHasRuntimeBits(dest_ty.elemType2()) or dest_ty.elemType2().zigTypeTag() == .Fn)) | |
| 28994 | const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod); | |
| 28995 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(mod) and | |
| 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 | 28999 | try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) |
| 28345 | 29000 | else |
| 28346 | 29001 | inst; |
| 28347 | 29002 | const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); |
| 28348 | 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 | 29005 | const len = try sema.analyzeSliceLen(block, inst_src, inst); |
| 28351 | 29006 | const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); |
| 28352 | 29007 | break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); |
| ... | ... | @@ -28364,9 +29019,11 @@ fn coerceEnumToUnion( |
| 28364 | 29019 | inst: Air.Inst.Ref, |
| 28365 | 29020 | inst_src: LazySrcLoc, |
| 28366 | 29021 | ) !Air.Inst.Ref { |
| 29022 | const mod = sema.mod; | |
| 29023 | const ip = &mod.intern_pool; | |
| 28367 | 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 | 29027 | const msg = msg: { |
| 28371 | 29028 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ |
| 28372 | 29029 | union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), |
| ... | ... | @@ -28393,16 +29050,18 @@ fn coerceEnumToUnion( |
| 28393 | 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 | 29054 | const field = union_obj.fields.values()[field_index]; |
| 28398 | 29055 | const field_ty = try sema.resolveTypeFields(field.ty); |
| 28399 | if (field_ty.zigTypeTag() == .NoReturn) { | |
| 29056 | if (field_ty.zigTypeTag(mod) == .NoReturn) { | |
| 28400 | 29057 | const msg = msg: { |
| 28401 | 29058 | const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); |
| 28402 | 29059 | errdefer msg.destroy(sema.gpa); |
| 28403 | 29060 | |
| 28404 | 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 | 29065 | try sema.addDeclaredHereNote(msg, union_ty); |
| 28407 | 29066 | break :msg msg; |
| 28408 | 29067 | }; |
| ... | ... | @@ -28411,27 +29070,27 @@ fn coerceEnumToUnion( |
| 28411 | 29070 | const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { |
| 28412 | 29071 | const msg = msg: { |
| 28413 | 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}'", .{ | |
| 28415 | inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), field_ty.fmt(sema.mod), field_name, | |
| 29073 | const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{ | |
| 29074 | inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), | |
| 29075 | field_ty.fmt(sema.mod), field_name.fmt(ip), | |
| 28416 | 29076 | }); |
| 28417 | 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 | 29082 | try sema.addDeclaredHereNote(msg, union_ty); |
| 28421 | 29083 | break :msg msg; |
| 28422 | 29084 | }; |
| 28423 | 29085 | return sema.failWithOwnedErrorMsg(msg); |
| 28424 | 29086 | }; |
| 28425 | 29087 | |
| 28426 | return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{ | |
| 28427 | .tag = val, | |
| 28428 | .val = opv, | |
| 28429 | })); | |
| 29088 | return sema.addConstant(union_ty, try mod.unionValue(union_ty, val, opv)); | |
| 28430 | 29089 | } |
| 28431 | 29090 | |
| 28432 | 29091 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28433 | 29092 | |
| 28434 | if (tag_ty.isNonexhaustiveEnum()) { | |
| 29093 | if (tag_ty.isNonexhaustiveEnum(mod)) { | |
| 28435 | 29094 | const msg = msg: { |
| 28436 | 29095 | const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{ |
| 28437 | 29096 | union_ty.fmt(sema.mod), |
| ... | ... | @@ -28443,13 +29102,13 @@ fn coerceEnumToUnion( |
| 28443 | 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 | 29107 | var msg: ?*Module.ErrorMsg = null; |
| 28449 | 29108 | errdefer if (msg) |some| some.destroy(sema.gpa); |
| 28450 | 29109 | |
| 28451 | 29110 | for (union_obj.fields.values(), 0..) |field, i| { |
| 28452 | if (field.ty.zigTypeTag() == .NoReturn) { | |
| 29111 | if (field.ty.zigTypeTag(mod) == .NoReturn) { | |
| 28453 | 29112 | const err_msg = msg orelse try sema.errMsg( |
| 28454 | 29113 | block, |
| 28455 | 29114 | inst_src, |
| ... | ... | @@ -28469,7 +29128,7 @@ fn coerceEnumToUnion( |
| 28469 | 29128 | } |
| 28470 | 29129 | |
| 28471 | 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 | 29132 | return block.addBitCast(union_ty, enum_tag); |
| 28474 | 29133 | } |
| 28475 | 29134 | |
| ... | ... | @@ -28487,8 +29146,11 @@ fn coerceEnumToUnion( |
| 28487 | 29146 | while (it.next()) |field| : (field_index += 1) { |
| 28488 | 29147 | const field_name = field.key_ptr.*; |
| 28489 | 29148 | const field_ty = field.value_ptr.ty; |
| 28490 | if (!field_ty.hasRuntimeBits()) continue; | |
| 28491 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); | |
| 29149 | if (!(try sema.typeHasRuntimeBits(field_ty))) continue; | |
| 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 | 29155 | try sema.addDeclaredHereNote(msg, union_ty); |
| 28494 | 29156 | break :msg msg; |
| ... | ... | @@ -28504,36 +29166,55 @@ fn coerceAnonStructToUnion( |
| 28504 | 29166 | inst: Air.Inst.Ref, |
| 28505 | 29167 | inst_src: LazySrcLoc, |
| 28506 | 29168 | ) !Air.Inst.Ref { |
| 29169 | const mod = sema.mod; | |
| 28507 | 29170 | const inst_ty = sema.typeOf(inst); |
| 28508 | const field_count = inst_ty.structFieldCount(); | |
| 28509 | if (field_count != 1) { | |
| 28510 | const msg = msg: { | |
| 28511 | const msg = if (field_count > 1) try sema.errMsg( | |
| 28512 | block, | |
| 28513 | inst_src, | |
| 28514 | "cannot initialize multiple union fields at once; unions can only have one active field", | |
| 28515 | .{}, | |
| 28516 | ) else try sema.errMsg( | |
| 28517 | block, | |
| 28518 | inst_src, | |
| 28519 | "union initializer must initialize one field", | |
| 28520 | .{}, | |
| 28521 | ); | |
| 28522 | errdefer msg.destroy(sema.gpa); | |
| 29171 | const field_info: union(enum) { | |
| 29172 | name: InternPool.NullTerminatedString, | |
| 29173 | count: usize, | |
| 29174 | } = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { | |
| 29175 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 1) | |
| 29176 | .{ .name = anon_struct_type.names[0] } | |
| 29177 | else | |
| 29178 | .{ .count = anon_struct_type.names.len }, | |
| 29179 | .struct_type => |struct_type| name: { | |
| 29180 | const field_names = mod.structPtrUnwrap(struct_type.index).?.fields.keys(); | |
| 29181 | break :name if (field_names.len == 1) | |
| 29182 | .{ .name = field_names[0] } | |
| 29183 | else | |
| 29184 | .{ .count = field_names.len }; | |
| 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 | |
| 28525 | // the extra fields. | |
| 29209 | // TODO add notes for where the anon struct was created to point out | |
| 29210 | // the extra fields. | |
| 28526 | 29211 | |
| 28527 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 28528 | break :msg msg; | |
| 28529 | }; | |
| 28530 | return sema.failWithOwnedErrorMsg(msg); | |
| 29212 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 29213 | break :msg msg; | |
| 29214 | }; | |
| 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 | 29220 | fn coerceAnonStructToUnionPtrs( |
| ... | ... | @@ -28544,7 +29225,8 @@ fn coerceAnonStructToUnionPtrs( |
| 28544 | 29225 | ptr_anon_struct: Air.Inst.Ref, |
| 28545 | 29226 | anon_struct_src: LazySrcLoc, |
| 28546 | 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 | 29230 | const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); |
| 28549 | 29231 | const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src); |
| 28550 | 29232 | return sema.analyzeRef(block, union_ty_src, union_inst); |
| ... | ... | @@ -28558,7 +29240,8 @@ fn coerceAnonStructToStructPtrs( |
| 28558 | 29240 | ptr_anon_struct: Air.Inst.Ref, |
| 28559 | 29241 | anon_struct_src: LazySrcLoc, |
| 28560 | 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 | 29245 | const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); |
| 28563 | 29246 | const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, anon_struct, anon_struct_src); |
| 28564 | 29247 | return sema.analyzeRef(block, struct_ty_src, struct_inst); |
| ... | ... | @@ -28573,15 +29256,16 @@ fn coerceArrayLike( |
| 28573 | 29256 | inst: Air.Inst.Ref, |
| 28574 | 29257 | inst_src: LazySrcLoc, |
| 28575 | 29258 | ) !Air.Inst.Ref { |
| 29259 | const mod = sema.mod; | |
| 28576 | 29260 | const inst_ty = sema.typeOf(inst); |
| 28577 | const inst_len = inst_ty.arrayLen(); | |
| 28578 | const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen()); | |
| 28579 | const target = sema.mod.getTarget(); | |
| 29261 | const inst_len = inst_ty.arrayLen(mod); | |
| 29262 | const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(mod)); | |
| 29263 | const target = mod.getTarget(); | |
| 28580 | 29264 | |
| 28581 | 29265 | if (dest_len != inst_len) { |
| 28582 | 29266 | const msg = msg: { |
| 28583 | 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 | 29270 | errdefer msg.destroy(sema.gpa); |
| 28587 | 29271 | try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); |
| ... | ... | @@ -28591,35 +29275,32 @@ fn coerceArrayLike( |
| 28591 | 29275 | return sema.failWithOwnedErrorMsg(msg); |
| 28592 | 29276 | } |
| 28593 | 29277 | |
| 28594 | const dest_elem_ty = dest_ty.childType(); | |
| 28595 | const inst_elem_ty = inst_ty.childType(); | |
| 29278 | const dest_elem_ty = dest_ty.childType(mod); | |
| 29279 | const inst_elem_ty = inst_ty.childType(mod); | |
| 28596 | 29280 | const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src); |
| 28597 | 29281 | if (in_memory_result == .ok) { |
| 28598 | 29282 | if (try sema.resolveMaybeUndefVal(inst)) |inst_val| { |
| 28599 | 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 | 29286 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28603 | 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 | 29291 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len); |
| 28608 | 29292 | var runtime_src: ?LazySrcLoc = null; |
| 28609 | 29293 | |
| 28610 | for (element_vals, 0..) |*elem, i| { | |
| 28611 | const index_ref = try sema.addConstant( | |
| 28612 | Type.usize, | |
| 28613 | try Value.Tag.int_u64.create(sema.arena, i), | |
| 28614 | ); | |
| 29294 | for (element_vals, element_refs, 0..) |*val, *ref, i| { | |
| 29295 | const index_ref = try sema.addConstant(Type.usize, try mod.intValue(Type.usize, i)); | |
| 28615 | 29296 | const src = inst_src; // TODO better source location |
| 28616 | 29297 | const elem_src = inst_src; // TODO better source location |
| 28617 | 29298 | const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true); |
| 28618 | 29299 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); |
| 28619 | element_refs[i] = coerced; | |
| 29300 | ref.* = coerced; | |
| 28620 | 29301 | if (runtime_src == null) { |
| 28621 | 29302 | if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| { |
| 28622 | elem.* = elem_val; | |
| 29303 | val.* = try elem_val.intern(dest_elem_ty, mod); | |
| 28623 | 29304 | } else { |
| 28624 | 29305 | runtime_src = elem_src; |
| 28625 | 29306 | } |
| ... | ... | @@ -28631,10 +29312,10 @@ fn coerceArrayLike( |
| 28631 | 29312 | return block.addAggregateInit(dest_ty, element_refs); |
| 28632 | 29313 | } |
| 28633 | 29314 | |
| 28634 | return sema.addConstant( | |
| 28635 | dest_ty, | |
| 28636 | try Value.Tag.aggregate.create(sema.arena, element_vals), | |
| 28637 | ); | |
| 29315 | return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ | |
| 29316 | .ty = dest_ty.toIntern(), | |
| 29317 | .storage = .{ .elems = element_vals }, | |
| 29318 | } })).toValue()); | |
| 28638 | 29319 | } |
| 28639 | 29320 | |
| 28640 | 29321 | /// If the lengths match, coerces element-wise. |
| ... | ... | @@ -28646,9 +29327,10 @@ fn coerceTupleToArray( |
| 28646 | 29327 | inst: Air.Inst.Ref, |
| 28647 | 29328 | inst_src: LazySrcLoc, |
| 28648 | 29329 | ) !Air.Inst.Ref { |
| 29330 | const mod = sema.mod; | |
| 28649 | 29331 | const inst_ty = sema.typeOf(inst); |
| 28650 | const inst_len = inst_ty.arrayLen(); | |
| 28651 | const dest_len = dest_ty.arrayLen(); | |
| 29332 | const inst_len = inst_ty.arrayLen(mod); | |
| 29333 | const dest_len = dest_ty.arrayLen(mod); | |
| 28652 | 29334 | |
| 28653 | 29335 | if (dest_len != inst_len) { |
| 28654 | 29336 | const msg = msg: { |
| ... | ... | @@ -28663,26 +29345,27 @@ fn coerceTupleToArray( |
| 28663 | 29345 | return sema.failWithOwnedErrorMsg(msg); |
| 28664 | 29346 | } |
| 28665 | 29347 | |
| 28666 | const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLenIncludingSentinel()); | |
| 28667 | const element_vals = try sema.arena.alloc(Value, dest_elems); | |
| 29348 | const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_len); | |
| 29349 | const element_vals = try sema.arena.alloc(InternPool.Index, dest_elems); | |
| 28668 | 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 | 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 | 29355 | const i = @intCast(u32, i_usize); |
| 28674 | 29356 | if (i_usize == inst_len) { |
| 28675 | elem.* = dest_ty.sentinel().?; | |
| 28676 | element_refs[i] = try sema.addConstant(dest_elem_ty, elem.*); | |
| 29357 | const sentinel_val = dest_ty.sentinel(mod).?; | |
| 29358 | val.* = sentinel_val.toIntern(); | |
| 29359 | ref.* = try sema.addConstant(dest_elem_ty, sentinel_val); | |
| 28677 | 29360 | break; |
| 28678 | 29361 | } |
| 28679 | 29362 | const elem_src = inst_src; // TODO better source location |
| 28680 | 29363 | const elem_ref = try sema.tupleField(block, inst_src, inst, elem_src, i); |
| 28681 | 29364 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); |
| 28682 | element_refs[i] = coerced; | |
| 29365 | ref.* = coerced; | |
| 28683 | 29366 | if (runtime_src == null) { |
| 28684 | 29367 | if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| { |
| 28685 | elem.* = elem_val; | |
| 29368 | val.* = try elem_val.intern(dest_elem_ty, mod); | |
| 28686 | 29369 | } else { |
| 28687 | 29370 | runtime_src = elem_src; |
| 28688 | 29371 | } |
| ... | ... | @@ -28694,10 +29377,10 @@ fn coerceTupleToArray( |
| 28694 | 29377 | return block.addAggregateInit(dest_ty, element_refs); |
| 28695 | 29378 | } |
| 28696 | 29379 | |
| 28697 | return sema.addConstant( | |
| 28698 | dest_ty, | |
| 28699 | try Value.Tag.aggregate.create(sema.arena, element_vals), | |
| 28700 | ); | |
| 29380 | return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ | |
| 29381 | .ty = dest_ty.toIntern(), | |
| 29382 | .storage = .{ .elems = element_vals }, | |
| 29383 | } })).toValue()); | |
| 28701 | 29384 | } |
| 28702 | 29385 | |
| 28703 | 29386 | /// If the lengths match, coerces element-wise. |
| ... | ... | @@ -28709,10 +29392,11 @@ fn coerceTupleToSlicePtrs( |
| 28709 | 29392 | ptr_tuple: Air.Inst.Ref, |
| 28710 | 29393 | tuple_src: LazySrcLoc, |
| 28711 | 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 | 29397 | const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); |
| 28714 | const slice_info = slice_ty.ptrInfo().data; | |
| 28715 | const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type, sema.mod); | |
| 29398 | const slice_info = slice_ty.ptrInfo(mod); | |
| 29399 | const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(mod), slice_info.sentinel, slice_info.pointee_type, sema.mod); | |
| 28716 | 29400 | const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src); |
| 28717 | 29401 | if (slice_info.@"align" != 0) { |
| 28718 | 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 | 29414 | ptr_tuple: Air.Inst.Ref, |
| 28731 | 29415 | tuple_src: LazySrcLoc, |
| 28732 | 29416 | ) !Air.Inst.Ref { |
| 29417 | const mod = sema.mod; | |
| 28733 | 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 | 29420 | const array_ty = ptr_info.pointee_type; |
| 28736 | 29421 | const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src); |
| 28737 | 29422 | if (ptr_info.@"align" != 0) { |
| ... | ... | @@ -28750,27 +29435,41 @@ fn coerceTupleToStruct( |
| 28750 | 29435 | inst: Air.Inst.Ref, |
| 28751 | 29436 | inst_src: LazySrcLoc, |
| 28752 | 29437 | ) !Air.Inst.Ref { |
| 29438 | const mod = sema.mod; | |
| 29439 | const ip = &mod.intern_pool; | |
| 28753 | 29440 | const struct_ty = try sema.resolveTypeFields(dest_ty); |
| 28754 | 29441 | |
| 28755 | if (struct_ty.isTupleOrAnonStruct()) { | |
| 29442 | if (struct_ty.isTupleOrAnonStruct(mod)) { | |
| 28756 | 29443 | return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); |
| 28757 | 29444 | } |
| 28758 | 29445 | |
| 28759 | const fields = struct_ty.structFields(); | |
| 28760 | const field_vals = try sema.arena.alloc(Value, fields.count()); | |
| 29446 | const fields = struct_ty.structFields(mod); | |
| 29447 | const field_vals = try sema.arena.alloc(InternPool.Index, fields.count()); | |
| 28761 | 29448 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 28762 | 29449 | @memset(field_refs, .none); |
| 28763 | 29450 | |
| 28764 | 29451 | const inst_ty = sema.typeOf(inst); |
| 28765 | 29452 | var runtime_src: ?LazySrcLoc = null; |
| 28766 | const field_count = inst_ty.structFieldCount(); | |
| 28767 | var field_i: u32 = 0; | |
| 28768 | while (field_i < field_count) : (field_i += 1) { | |
| 28769 | const field_src = inst_src; // TODO better source location | |
| 28770 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | |
| 28771 | payload.data.names[field_i] | |
| 29453 | const field_count = switch (ip.indexToKey(inst_ty.toIntern())) { | |
| 29454 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | |
| 29455 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| | |
| 29456 | struct_obj.fields.count() | |
| 28772 | 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 | 29473 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| 28775 | 29474 | const field = fields.values()[field_index]; |
| 28776 | 29475 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| ... | ... | @@ -28781,13 +29480,13 @@ fn coerceTupleToStruct( |
| 28781 | 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 | 29484 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 28786 | 29485 | } |
| 28787 | 29486 | } |
| 28788 | 29487 | if (runtime_src == null) { |
| 28789 | 29488 | if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { |
| 28790 | field_vals[field_index] = field_val; | |
| 29489 | field_vals[field_index] = field_val.toIntern(); | |
| 28791 | 29490 | } else { |
| 28792 | 29491 | runtime_src = field_src; |
| 28793 | 29492 | } |
| ... | ... | @@ -28804,9 +29503,9 @@ fn coerceTupleToStruct( |
| 28804 | 29503 | const field_name = fields.keys()[i]; |
| 28805 | 29504 | const field = fields.values()[i]; |
| 28806 | 29505 | const field_src = inst_src; // TODO better source location |
| 28807 | if (field.default_val.tag() == .unreachable_value) { | |
| 28808 | const template = "missing struct field: {s}"; | |
| 28809 | const args = .{field_name}; | |
| 29506 | if (field.default_val == .none) { | |
| 29507 | const template = "missing struct field: {}"; | |
| 29508 | const args = .{field_name.fmt(ip)}; | |
| 28810 | 29509 | if (root_msg) |msg| { |
| 28811 | 29510 | try sema.errNote(block, field_src, msg, template, args); |
| 28812 | 29511 | } else { |
| ... | ... | @@ -28817,7 +29516,7 @@ fn coerceTupleToStruct( |
| 28817 | 29516 | if (runtime_src == null) { |
| 28818 | 29517 | field_vals[i] = field.default_val; |
| 28819 | 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 | 29531 | return block.addAggregateInit(struct_ty, field_refs); |
| 28833 | 29532 | } |
| 28834 | 29533 | |
| 28835 | return sema.addConstant( | |
| 28836 | struct_ty, | |
| 28837 | try Value.Tag.aggregate.create(sema.arena, field_vals), | |
| 28838 | ); | |
| 29534 | const struct_val = try mod.intern(.{ .aggregate = .{ | |
| 29535 | .ty = struct_ty.toIntern(), | |
| 29536 | .storage = .{ .elems = field_vals }, | |
| 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 | 29544 | fn coerceTupleToTuple( |
| ... | ... | @@ -28845,47 +29548,76 @@ fn coerceTupleToTuple( |
| 28845 | 29548 | inst: Air.Inst.Ref, |
| 28846 | 29549 | inst_src: LazySrcLoc, |
| 28847 | 29550 | ) !Air.Inst.Ref { |
| 28848 | const dest_field_count = tuple_ty.structFieldCount(); | |
| 28849 | const field_vals = try sema.arena.alloc(Value, dest_field_count); | |
| 29551 | const mod = sema.mod; | |
| 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 | 29562 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 28851 | 29563 | @memset(field_refs, .none); |
| 28852 | 29564 | |
| 28853 | 29565 | const inst_ty = sema.typeOf(inst); |
| 28854 | const inst_field_count = inst_ty.structFieldCount(); | |
| 28855 | if (inst_field_count > dest_field_count) return error.NotCoercible; | |
| 29566 | const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) { | |
| 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 | 29576 | var runtime_src: ?LazySrcLoc = null; |
| 28858 | var field_i: u32 = 0; | |
| 28859 | while (field_i < inst_field_count) : (field_i += 1) { | |
| 29577 | for (0..dest_field_count) |field_index_usize| { | |
| 29578 | const field_i = @intCast(u32, field_index_usize); | |
| 28860 | 29579 | const field_src = inst_src; // TODO better source location |
| 28861 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | |
| 28862 | payload.data.names[field_i] | |
| 28863 | else | |
| 28864 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); | |
| 29580 | // https://github.com/ziglang/zig/issues/15709 | |
| 29581 | const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) { | |
| 29582 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0) | |
| 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 | 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 | 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 | 29606 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| 28875 | 29607 | const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); |
| 28876 | 29608 | field_refs[field_index] = coerced; |
| 28877 | if (default_val.tag() != .unreachable_value) { | |
| 29609 | if (default_val != .none) { | |
| 28878 | 29610 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 28879 | 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 | 29615 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 28884 | 29616 | } |
| 28885 | 29617 | } |
| 28886 | 29618 | if (runtime_src == null) { |
| 28887 | 29619 | if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { |
| 28888 | field_vals[field_index] = field_val; | |
| 29620 | field_vals[field_index] = field_val.toIntern(); | |
| 28889 | 29621 | } else { |
| 28890 | 29622 | runtime_src = field_src; |
| 28891 | 29623 | } |
| ... | ... | @@ -28899,12 +29631,15 @@ fn coerceTupleToTuple( |
| 28899 | 29631 | for (field_refs, 0..) |*field_ref, i| { |
| 28900 | 29632 | if (field_ref.* != .none) continue; |
| 28901 | 29633 | |
| 28902 | const default_val = tuple_ty.structFieldDefaultValue(i); | |
| 28903 | const field_ty = tuple_ty.structFieldType(i); | |
| 29634 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { | |
| 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 | 29640 | const field_src = inst_src; // TODO better source location |
| 28906 | if (default_val.tag() == .unreachable_value) { | |
| 28907 | if (tuple_ty.isTuple()) { | |
| 29641 | if (default_val == .none) { | |
| 29642 | if (tuple_ty.isTuple(mod)) { | |
| 28908 | 29643 | const template = "missing tuple field: {d}"; |
| 28909 | 29644 | if (root_msg) |msg| { |
| 28910 | 29645 | try sema.errNote(block, field_src, msg, template, .{i}); |
| ... | ... | @@ -28913,8 +29648,8 @@ fn coerceTupleToTuple( |
| 28913 | 29648 | } |
| 28914 | 29649 | continue; |
| 28915 | 29650 | } |
| 28916 | const template = "missing struct field: {s}"; | |
| 28917 | const args = .{tuple_ty.structFieldName(i)}; | |
| 29651 | const template = "missing struct field: {}"; | |
| 29652 | const args = .{tuple_ty.structFieldName(i, mod).fmt(ip)}; | |
| 28918 | 29653 | if (root_msg) |msg| { |
| 28919 | 29654 | try sema.errNote(block, field_src, msg, template, args); |
| 28920 | 29655 | } else { |
| ... | ... | @@ -28925,7 +29660,12 @@ fn coerceTupleToTuple( |
| 28925 | 29660 | if (runtime_src == null) { |
| 28926 | 29661 | field_vals[i] = default_val; |
| 28927 | 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 | 29682 | |
| 28943 | 29683 | return sema.addConstant( |
| 28944 | 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 | 29702 | const decl_ref = try sema.analyzeDeclRefInner(decl_index, false); |
| 28960 | 29703 | const result = try sema.analyzeLoad(block, src, decl_ref, src); |
| 28961 | 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 | 29706 | try sema.decl_val_table.put(sema.gpa, decl_index, result); |
| 28964 | 29707 | } |
| 28965 | 29708 | } |
| ... | ... | @@ -28980,13 +29723,14 @@ fn addReferencedBy( |
| 28980 | 29723 | } |
| 28981 | 29724 | |
| 28982 | 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 | 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 | 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 | 29734 | if (sema.owner_func) |owner_func| { |
| 28991 | 29735 | owner_func.state = .dependency_failure; |
| 28992 | 29736 | } else { |
| ... | ... | @@ -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 | 29744 | sema.mod.ensureFuncBodyAnalyzed(func) catch |err| { |
| 29001 | 29745 | if (sema.owner_func) |owner_func| { |
| 29002 | 29746 | owner_func.state = .dependency_failure; |
| ... | ... | @@ -29008,23 +29752,33 @@ fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void { |
| 29008 | 29752 | } |
| 29009 | 29753 | |
| 29010 | 29754 | fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value { |
| 29755 | const mod = sema.mod; | |
| 29011 | 29756 | var anon_decl = try block.startAnonDecl(); |
| 29012 | 29757 | defer anon_decl.deinit(); |
| 29013 | 29758 | const decl = try anon_decl.finish( |
| 29014 | try ty.copy(anon_decl.arena()), | |
| 29015 | try val.copy(anon_decl.arena()), | |
| 29759 | ty, | |
| 29760 | val, | |
| 29016 | 29761 | 0, // default alignment |
| 29017 | 29762 | ); |
| 29018 | 29763 | try sema.maybeQueueFuncBodyAnalysis(decl); |
| 29019 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl); | |
| 29020 | return try Value.Tag.decl_ref.create(sema.arena, decl); | |
| 29764 | try mod.declareDeclDependency(sema.owner_decl_index, 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 | 29772 | fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value { |
| 29024 | const val = opt_val orelse return Value.null; | |
| 29025 | const ptr_val = try sema.refValue(block, ty, val); | |
| 29026 | const result = try Value.Tag.opt_payload.create(sema.arena, ptr_val); | |
| 29027 | return result; | |
| 29773 | const mod = sema.mod; | |
| 29774 | const ptr_anyopaque_ty = try mod.singleConstPtrType(Type.anyopaque); | |
| 29775 | return (try mod.intern(.{ .opt = .{ | |
| 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 | 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 | 29790 | /// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps |
| 29037 | 29791 | /// this function with `analyze_fn_body` set to true. |
| 29038 | 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 | 29795 | try sema.ensureDeclAnalyzed(decl_index); |
| 29041 | 29796 | |
| 29042 | const decl = sema.mod.declPtr(decl_index); | |
| 29797 | const decl = mod.declPtr(decl_index); | |
| 29043 | 29798 | const decl_tv = try decl.typedValue(); |
| 29044 | if (decl_tv.val.castTag(.variable)) |payload| { | |
| 29045 | const variable = payload.data; | |
| 29046 | const ty = try Type.ptr(sema.arena, sema.mod, .{ | |
| 29047 | .pointee_type = decl_tv.ty, | |
| 29048 | .mutable = variable.is_mutable, | |
| 29049 | .@"addrspace" = decl.@"addrspace", | |
| 29050 | .@"align" = decl.@"align", | |
| 29051 | }); | |
| 29052 | return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl_index)); | |
| 29053 | } | |
| 29799 | const ptr_ty = try mod.ptrType(.{ | |
| 29800 | .child = decl_tv.ty.toIntern(), | |
| 29801 | .flags = .{ | |
| 29802 | .alignment = InternPool.Alignment.fromByteUnits(decl.@"align"), | |
| 29803 | .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true, | |
| 29804 | .address_space = decl.@"addrspace", | |
| 29805 | }, | |
| 29806 | }); | |
| 29054 | 29807 | if (analyze_fn_body) { |
| 29055 | 29808 | try sema.maybeQueueFuncBodyAnalysis(decl_index); |
| 29056 | 29809 | } |
| 29057 | return sema.addConstant( | |
| 29058 | try Type.ptr(sema.arena, sema.mod, .{ | |
| 29059 | .pointee_type = decl_tv.ty, | |
| 29060 | .mutable = false, | |
| 29061 | .@"addrspace" = decl.@"addrspace", | |
| 29062 | .@"align" = decl.@"align", | |
| 29063 | }), | |
| 29064 | try Value.Tag.decl_ref.create(sema.arena, decl_index), | |
| 29065 | ); | |
| 29810 | return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{ | |
| 29811 | .ty = ptr_ty.toIntern(), | |
| 29812 | .addr = .{ .decl = decl_index }, | |
| 29813 | } })).toValue()); | |
| 29066 | 29814 | } |
| 29067 | 29815 | |
| 29068 | 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 | 29819 | const tv = try decl.typedValue(); |
| 29071 | if (tv.ty.zigTypeTag() != .Fn) return; | |
| 29820 | if (tv.ty.zigTypeTag(mod) != .Fn) return; | |
| 29072 | 29821 | if (!try sema.fnHasRuntimeBits(tv.ty)) return; |
| 29073 | const func = tv.val.castTag(.function) orelse return; // undef or extern_fn | |
| 29074 | try sema.mod.ensureFuncBodyAnalysisQueued(func.data); | |
| 29822 | const func_index = mod.intern_pool.indexToFunc(tv.val.toIntern()).unwrap() orelse return; // undef or extern_fn | |
| 29823 | try mod.ensureFuncBodyAnalysisQueued(func_index); | |
| 29075 | 29824 | } |
| 29076 | 29825 | |
| 29077 | 29826 | fn analyzeRef( |
| ... | ... | @@ -29083,18 +29832,16 @@ fn analyzeRef( |
| 29083 | 29832 | const operand_ty = sema.typeOf(operand); |
| 29084 | 29833 | |
| 29085 | 29834 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 29086 | switch (val.tag()) { | |
| 29087 | .extern_fn, .function => { | |
| 29088 | const decl_index = val.pointerDecl().?; | |
| 29089 | return sema.analyzeDeclRef(decl_index); | |
| 29090 | }, | |
| 29835 | switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { | |
| 29836 | .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl), | |
| 29837 | .func => |func| return sema.analyzeDeclRef(sema.mod.funcPtr(func.index).owner_decl), | |
| 29091 | 29838 | else => {}, |
| 29092 | 29839 | } |
| 29093 | 29840 | var anon_decl = try block.startAnonDecl(); |
| 29094 | 29841 | defer anon_decl.deinit(); |
| 29095 | 29842 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 29096 | try operand_ty.copy(anon_decl.arena()), | |
| 29097 | try val.copy(anon_decl.arena()), | |
| 29843 | operand_ty, | |
| 29844 | val, | |
| 29098 | 29845 | 0, // default alignment |
| 29099 | 29846 | )); |
| 29100 | 29847 | } |
| ... | ... | @@ -29124,9 +29871,10 @@ fn analyzeLoad( |
| 29124 | 29871 | ptr: Air.Inst.Ref, |
| 29125 | 29872 | ptr_src: LazySrcLoc, |
| 29126 | 29873 | ) CompileError!Air.Inst.Ref { |
| 29874 | const mod = sema.mod; | |
| 29127 | 29875 | const ptr_ty = sema.typeOf(ptr); |
| 29128 | const elem_ty = switch (ptr_ty.zigTypeTag()) { | |
| 29129 | .Pointer => ptr_ty.childType(), | |
| 29876 | const elem_ty = switch (ptr_ty.zigTypeTag(mod)) { | |
| 29877 | .Pointer => ptr_ty.childType(mod), | |
| 29130 | 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 | 29884 | |
| 29137 | 29885 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { |
| 29138 | 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 | 29892 | const ptr_inst = Air.refToIndex(ptr).?; |
| 29145 | 29893 | const air_tags = sema.air_instructions.items(.tag); |
| 29146 | 29894 | if (air_tags[ptr_inst] == .ptr_elem_ptr) { |
| ... | ... | @@ -29163,11 +29911,11 @@ fn analyzeSlicePtr( |
| 29163 | 29911 | slice: Air.Inst.Ref, |
| 29164 | 29912 | slice_ty: Type, |
| 29165 | 29913 | ) CompileError!Air.Inst.Ref { |
| 29166 | const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); | |
| 29167 | const result_ty = slice_ty.slicePtrFieldType(buf); | |
| 29914 | const mod = sema.mod; | |
| 29915 | const result_ty = slice_ty.slicePtrFieldType(mod); | |
| 29168 | 29916 | if (try sema.resolveMaybeUndefVal(slice)) |val| { |
| 29169 | if (val.isUndef()) return sema.addConstUndef(result_ty); | |
| 29170 | return sema.addConstant(result_ty, val.slicePtr()); | |
| 29917 | if (val.isUndef(mod)) return sema.addConstUndef(result_ty); | |
| 29918 | return sema.addConstant(result_ty, val.slicePtr(mod)); | |
| 29171 | 29919 | } |
| 29172 | 29920 | try sema.requireRuntimeBlock(block, slice_src, null); |
| 29173 | 29921 | return block.addTyOp(.slice_ptr, result_ty, slice); |
| ... | ... | @@ -29179,8 +29927,9 @@ fn analyzeSliceLen( |
| 29179 | 29927 | src: LazySrcLoc, |
| 29180 | 29928 | slice_inst: Air.Inst.Ref, |
| 29181 | 29929 | ) CompileError!Air.Inst.Ref { |
| 29930 | const mod = sema.mod; | |
| 29182 | 29931 | if (try sema.resolveMaybeUndefVal(slice_inst)) |slice_val| { |
| 29183 | if (slice_val.isUndef()) { | |
| 29932 | if (slice_val.isUndef(mod)) { | |
| 29184 | 29933 | return sema.addConstUndef(Type.usize); |
| 29185 | 29934 | } |
| 29186 | 29935 | return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)); |
| ... | ... | @@ -29196,12 +29945,13 @@ fn analyzeIsNull( |
| 29196 | 29945 | operand: Air.Inst.Ref, |
| 29197 | 29946 | invert_logic: bool, |
| 29198 | 29947 | ) CompileError!Air.Inst.Ref { |
| 29948 | const mod = sema.mod; | |
| 29199 | 29949 | const result_ty = Type.bool; |
| 29200 | 29950 | if (try sema.resolveMaybeUndefVal(operand)) |opt_val| { |
| 29201 | if (opt_val.isUndef()) { | |
| 29951 | if (opt_val.isUndef(mod)) { | |
| 29202 | 29952 | return sema.addConstUndef(result_ty); |
| 29203 | 29953 | } |
| 29204 | const is_null = opt_val.isNull(); | |
| 29954 | const is_null = opt_val.isNull(mod); | |
| 29205 | 29955 | const bool_value = if (invert_logic) !is_null else is_null; |
| 29206 | 29956 | if (bool_value) { |
| 29207 | 29957 | return Air.Inst.Ref.bool_true; |
| ... | ... | @@ -29212,11 +29962,10 @@ fn analyzeIsNull( |
| 29212 | 29962 | |
| 29213 | 29963 | const inverted_non_null_res = if (invert_logic) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; |
| 29214 | 29964 | const operand_ty = sema.typeOf(operand); |
| 29215 | var buf: Type.Payload.ElemType = undefined; | |
| 29216 | if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) { | |
| 29965 | if (operand_ty.zigTypeTag(mod) == .Optional and operand_ty.optionalChild(mod).zigTypeTag(mod) == .NoReturn) { | |
| 29217 | 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 | 29969 | return inverted_non_null_res; |
| 29221 | 29970 | } |
| 29222 | 29971 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -29230,11 +29979,12 @@ fn analyzePtrIsNonErrComptimeOnly( |
| 29230 | 29979 | src: LazySrcLoc, |
| 29231 | 29980 | operand: Air.Inst.Ref, |
| 29232 | 29981 | ) CompileError!Air.Inst.Ref { |
| 29982 | const mod = sema.mod; | |
| 29233 | 29983 | const ptr_ty = sema.typeOf(operand); |
| 29234 | assert(ptr_ty.zigTypeTag() == .Pointer); | |
| 29235 | const child_ty = ptr_ty.childType(); | |
| 29984 | assert(ptr_ty.zigTypeTag(mod) == .Pointer); | |
| 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 | 29988 | if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true; |
| 29239 | 29989 | if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false; |
| 29240 | 29990 | assert(child_tag == .ErrorUnion); |
| ... | ... | @@ -29251,14 +30001,15 @@ fn analyzeIsNonErrComptimeOnly( |
| 29251 | 30001 | src: LazySrcLoc, |
| 29252 | 30002 | operand: Air.Inst.Ref, |
| 29253 | 30003 | ) CompileError!Air.Inst.Ref { |
| 30004 | const mod = sema.mod; | |
| 29254 | 30005 | const operand_ty = sema.typeOf(operand); |
| 29255 | const ot = operand_ty.zigTypeTag(); | |
| 30006 | const ot = operand_ty.zigTypeTag(mod); | |
| 29256 | 30007 | if (ot != .ErrorSet and ot != .ErrorUnion) return Air.Inst.Ref.bool_true; |
| 29257 | 30008 | if (ot == .ErrorSet) return Air.Inst.Ref.bool_false; |
| 29258 | 30009 | assert(ot == .ErrorUnion); |
| 29259 | 30010 | |
| 29260 | const payload_ty = operand_ty.errorUnionPayload(); | |
| 29261 | if (payload_ty.zigTypeTag() == .NoReturn) { | |
| 30011 | const payload_ty = operand_ty.errorUnionPayload(mod); | |
| 30012 | if (payload_ty.zigTypeTag(mod) == .NoReturn) { | |
| 29262 | 30013 | return Air.Inst.Ref.bool_false; |
| 29263 | 30014 | } |
| 29264 | 30015 | |
| ... | ... | @@ -29279,50 +30030,56 @@ fn analyzeIsNonErrComptimeOnly( |
| 29279 | 30030 | |
| 29280 | 30031 | // exception if the error union error set is known to be empty, |
| 29281 | 30032 | // we allow the comparison but always make it comptime-known. |
| 29282 | const set_ty = operand_ty.errorUnionSet(); | |
| 29283 | switch (set_ty.tag()) { | |
| 29284 | .anyerror => {}, | |
| 29285 | .error_set_inferred => blk: { | |
| 29286 | // If the error set is empty, we must return a comptime true or false. | |
| 29287 | // However we want to avoid unnecessarily resolving an inferred error set | |
| 29288 | // in case it is already non-empty. | |
| 29289 | const ies = set_ty.castTag(.error_set_inferred).?.data; | |
| 29290 | if (ies.is_anyerror) break :blk; | |
| 29291 | if (ies.errors.count() != 0) break :blk; | |
| 29292 | if (maybe_operand_val == null) { | |
| 29293 | // Try to avoid resolving inferred error set if possible. | |
| 29294 | if (ies.errors.count() != 0) break :blk; | |
| 30033 | const set_ty = operand_ty.errorUnionSet(mod); | |
| 30034 | switch (set_ty.toIntern()) { | |
| 30035 | .anyerror_type => {}, | |
| 30036 | else => switch (mod.intern_pool.indexToKey(set_ty.toIntern())) { | |
| 30037 | .error_set_type => |error_set_type| { | |
| 30038 | if (error_set_type.names.len == 0) return Air.Inst.Ref.bool_true; | |
| 30039 | }, | |
| 30040 | .inferred_error_set_type => |ies_index| blk: { | |
| 30041 | // If the error set is empty, we must return a comptime true or false. | |
| 30042 | // However we want to avoid unnecessarily resolving an inferred error set | |
| 30043 | // in case it is already non-empty. | |
| 30044 | const ies = mod.inferredErrorSetPtr(ies_index); | |
| 29295 | 30045 | if (ies.is_anyerror) break :blk; |
| 29296 | for (ies.inferred_error_sets.keys()) |other_ies| { | |
| 29297 | if (ies == other_ies) continue; | |
| 29298 | try sema.resolveInferredErrorSet(block, src, other_ies); | |
| 29299 | if (other_ies.is_anyerror) { | |
| 29300 | ies.is_anyerror = true; | |
| 29301 | ies.is_resolved = true; | |
| 29302 | break :blk; | |
| 29303 | } | |
| 30046 | if (ies.errors.count() != 0) break :blk; | |
| 30047 | if (maybe_operand_val == null) { | |
| 30048 | // Try to avoid resolving inferred error set if possible. | |
| 30049 | if (ies.errors.count() != 0) break :blk; | |
| 30050 | if (ies.is_anyerror) break :blk; | |
| 30051 | for (ies.inferred_error_sets.keys()) |other_ies_index| { | |
| 30052 | if (ies_index == other_ies_index) continue; | |
| 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; | |
| 29306 | } | |
| 29307 | if (ies.func == sema.owner_func) { | |
| 29308 | // 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 | |
| 29310 | // so far with this type can't contain errors either. | |
| 29311 | return Air.Inst.Ref.bool_true; | |
| 30061 | if (other_ies.errors.count() != 0) break :blk; | |
| 30062 | } | |
| 30063 | if (ies.func == sema.owner_func_index.unwrap()) { | |
| 30064 | // We're checking the inferred errorset of the current function and none of | |
| 30065 | // its child inferred error sets contained any errors meaning that any value | |
| 30066 | // so far with this type can't contain errors either. | |
| 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); | |
| 29314 | if (ies.is_anyerror) break :blk; | |
| 29315 | if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true; | |
| 29316 | } | |
| 30073 | }, | |
| 30074 | else => unreachable, | |
| 29317 | 30075 | }, |
| 29318 | else => if (set_ty.errorSetNames().len == 0) return Air.Inst.Ref.bool_true, | |
| 29319 | 30076 | } |
| 29320 | 30077 | |
| 29321 | 30078 | if (maybe_operand_val) |err_union| { |
| 29322 | if (err_union.isUndef()) { | |
| 30079 | if (err_union.isUndef(mod)) { | |
| 29323 | 30080 | return sema.addConstUndef(Type.bool); |
| 29324 | 30081 | } |
| 29325 | if (err_union.getError() == null) { | |
| 30082 | if (err_union.getErrorName(mod) == .none) { | |
| 29326 | 30083 | return Air.Inst.Ref.bool_true; |
| 29327 | 30084 | } else { |
| 29328 | 30085 | return Air.Inst.Ref.bool_false; |
| ... | ... | @@ -29375,72 +30132,78 @@ fn analyzeSlice( |
| 29375 | 30132 | end_src: LazySrcLoc, |
| 29376 | 30133 | by_length: bool, |
| 29377 | 30134 | ) CompileError!Air.Inst.Ref { |
| 30135 | const mod = sema.mod; | |
| 29378 | 30136 | // Slice expressions can operate on a variable whose type is an array. This requires |
| 29379 | 30137 | // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer. |
| 29380 | 30138 | const ptr_ptr_ty = sema.typeOf(ptr_ptr); |
| 29381 | const target = sema.mod.getTarget(); | |
| 29382 | const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag()) { | |
| 29383 | .Pointer => ptr_ptr_ty.elemType(), | |
| 29384 | else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(sema.mod)}), | |
| 30139 | const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(mod)) { | |
| 30140 | .Pointer => ptr_ptr_ty.childType(mod), | |
| 30141 | else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(mod)}), | |
| 29385 | 30142 | }; |
| 29386 | const mod = sema.mod; | |
| 29387 | 30143 | |
| 29388 | 30144 | var array_ty = ptr_ptr_child_ty; |
| 29389 | 30145 | var slice_ty = ptr_ptr_ty; |
| 29390 | 30146 | var ptr_or_slice = ptr_ptr; |
| 29391 | 30147 | var elem_ty: Type = undefined; |
| 29392 | 30148 | var ptr_sentinel: ?Value = null; |
| 29393 | switch (ptr_ptr_child_ty.zigTypeTag()) { | |
| 30149 | switch (ptr_ptr_child_ty.zigTypeTag(mod)) { | |
| 29394 | 30150 | .Array => { |
| 29395 | ptr_sentinel = ptr_ptr_child_ty.sentinel(); | |
| 29396 | elem_ty = ptr_ptr_child_ty.childType(); | |
| 30151 | ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); | |
| 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 | 30155 | .One => { |
| 29400 | const double_child_ty = ptr_ptr_child_ty.childType(); | |
| 29401 | if (double_child_ty.zigTypeTag() == .Array) { | |
| 29402 | ptr_sentinel = double_child_ty.sentinel(); | |
| 30156 | const double_child_ty = ptr_ptr_child_ty.childType(mod); | |
| 30157 | if (double_child_ty.zigTypeTag(mod) == .Array) { | |
| 30158 | ptr_sentinel = double_child_ty.sentinel(mod); | |
| 29403 | 30159 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); |
| 29404 | 30160 | slice_ty = ptr_ptr_child_ty; |
| 29405 | 30161 | array_ty = double_child_ty; |
| 29406 | elem_ty = double_child_ty.childType(); | |
| 30162 | elem_ty = double_child_ty.childType(mod); | |
| 29407 | 30163 | } else { |
| 29408 | 30164 | return sema.fail(block, src, "slice of single-item pointer", .{}); |
| 29409 | 30165 | } |
| 29410 | 30166 | }, |
| 29411 | 30167 | .Many, .C => { |
| 29412 | ptr_sentinel = ptr_ptr_child_ty.sentinel(); | |
| 30168 | ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); | |
| 29413 | 30169 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); |
| 29414 | 30170 | slice_ty = ptr_ptr_child_ty; |
| 29415 | 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 | 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 | 30177 | return sema.fail(block, src, "slice of null pointer", .{}); |
| 29422 | 30178 | } |
| 29423 | 30179 | } |
| 29424 | 30180 | } |
| 29425 | 30181 | }, |
| 29426 | 30182 | .Slice => { |
| 29427 | ptr_sentinel = ptr_ptr_child_ty.sentinel(); | |
| 30183 | ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); | |
| 29428 | 30184 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); |
| 29429 | 30185 | slice_ty = ptr_ptr_child_ty; |
| 29430 | 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 | 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 | 30194 | try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty) |
| 29439 | else | |
| 29440 | ptr_or_slice; | |
| 30195 | else if (array_ty.zigTypeTag(mod) == .Array) ptr: { | |
| 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 | 30204 | const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); |
| 29443 | 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 | 30208 | // true if and only if the end index of the slice, implicitly or explicitly, equals |
| 29446 | 30209 | // the length of the underlying object being sliced. we might learn the length of the |
| ... | ... | @@ -29448,8 +30211,8 @@ fn analyzeSlice( |
| 29448 | 30211 | // we might learn of the length because it is a comptime-known slice value. |
| 29449 | 30212 | var end_is_len = uncasted_end_opt == .none; |
| 29450 | 30213 | const end = e: { |
| 29451 | if (array_ty.zigTypeTag() == .Array) { | |
| 29452 | const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); | |
| 30214 | if (array_ty.zigTypeTag(mod) == .Array) { | |
| 30215 | const len_val = try mod.intValue(Type.usize, array_ty.arrayLen(mod)); | |
| 29453 | 30216 | |
| 29454 | 30217 | if (!end_is_len) { |
| 29455 | 30218 | const end = if (by_length) end: { |
| ... | ... | @@ -29458,12 +30221,12 @@ fn analyzeSlice( |
| 29458 | 30221 | break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); |
| 29459 | 30222 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29460 | 30223 | if (try sema.resolveMaybeUndefVal(end)) |end_val| { |
| 29461 | const len_s_val = try Value.Tag.int_u64.create( | |
| 29462 | sema.arena, | |
| 29463 | array_ty.arrayLenIncludingSentinel(), | |
| 30224 | const len_s_val = try mod.intValue( | |
| 30225 | Type.usize, | |
| 30226 | array_ty.arrayLenIncludingSentinel(mod), | |
| 29464 | 30227 | ); |
| 29465 | 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 | 30230 | " +1 (sentinel)" |
| 29468 | 30231 | else |
| 29469 | 30232 | ""; |
| ... | ... | @@ -29491,7 +30254,7 @@ fn analyzeSlice( |
| 29491 | 30254 | } |
| 29492 | 30255 | |
| 29493 | 30256 | break :e try sema.addConstant(Type.usize, len_val); |
| 29494 | } else if (slice_ty.isSlice()) { | |
| 30257 | } else if (slice_ty.isSlice(mod)) { | |
| 29495 | 30258 | if (!end_is_len) { |
| 29496 | 30259 | const end = if (by_length) end: { |
| 29497 | 30260 | const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| ... | ... | @@ -29500,16 +30263,14 @@ fn analyzeSlice( |
| 29500 | 30263 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29501 | 30264 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 29502 | 30265 | if (try sema.resolveMaybeUndefVal(ptr_or_slice)) |slice_val| { |
| 29503 | if (slice_val.isUndef()) { | |
| 30266 | if (slice_val.isUndef(mod)) { | |
| 29504 | 30267 | return sema.fail(block, src, "slice of undefined", .{}); |
| 29505 | 30268 | } |
| 29506 | const has_sentinel = slice_ty.sentinel() != null; | |
| 29507 | var int_payload: Value.Payload.U64 = .{ | |
| 29508 | .base = .{ .tag = .int_u64 }, | |
| 29509 | .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel), | |
| 29510 | }; | |
| 29511 | const slice_len_val = Value.initPayload(&int_payload.base); | |
| 29512 | if (!(try sema.compareAll(end_val, .lte, slice_len_val, Type.usize))) { | |
| 30269 | const has_sentinel = slice_ty.sentinel(mod) != null; | |
| 30270 | const slice_len = slice_val.sliceLen(mod); | |
| 30271 | const len_plus_sent = slice_len + @boolToInt(has_sentinel); | |
| 30272 | const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent); | |
| 30273 | if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) { | |
| 29513 | 30274 | const sentinel_label: []const u8 = if (has_sentinel) |
| 29514 | 30275 | " +1 (sentinel)" |
| 29515 | 30276 | else |
| ... | ... | @@ -29527,13 +30288,10 @@ fn analyzeSlice( |
| 29527 | 30288 | ); |
| 29528 | 30289 | } |
| 29529 | 30290 | |
| 29530 | // If the slice has a sentinel, we subtract one so that | |
| 29531 | // end_is_len is only true if it equals the length WITHOUT | |
| 29532 | // the sentinel, so we don't add a sentinel type. | |
| 29533 | if (has_sentinel) { | |
| 29534 | int_payload.data -= 1; | |
| 29535 | } | |
| 29536 | ||
| 30291 | // If the slice has a sentinel, we consider end_is_len | |
| 30292 | // is only true if it equals the length WITHOUT the | |
| 30293 | // sentinel, so we don't add a sentinel type. | |
| 30294 | const slice_len_val = try mod.intValue(Type.usize, slice_len); | |
| 29537 | 30295 | if (end_val.eql(slice_len_val, Type.usize, mod)) { |
| 29538 | 30296 | end_is_len = true; |
| 29539 | 30297 | } |
| ... | ... | @@ -29569,11 +30327,12 @@ fn analyzeSlice( |
| 29569 | 30327 | }; |
| 29570 | 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 | 30333 | // requirement: start <= end |
| 29573 | var need_start_gt_end_check = true; | |
| 29574 | 30334 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 29575 | 30335 | if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { |
| 29576 | need_start_gt_end_check = false; | |
| 29577 | 30336 | if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { |
| 29578 | 30337 | return sema.fail( |
| 29579 | 30338 | block, |
| ... | ... | @@ -29585,14 +30344,18 @@ fn analyzeSlice( |
| 29585 | 30344 | }, |
| 29586 | 30345 | ); |
| 29587 | 30346 | } |
| 30347 | checked_start_lte_end = true; | |
| 29588 | 30348 | if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { |
| 29589 | 30349 | const expected_sentinel = sentinel orelse break :sentinel_check; |
| 29590 | const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; | |
| 29591 | const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; | |
| 30350 | const start_int = start_val.getUnsignedInt(mod).?; | |
| 30351 | const end_int = end_val.getUnsignedInt(mod).?; | |
| 29592 | 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); | |
| 29595 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); | |
| 30354 | const many_ptr_ty = try mod.manyConstPtrType(elem_ty); | |
| 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 | 30359 | const actual_sentinel = switch (res) { |
| 29597 | 30360 | .runtime_load => break :sentinel_check, |
| 29598 | 30361 | .val => |v| v, |
| ... | ... | @@ -29600,36 +30363,49 @@ fn analyzeSlice( |
| 29600 | 30363 | block, |
| 29601 | 30364 | src, |
| 29602 | 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 | 30368 | .out_of_bounds => |ty| return sema.fail( |
| 29606 | 30369 | block, |
| 29607 | 30370 | end_src, |
| 29608 | 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 | 30377 | const msg = msg: { |
| 29615 | 30378 | const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); |
| 29616 | 30379 | errdefer msg.destroy(sema.gpa); |
| 29617 | 30380 | try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ |
| 29618 | expected_sentinel.fmtValue(elem_ty, sema.mod), | |
| 29619 | actual_sentinel.fmtValue(elem_ty, sema.mod), | |
| 30381 | expected_sentinel.fmtValue(elem_ty, mod), | |
| 30382 | actual_sentinel.fmtValue(elem_ty, mod), | |
| 29620 | 30383 | }); |
| 29621 | 30384 | |
| 29622 | 30385 | break :msg msg; |
| 29623 | 30386 | }; |
| 29624 | 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 | 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 | 30410 | const new_len = if (by_length) |
| 29635 | 30411 | try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) |
| ... | ... | @@ -29637,11 +30413,11 @@ fn analyzeSlice( |
| 29637 | 30413 | try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); |
| 29638 | 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; | |
| 29641 | const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize() != .C; | |
| 30416 | const new_ptr_ty_info = new_ptr_ty.ptrInfo(mod); | |
| 30417 | const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize(mod) != .C; | |
| 29642 | 30418 | |
| 29643 | 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 | 30422 | const return_ty = try Type.ptr(sema.arena, mod, .{ |
| 29647 | 30423 | .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, mod), |
| ... | ... | @@ -29659,14 +30435,14 @@ fn analyzeSlice( |
| 29659 | 30435 | const result = try block.addBitCast(return_ty, new_ptr); |
| 29660 | 30436 | if (block.wantSafety()) { |
| 29661 | 30437 | // requirement: slicing C ptr is non-null |
| 29662 | if (ptr_ptr_child_ty.isCPtr()) { | |
| 30438 | if (ptr_ptr_child_ty.isCPtr(mod)) { | |
| 29663 | 30439 | const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); |
| 29664 | 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 | 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 | 30446 | slice_len_inst |
| 29671 | 30447 | else |
| 29672 | 30448 | try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true); |
| ... | ... | @@ -29685,8 +30461,11 @@ fn analyzeSlice( |
| 29685 | 30461 | return result; |
| 29686 | 30462 | }; |
| 29687 | 30463 | |
| 29688 | if (!new_ptr_val.isUndef()) { | |
| 29689 | return sema.addConstant(return_ty, new_ptr_val); | |
| 30464 | if (!new_ptr_val.isUndef(mod)) { | |
| 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 | 30471 | // Special case: @as([]i32, undefined)[x..x] |
| ... | ... | @@ -29708,25 +30487,18 @@ fn analyzeSlice( |
| 29708 | 30487 | .size = .Slice, |
| 29709 | 30488 | }); |
| 29710 | 30489 | |
| 29711 | const runtime_src = if ((try sema.resolveMaybeUndefVal(ptr_or_slice)) == null) | |
| 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); | |
| 30490 | try sema.requireRuntimeBlock(block, src, runtime_src.?); | |
| 29719 | 30491 | if (block.wantSafety()) { |
| 29720 | 30492 | // requirement: slicing C ptr is non-null |
| 29721 | if (ptr_ptr_child_ty.isCPtr()) { | |
| 30493 | if (ptr_ptr_child_ty.isCPtr(mod)) { | |
| 29722 | 30494 | const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); |
| 29723 | 30495 | try sema.addSafetyCheck(block, is_non_null, .unwrap_null); |
| 29724 | 30496 | } |
| 29725 | 30497 | |
| 29726 | 30498 | // requirement: end <= len |
| 29727 | const opt_len_inst = if (array_ty.zigTypeTag() == .Array) | |
| 29728 | try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel()) | |
| 29729 | else if (slice_ty.isSlice()) blk: { | |
| 30499 | const opt_len_inst = if (array_ty.zigTypeTag(mod) == .Array) | |
| 30500 | try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel(mod)) | |
| 30501 | else if (slice_ty.isSlice(mod)) blk: { | |
| 29730 | 30502 | if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { |
| 29731 | 30503 | // we don't need to add one for sentinels because the |
| 29732 | 30504 | // underlying value data includes the sentinel |
| ... | ... | @@ -29734,7 +30506,7 @@ fn analyzeSlice( |
| 29734 | 30506 | } |
| 29735 | 30507 | |
| 29736 | 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 | 30511 | // we have to add one because slice lengths don't include the sentinel |
| 29740 | 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 | 30550 | lhs_src: LazySrcLoc, |
| 29779 | 30551 | rhs_src: LazySrcLoc, |
| 29780 | 30552 | ) CompileError!Air.Inst.Ref { |
| 30553 | const mod = sema.mod; | |
| 29781 | 30554 | const lhs_ty = sema.typeOf(uncasted_lhs); |
| 29782 | 30555 | const rhs_ty = sema.typeOf(uncasted_rhs); |
| 29783 | 30556 | |
| 29784 | assert(lhs_ty.isNumeric()); | |
| 29785 | assert(rhs_ty.isNumeric()); | |
| 30557 | assert(lhs_ty.isNumeric(mod)); | |
| 30558 | assert(rhs_ty.isNumeric(mod)); | |
| 29786 | 30559 | |
| 29787 | const lhs_ty_tag = lhs_ty.zigTypeTag(); | |
| 29788 | const rhs_ty_tag = rhs_ty.zigTypeTag(); | |
| 29789 | const target = sema.mod.getTarget(); | |
| 30560 | const lhs_ty_tag = lhs_ty.zigTypeTag(mod); | |
| 30561 | const rhs_ty_tag = rhs_ty.zigTypeTag(mod); | |
| 30562 | const target = mod.getTarget(); | |
| 29790 | 30563 | |
| 29791 | 30564 | // One exception to heterogeneous comparison: comptime_float needs to |
| 29792 | 30565 | // coerce to fixed-width float. |
| ... | ... | @@ -29805,49 +30578,45 @@ fn cmpNumeric( |
| 29805 | 30578 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { |
| 29806 | 30579 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { |
| 29807 | 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()) { | |
| 29809 | try sema.resolveLazyValue(lhs_val); | |
| 29810 | if (sema.compareIntsOnlyPossibleResult(target, lhs_val, op, rhs_ty)) |res| { | |
| 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)) { | |
| 30582 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { | |
| 29811 | 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()) { | |
| 29814 | try sema.resolveLazyValue(rhs_val); | |
| 29815 | if (sema.compareIntsOnlyPossibleResult(target, rhs_val, op.reverse(), lhs_ty)) |res| { | |
| 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)) { | |
| 30586 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { | |
| 29816 | 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 | 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 | 30595 | if (op == std.math.CompareOperator.neq) { |
| 29825 | 30596 | return Air.Inst.Ref.bool_true; |
| 29826 | 30597 | } else { |
| 29827 | 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 | 30602 | return Air.Inst.Ref.bool_true; |
| 29832 | 30603 | } else { |
| 29833 | 30604 | return Air.Inst.Ref.bool_false; |
| 29834 | 30605 | } |
| 29835 | 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 | 30608 | // Compare ints: const vs. var |
| 29838 | try sema.resolveLazyValue(lhs_val); | |
| 29839 | if (sema.compareIntsOnlyPossibleResult(target, lhs_val, op, rhs_ty)) |res| { | |
| 30609 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { | |
| 29840 | 30610 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; |
| 29841 | 30611 | } |
| 29842 | 30612 | } |
| 29843 | 30613 | break :src rhs_src; |
| 29844 | 30614 | } |
| 29845 | 30615 | } else { |
| 29846 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { | |
| 29847 | if (!rhs_val.isUndef() and (rhs_ty.isInt() or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt()) { | |
| 30616 | if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| { | |
| 30617 | if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod)) { | |
| 29848 | 30618 | // Compare ints: var vs. const |
| 29849 | try sema.resolveLazyValue(rhs_val); | |
| 29850 | if (sema.compareIntsOnlyPossibleResult(target, rhs_val, op.reverse(), lhs_ty)) |res| { | |
| 30619 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { | |
| 29851 | 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 | 30670 | const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| |
| 29902 | 30671 | !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) |
| 29903 | 30672 | else |
| 29904 | (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt()); | |
| 30673 | (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(mod)); | |
| 29905 | 30674 | const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| |
| 29906 | 30675 | !(try rhs_val.compareAllWithZeroAdvanced(.gte, sema)) |
| 29907 | 30676 | else |
| 29908 | (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt()); | |
| 30677 | (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(mod)); | |
| 29909 | 30678 | const dest_int_is_signed = lhs_is_signed or rhs_is_signed; |
| 29910 | 30679 | |
| 29911 | 30680 | var dest_float_type: ?Type = null; |
| 29912 | 30681 | |
| 29913 | 30682 | var lhs_bits: usize = undefined; |
| 29914 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { | |
| 29915 | try sema.resolveLazyValue(lhs_val); | |
| 29916 | if (lhs_val.isUndef()) | |
| 30683 | if (try sema.resolveMaybeUndefLazyVal(lhs)) |lhs_val| { | |
| 30684 | if (lhs_val.isUndef(mod)) | |
| 29917 | 30685 | return sema.addConstUndef(Type.bool); |
| 29918 | if (lhs_val.isNan()) switch (op) { | |
| 30686 | if (lhs_val.isNan(mod)) switch (op) { | |
| 29919 | 30687 | .neq => return Air.Inst.Ref.bool_true, |
| 29920 | 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 | 30691 | .neq => return Air.Inst.Ref.bool_true, |
| 29924 | 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, | |
| 29926 | .lt, .lte => return if (lhs_val.isNegativeInf()) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, | |
| 30693 | .gt, .gte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, | |
| 30694 | .lt, .lte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, | |
| 29927 | 30695 | }; |
| 29928 | 30696 | if (!rhs_is_signed) { |
| 29929 | switch (lhs_val.orderAgainstZero()) { | |
| 30697 | switch (lhs_val.orderAgainstZero(mod)) { | |
| 29930 | 30698 | .gt => {}, |
| 29931 | 30699 | .eq => switch (op) { // LHS = 0, RHS is unsigned |
| 29932 | 30700 | .lte => return Air.Inst.Ref.bool_true, |
| ... | ... | @@ -29940,7 +30708,7 @@ fn cmpNumeric( |
| 29940 | 30708 | } |
| 29941 | 30709 | } |
| 29942 | 30710 | if (lhs_is_float) { |
| 29943 | if (lhs_val.floatHasFraction()) { | |
| 30711 | if (lhs_val.floatHasFraction(mod)) { | |
| 29944 | 30712 | switch (op) { |
| 29945 | 30713 | .eq => return Air.Inst.Ref.bool_false, |
| 29946 | 30714 | .neq => return Air.Inst.Ref.bool_true, |
| ... | ... | @@ -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 | 30720 | defer bigint.deinit(); |
| 29953 | if (lhs_val.floatHasFraction()) { | |
| 30721 | if (lhs_val.floatHasFraction(mod)) { | |
| 29954 | 30722 | if (lhs_is_signed) { |
| 29955 | 30723 | try bigint.addScalar(&bigint, -1); |
| 29956 | 30724 | } else { |
| ... | ... | @@ -29959,33 +30727,32 @@ fn cmpNumeric( |
| 29959 | 30727 | } |
| 29960 | 30728 | lhs_bits = bigint.toConst().bitCountTwosComp(); |
| 29961 | 30729 | } else { |
| 29962 | lhs_bits = lhs_val.intBitCountTwosComp(target); | |
| 30730 | lhs_bits = lhs_val.intBitCountTwosComp(mod); | |
| 29963 | 30731 | } |
| 29964 | 30732 | lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed); |
| 29965 | 30733 | } else if (lhs_is_float) { |
| 29966 | 30734 | dest_float_type = lhs_ty; |
| 29967 | 30735 | } else { |
| 29968 | const int_info = lhs_ty.intInfo(target); | |
| 30736 | const int_info = lhs_ty.intInfo(mod); | |
| 29969 | 30737 | lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); |
| 29970 | 30738 | } |
| 29971 | 30739 | |
| 29972 | 30740 | var rhs_bits: usize = undefined; |
| 29973 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { | |
| 29974 | try sema.resolveLazyValue(rhs_val); | |
| 29975 | if (rhs_val.isUndef()) | |
| 30741 | if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| { | |
| 30742 | if (rhs_val.isUndef(mod)) | |
| 29976 | 30743 | return sema.addConstUndef(Type.bool); |
| 29977 | if (rhs_val.isNan()) switch (op) { | |
| 30744 | if (rhs_val.isNan(mod)) switch (op) { | |
| 29978 | 30745 | .neq => return Air.Inst.Ref.bool_true, |
| 29979 | 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 | 30749 | .neq => return Air.Inst.Ref.bool_true, |
| 29983 | 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, | |
| 29985 | .lt, .lte => return if (rhs_val.isNegativeInf()) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, | |
| 30751 | .gt, .gte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, | |
| 30752 | .lt, .lte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, | |
| 29986 | 30753 | }; |
| 29987 | 30754 | if (!lhs_is_signed) { |
| 29988 | switch (rhs_val.orderAgainstZero()) { | |
| 30755 | switch (rhs_val.orderAgainstZero(mod)) { | |
| 29989 | 30756 | .gt => {}, |
| 29990 | 30757 | .eq => switch (op) { // RHS = 0, LHS is unsigned |
| 29991 | 30758 | .gte => return Air.Inst.Ref.bool_true, |
| ... | ... | @@ -29999,7 +30766,7 @@ fn cmpNumeric( |
| 29999 | 30766 | } |
| 30000 | 30767 | } |
| 30001 | 30768 | if (rhs_is_float) { |
| 30002 | if (rhs_val.floatHasFraction()) { | |
| 30769 | if (rhs_val.floatHasFraction(mod)) { | |
| 30003 | 30770 | switch (op) { |
| 30004 | 30771 | .eq => return Air.Inst.Ref.bool_false, |
| 30005 | 30772 | .neq => return Air.Inst.Ref.bool_true, |
| ... | ... | @@ -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 | 30778 | defer bigint.deinit(); |
| 30012 | if (rhs_val.floatHasFraction()) { | |
| 30779 | if (rhs_val.floatHasFraction(mod)) { | |
| 30013 | 30780 | if (rhs_is_signed) { |
| 30014 | 30781 | try bigint.addScalar(&bigint, -1); |
| 30015 | 30782 | } else { |
| ... | ... | @@ -30018,13 +30785,13 @@ fn cmpNumeric( |
| 30018 | 30785 | } |
| 30019 | 30786 | rhs_bits = bigint.toConst().bitCountTwosComp(); |
| 30020 | 30787 | } else { |
| 30021 | rhs_bits = rhs_val.intBitCountTwosComp(target); | |
| 30788 | rhs_bits = rhs_val.intBitCountTwosComp(mod); | |
| 30022 | 30789 | } |
| 30023 | 30790 | rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed); |
| 30024 | 30791 | } else if (rhs_is_float) { |
| 30025 | 30792 | dest_float_type = rhs_ty; |
| 30026 | 30793 | } else { |
| 30027 | const int_info = rhs_ty.intInfo(target); | |
| 30794 | const int_info = rhs_ty.intInfo(mod); | |
| 30028 | 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 | 30799 | const max_bits = std.math.max(lhs_bits, rhs_bits); |
| 30033 | 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 | 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 | 30804 | const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); |
| 30038 | 30805 | const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); |
| ... | ... | @@ -30040,13 +30807,20 @@ fn cmpNumeric( |
| 30040 | 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. | |
| 30044 | /// Given a const LHS and an unknown RHS, attempt to determine whether `op` has a guaranteed result. | |
| 30810 | /// Asserts that LHS value is an int or comptime int and not undefined, and | |
| 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 | 30813 | /// If it cannot be determined, returns null. |
| 30046 | 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 { | |
| 30048 | const rhs_info = rhs_ty.intInfo(target); | |
| 30049 | const vs_zero = lhs_val.orderAgainstZeroAdvanced(sema) catch unreachable; | |
| 30815 | fn compareIntsOnlyPossibleResult( | |
| 30816 | sema: *Sema, | |
| 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 | 30824 | const is_zero = vs_zero == .eq; |
| 30051 | 30825 | const is_negative = vs_zero == .lt; |
| 30052 | 30826 | const is_positive = vs_zero == .gt; |
| ... | ... | @@ -30078,7 +30852,7 @@ fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value |
| 30078 | 30852 | }; |
| 30079 | 30853 | |
| 30080 | 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 | 30857 | // No sized type can have more than 65535 bits. |
| 30084 | 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 | 30885 | .max = false, |
| 30112 | 30886 | }; |
| 30113 | 30887 | |
| 30114 | var ty_buffer: Type.Payload.Bits = .{ | |
| 30115 | .base = .{ .tag = if (is_negative) .int_signed else .int_unsigned }, | |
| 30116 | .data = @intCast(u16, req_bits), | |
| 30117 | }; | |
| 30118 | const ty = Type.initPayload(&ty_buffer.base); | |
| 30119 | const pop_count = lhs_val.popCount(ty, target); | |
| 30888 | const ty = try mod.intType( | |
| 30889 | if (is_negative) .signed else .unsigned, | |
| 30890 | @intCast(u16, req_bits), | |
| 30891 | ); | |
| 30892 | const pop_count = lhs_val.popCount(ty, mod); | |
| 30120 | 30893 | |
| 30121 | 30894 | if (is_negative) { |
| 30122 | 30895 | break :edge .{ |
| ... | ... | @@ -30152,22 +30925,26 @@ fn cmpVector( |
| 30152 | 30925 | lhs_src: LazySrcLoc, |
| 30153 | 30926 | rhs_src: LazySrcLoc, |
| 30154 | 30927 | ) CompileError!Air.Inst.Ref { |
| 30928 | const mod = sema.mod; | |
| 30155 | 30929 | const lhs_ty = sema.typeOf(lhs); |
| 30156 | 30930 | const rhs_ty = sema.typeOf(rhs); |
| 30157 | assert(lhs_ty.zigTypeTag() == .Vector); | |
| 30158 | assert(rhs_ty.zigTypeTag() == .Vector); | |
| 30931 | assert(lhs_ty.zigTypeTag(mod) == .Vector); | |
| 30932 | assert(rhs_ty.zigTypeTag(mod) == .Vector); | |
| 30159 | 30933 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 30160 | 30934 | |
| 30161 | 30935 | const resolved_ty = try sema.resolvePeerTypes(block, src, &.{ lhs, rhs }, .{ .override = &.{ lhs_src, rhs_src } }); |
| 30162 | 30936 | const casted_lhs = try sema.coerce(block, resolved_ty, lhs, lhs_src); |
| 30163 | 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 | 30944 | const runtime_src: LazySrcLoc = src: { |
| 30168 | 30945 | if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| { |
| 30169 | 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 | 30948 | return sema.addConstUndef(result_ty); |
| 30172 | 30949 | } |
| 30173 | 30950 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_ty); |
| ... | ... | @@ -30192,7 +30969,10 @@ fn wrapOptional( |
| 30192 | 30969 | inst_src: LazySrcLoc, |
| 30193 | 30970 | ) !Air.Inst.Ref { |
| 30194 | 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 | 30978 | try sema.requireRuntimeBlock(block, inst_src, null); |
| ... | ... | @@ -30206,10 +30986,14 @@ fn wrapErrorUnionPayload( |
| 30206 | 30986 | inst: Air.Inst.Ref, |
| 30207 | 30987 | inst_src: LazySrcLoc, |
| 30208 | 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 | 30991 | const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false }); |
| 30211 | 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 | 30998 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 30215 | 30999 | try sema.queueFullTypeResolution(dest_payload_ty); |
| ... | ... | @@ -30223,48 +31007,41 @@ fn wrapErrorUnionSet( |
| 30223 | 31007 | inst: Air.Inst.Ref, |
| 30224 | 31008 | inst_src: LazySrcLoc, |
| 30225 | 31009 | ) !Air.Inst.Ref { |
| 31010 | const mod = sema.mod; | |
| 31011 | const ip = &mod.intern_pool; | |
| 30226 | 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 | 31014 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 30229 | switch (dest_err_set_ty.tag()) { | |
| 30230 | .anyerror => {}, | |
| 30231 | .error_set_single => ok: { | |
| 30232 | const expected_name = val.castTag(.@"error").?.data.name; | |
| 30233 | const n = dest_err_set_ty.castTag(.error_set_single).?.data; | |
| 30234 | if (mem.eql(u8, expected_name, n)) 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)) { | |
| 31015 | switch (dest_err_set_ty.toIntern()) { | |
| 31016 | .anyerror_type => {}, | |
| 31017 | else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) { | |
| 31018 | .error_set_type => |error_set_type| ok: { | |
| 31019 | const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; | |
| 31020 | if (error_set_type.nameIndex(ip, expected_name) != null) break :ok; | |
| 30241 | 31021 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); |
| 30242 | } | |
| 30243 | }, | |
| 30244 | .error_set_inferred => ok: { | |
| 30245 | const expected_name = val.castTag(.@"error").?.data.name; | |
| 30246 | const ies = dest_err_set_ty.castTag(.error_set_inferred).?.data; | |
| 31022 | }, | |
| 31023 | .inferred_error_set_type => |ies_index| ok: { | |
| 31024 | const ies = mod.inferredErrorSetPtr(ies_index); | |
| 31025 | const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; | |
| 30247 | 31026 | |
| 30248 | // We carefully do this in an order that avoids unnecessarily | |
| 30249 | // resolving the destination error set type. | |
| 30250 | if (ies.is_anyerror) break :ok; | |
| 30251 | if (ies.errors.contains(expected_name)) break :ok; | |
| 30252 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) { | |
| 30253 | break :ok; | |
| 30254 | } | |
| 31027 | // We carefully do this in an order that avoids unnecessarily | |
| 31028 | // resolving the destination error set type. | |
| 31029 | if (ies.is_anyerror) break :ok; | |
| 31030 | ||
| 31031 | if (ies.errors.contains(expected_name)) break :ok; | |
| 31032 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) break :ok; | |
| 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 | 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 | 31047 | try sema.requireRuntimeBlock(block, inst_src, null); |
| ... | ... | @@ -30279,11 +31056,12 @@ fn unionToTag( |
| 30279 | 31056 | un: Air.Inst.Ref, |
| 30280 | 31057 | un_src: LazySrcLoc, |
| 30281 | 31058 | ) !Air.Inst.Ref { |
| 31059 | const mod = sema.mod; | |
| 30282 | 31060 | if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| { |
| 30283 | 31061 | return sema.addConstant(enum_ty, opv); |
| 30284 | 31062 | } |
| 30285 | 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 | 31066 | try sema.requireRuntimeBlock(block, un_src, null); |
| 30289 | 31067 | return block.addTyOp(.get_union_tag, enum_ty, un); |
| ... | ... | @@ -30296,16 +31074,17 @@ fn resolvePeerTypes( |
| 30296 | 31074 | instructions: []const Air.Inst.Ref, |
| 30297 | 31075 | candidate_srcs: Module.PeerTypeCandidateSrc, |
| 30298 | 31076 | ) !Type { |
| 31077 | const mod = sema.mod; | |
| 30299 | 31078 | switch (instructions.len) { |
| 30300 | 0 => return Type.initTag(.noreturn), | |
| 31079 | 0 => return Type.noreturn, | |
| 30301 | 31080 | 1 => return sema.typeOf(instructions[0]), |
| 30302 | 31081 | else => {}, |
| 30303 | 31082 | } |
| 30304 | 31083 | |
| 30305 | const target = sema.mod.getTarget(); | |
| 31084 | const target = mod.getTarget(); | |
| 30306 | 31085 | |
| 30307 | 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 | 31088 | // * ErrorSet: this is an override |
| 30310 | 31089 | // * ErrorUnion: this is an override of the error set only |
| 30311 | 31090 | // * other: at the end we make an ErrorUnion with the other thing and this |
| ... | ... | @@ -30318,8 +31097,8 @@ fn resolvePeerTypes( |
| 30318 | 31097 | const candidate_ty = sema.typeOf(candidate); |
| 30319 | 31098 | const chosen_ty = sema.typeOf(chosen); |
| 30320 | 31099 | |
| 30321 | const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison(); | |
| 30322 | const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison(); | |
| 31100 | const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison(mod); | |
| 31101 | const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison(mod); | |
| 30323 | 31102 | |
| 30324 | 31103 | // If the candidate can coerce into our chosen type, we're done. |
| 30325 | 31104 | // If the chosen type can coerce into the candidate, use that. |
| ... | ... | @@ -30347,8 +31126,8 @@ fn resolvePeerTypes( |
| 30347 | 31126 | continue; |
| 30348 | 31127 | }, |
| 30349 | 31128 | .Int => { |
| 30350 | const chosen_info = chosen_ty.intInfo(target); | |
| 30351 | const candidate_info = candidate_ty.intInfo(target); | |
| 31129 | const chosen_info = chosen_ty.intInfo(mod); | |
| 31130 | const candidate_info = candidate_ty.intInfo(mod); | |
| 30352 | 31131 | |
| 30353 | 31132 | if (chosen_info.bits < candidate_info.bits) { |
| 30354 | 31133 | chosen = candidate; |
| ... | ... | @@ -30356,12 +31135,12 @@ fn resolvePeerTypes( |
| 30356 | 31135 | } |
| 30357 | 31136 | continue; |
| 30358 | 31137 | }, |
| 30359 | .Pointer => if (chosen_ty.ptrSize() == .C) continue, | |
| 31138 | .Pointer => if (chosen_ty.ptrSize(mod) == .C) continue, | |
| 30360 | 31139 | else => {}, |
| 30361 | 31140 | }, |
| 30362 | 31141 | .ComptimeInt => switch (chosen_ty_tag) { |
| 30363 | 31142 | .Int, .Float, .ComptimeFloat => continue, |
| 30364 | .Pointer => if (chosen_ty.ptrSize() == .C) continue, | |
| 31143 | .Pointer => if (chosen_ty.ptrSize(mod) == .C) continue, | |
| 30365 | 31144 | else => {}, |
| 30366 | 31145 | }, |
| 30367 | 31146 | .Float => switch (chosen_ty_tag) { |
| ... | ... | @@ -30426,11 +31205,11 @@ fn resolvePeerTypes( |
| 30426 | 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 | 31209 | continue; |
| 30431 | 31210 | }, |
| 30432 | 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 | 31214 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { |
| 30436 | 31215 | continue; |
| ... | ... | @@ -30440,7 +31219,7 @@ fn resolvePeerTypes( |
| 30440 | 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 | 31223 | continue; |
| 30445 | 31224 | }, |
| 30446 | 31225 | else => { |
| ... | ... | @@ -30453,7 +31232,7 @@ fn resolvePeerTypes( |
| 30453 | 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 | 31236 | continue; |
| 30458 | 31237 | } else { |
| 30459 | 31238 | err_set_ty = candidate_ty; |
| ... | ... | @@ -30464,14 +31243,14 @@ fn resolvePeerTypes( |
| 30464 | 31243 | .ErrorUnion => switch (chosen_ty_tag) { |
| 30465 | 31244 | .ErrorSet => { |
| 30466 | 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 | 31248 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { |
| 30470 | 31249 | err_set_ty = chosen_set_ty; |
| 30471 | 31250 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { |
| 30472 | 31251 | err_set_ty = null; |
| 30473 | 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 | 31255 | chosen = candidate; |
| 30477 | 31256 | chosen_i = candidate_i + 1; |
| ... | ... | @@ -30479,8 +31258,8 @@ fn resolvePeerTypes( |
| 30479 | 31258 | }, |
| 30480 | 31259 | |
| 30481 | 31260 | .ErrorUnion => { |
| 30482 | const chosen_payload_ty = chosen_ty.errorUnionPayload(); | |
| 30483 | const candidate_payload_ty = candidate_ty.errorUnionPayload(); | |
| 31261 | const chosen_payload_ty = chosen_ty.errorUnionPayload(mod); | |
| 31262 | const candidate_payload_ty = candidate_ty.errorUnionPayload(mod); | |
| 30484 | 31263 | |
| 30485 | 31264 | const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok; |
| 30486 | 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 | 31273 | chosen_i = candidate_i + 1; |
| 30495 | 31274 | } |
| 30496 | 31275 | |
| 30497 | const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); | |
| 30498 | const candidate_set_ty = candidate_ty.errorUnionSet(); | |
| 31276 | const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); | |
| 31277 | const candidate_set_ty = candidate_ty.errorUnionSet(mod); | |
| 30499 | 31278 | |
| 30500 | 31279 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { |
| 30501 | 31280 | err_set_ty = chosen_set_ty; |
| 30502 | 31281 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { |
| 30503 | 31282 | err_set_ty = candidate_set_ty; |
| 30504 | 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 | 31286 | continue; |
| 30508 | 31287 | } |
| ... | ... | @@ -30510,26 +31289,26 @@ fn resolvePeerTypes( |
| 30510 | 31289 | |
| 30511 | 31290 | else => { |
| 30512 | 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 | 31293 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { |
| 30515 | 31294 | err_set_ty = chosen_set_ty; |
| 30516 | 31295 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { |
| 30517 | 31296 | err_set_ty = null; |
| 30518 | 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 | 31302 | chosen = candidate; |
| 30524 | 31303 | chosen_i = candidate_i + 1; |
| 30525 | 31304 | continue; |
| 30526 | 31305 | }, |
| 30527 | 31306 | }, |
| 30528 | 31307 | .Pointer => { |
| 30529 | const cand_info = candidate_ty.ptrInfo().data; | |
| 31308 | const cand_info = candidate_ty.ptrInfo(mod); | |
| 30530 | 31309 | switch (chosen_ty_tag) { |
| 30531 | 31310 | .Pointer => { |
| 30532 | const chosen_info = chosen_ty.ptrInfo().data; | |
| 31311 | const chosen_info = chosen_ty.ptrInfo(mod); | |
| 30533 | 31312 | |
| 30534 | 31313 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; |
| 30535 | 31314 | |
| ... | ... | @@ -30537,7 +31316,7 @@ fn resolvePeerTypes( |
| 30537 | 31316 | // *[N]T to []T |
| 30538 | 31317 | if ((cand_info.size == .Many or cand_info.size == .Slice) and |
| 30539 | 31318 | chosen_info.size == .One and |
| 30540 | chosen_info.pointee_type.zigTypeTag() == .Array) | |
| 31319 | chosen_info.pointee_type.zigTypeTag(mod) == .Array) | |
| 30541 | 31320 | { |
| 30542 | 31321 | // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` |
| 30543 | 31322 | convert_to_slice = false; |
| ... | ... | @@ -30546,7 +31325,7 @@ fn resolvePeerTypes( |
| 30546 | 31325 | continue; |
| 30547 | 31326 | } |
| 30548 | 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 | 31329 | (chosen_info.size == .Many or chosen_info.size == .Slice)) |
| 30551 | 31330 | { |
| 30552 | 31331 | // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` |
| ... | ... | @@ -30559,11 +31338,11 @@ fn resolvePeerTypes( |
| 30559 | 31338 | // Keep the one whose element type can be coerced into. |
| 30560 | 31339 | if (chosen_info.size == .One and |
| 30561 | 31340 | cand_info.size == .One and |
| 30562 | chosen_info.pointee_type.zigTypeTag() == .Array and | |
| 30563 | cand_info.pointee_type.zigTypeTag() == .Array) | |
| 31341 | chosen_info.pointee_type.zigTypeTag(mod) == .Array and | |
| 31342 | cand_info.pointee_type.zigTypeTag(mod) == .Array) | |
| 30564 | 31343 | { |
| 30565 | const chosen_elem_ty = chosen_info.pointee_type.childType(); | |
| 30566 | const cand_elem_ty = cand_info.pointee_type.childType(); | |
| 31344 | const chosen_elem_ty = chosen_info.pointee_type.childType(mod); | |
| 31345 | const cand_elem_ty = cand_info.pointee_type.childType(mod); | |
| 30567 | 31346 | |
| 30568 | 31347 | const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src); |
| 30569 | 31348 | if (chosen_ok) { |
| ... | ... | @@ -30629,17 +31408,16 @@ fn resolvePeerTypes( |
| 30629 | 31408 | } |
| 30630 | 31409 | }, |
| 30631 | 31410 | .Optional => { |
| 30632 | var opt_child_buf: Type.Payload.ElemType = undefined; | |
| 30633 | const chosen_ptr_ty = chosen_ty.optionalChild(&opt_child_buf); | |
| 30634 | if (chosen_ptr_ty.zigTypeTag() == .Pointer) { | |
| 30635 | const chosen_info = chosen_ptr_ty.ptrInfo().data; | |
| 31411 | const chosen_ptr_ty = chosen_ty.optionalChild(mod); | |
| 31412 | if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) { | |
| 31413 | const chosen_info = chosen_ptr_ty.ptrInfo(mod); | |
| 30636 | 31414 | |
| 30637 | 31415 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; |
| 30638 | 31416 | |
| 30639 | 31417 | // *[N]T to ?![*]T |
| 30640 | 31418 | // *[N]T to ?![]T |
| 30641 | 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 | 31421 | (chosen_info.size == .Many or chosen_info.size == .Slice)) |
| 30644 | 31422 | { |
| 30645 | 31423 | continue; |
| ... | ... | @@ -30647,16 +31425,16 @@ fn resolvePeerTypes( |
| 30647 | 31425 | } |
| 30648 | 31426 | }, |
| 30649 | 31427 | .ErrorUnion => { |
| 30650 | const chosen_ptr_ty = chosen_ty.errorUnionPayload(); | |
| 30651 | if (chosen_ptr_ty.zigTypeTag() == .Pointer) { | |
| 30652 | const chosen_info = chosen_ptr_ty.ptrInfo().data; | |
| 31428 | const chosen_ptr_ty = chosen_ty.errorUnionPayload(mod); | |
| 31429 | if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) { | |
| 31430 | const chosen_info = chosen_ptr_ty.ptrInfo(mod); | |
| 30653 | 31431 | |
| 30654 | 31432 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; |
| 30655 | 31433 | |
| 30656 | 31434 | // *[N]T to E![*]T |
| 30657 | 31435 | // *[N]T to E![]T |
| 30658 | 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 | 31438 | (chosen_info.size == .Many or chosen_info.size == .Slice)) |
| 30661 | 31439 | { |
| 30662 | 31440 | continue; |
| ... | ... | @@ -30664,7 +31442,7 @@ fn resolvePeerTypes( |
| 30664 | 31442 | } |
| 30665 | 31443 | }, |
| 30666 | 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 | 31446 | chosen = candidate; |
| 30669 | 31447 | chosen_i = candidate_i + 1; |
| 30670 | 31448 | continue; |
| ... | ... | @@ -30674,15 +31452,14 @@ fn resolvePeerTypes( |
| 30674 | 31452 | } |
| 30675 | 31453 | }, |
| 30676 | 31454 | .Optional => { |
| 30677 | var opt_child_buf: Type.Payload.ElemType = undefined; | |
| 30678 | const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf); | |
| 31455 | const opt_child_ty = candidate_ty.optionalChild(mod); | |
| 30679 | 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 | 31458 | any_are_null = true; |
| 30682 | 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 | 31463 | any_are_null = false; |
| 30687 | 31464 | chosen = candidate; |
| 30688 | 31465 | chosen_i = candidate_i + 1; |
| ... | ... | @@ -30690,23 +31467,23 @@ fn resolvePeerTypes( |
| 30690 | 31467 | }, |
| 30691 | 31468 | .Vector => switch (chosen_ty_tag) { |
| 30692 | 31469 | .Vector => { |
| 30693 | const chosen_len = chosen_ty.vectorLen(); | |
| 30694 | const candidate_len = candidate_ty.vectorLen(); | |
| 31470 | const chosen_len = chosen_ty.vectorLen(mod); | |
| 31471 | const candidate_len = candidate_ty.vectorLen(mod); | |
| 30695 | 31472 | if (chosen_len != candidate_len) |
| 30696 | 31473 | continue; |
| 30697 | 31474 | |
| 30698 | const chosen_child_ty = chosen_ty.childType(); | |
| 30699 | const candidate_child_ty = candidate_ty.childType(); | |
| 30700 | if (chosen_child_ty.zigTypeTag() == .Int and candidate_child_ty.zigTypeTag() == .Int) { | |
| 30701 | const chosen_info = chosen_child_ty.intInfo(target); | |
| 30702 | const candidate_info = candidate_child_ty.intInfo(target); | |
| 31475 | const chosen_child_ty = chosen_ty.childType(mod); | |
| 31476 | const candidate_child_ty = candidate_ty.childType(mod); | |
| 31477 | if (chosen_child_ty.zigTypeTag(mod) == .Int and candidate_child_ty.zigTypeTag(mod) == .Int) { | |
| 31478 | const chosen_info = chosen_child_ty.intInfo(mod); | |
| 31479 | const candidate_info = candidate_child_ty.intInfo(mod); | |
| 30703 | 31480 | if (chosen_info.bits < candidate_info.bits) { |
| 30704 | 31481 | chosen = candidate; |
| 30705 | 31482 | chosen_i = candidate_i + 1; |
| 30706 | 31483 | } |
| 30707 | 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 | 31487 | if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) { |
| 30711 | 31488 | chosen = candidate; |
| 30712 | 31489 | chosen_i = candidate_i + 1; |
| ... | ... | @@ -30725,8 +31502,8 @@ fn resolvePeerTypes( |
| 30725 | 31502 | .Vector => continue, |
| 30726 | 31503 | else => {}, |
| 30727 | 31504 | }, |
| 30728 | .Fn => if (chosen_ty.isSinglePointer() and chosen_ty.isConstPtr() and chosen_ty.childType().zigTypeTag() == .Fn) { | |
| 30729 | if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(), candidate_ty, target, src, src)) { | |
| 31505 | .Fn => if (chosen_ty.isSinglePointer(mod) and chosen_ty.isConstPtr(mod) and chosen_ty.childType(mod).zigTypeTag(mod) == .Fn) { | |
| 31506 | if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(mod), candidate_ty, target, src, src)) { | |
| 30730 | 31507 | continue; |
| 30731 | 31508 | } |
| 30732 | 31509 | }, |
| ... | ... | @@ -30746,8 +31523,7 @@ fn resolvePeerTypes( |
| 30746 | 31523 | continue; |
| 30747 | 31524 | }, |
| 30748 | 31525 | .Optional => { |
| 30749 | var opt_child_buf: Type.Payload.ElemType = undefined; | |
| 30750 | const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf); | |
| 31526 | const opt_child_ty = chosen_ty.optionalChild(mod); | |
| 30751 | 31527 | if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) { |
| 30752 | 31528 | continue; |
| 30753 | 31529 | } |
| ... | ... | @@ -30759,7 +31535,7 @@ fn resolvePeerTypes( |
| 30759 | 31535 | } |
| 30760 | 31536 | }, |
| 30761 | 31537 | .ErrorUnion => { |
| 30762 | const payload_ty = chosen_ty.errorUnionPayload(); | |
| 31538 | const payload_ty = chosen_ty.errorUnionPayload(mod); | |
| 30763 | 31539 | if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) { |
| 30764 | 31540 | continue; |
| 30765 | 31541 | } |
| ... | ... | @@ -30776,7 +31552,7 @@ fn resolvePeerTypes( |
| 30776 | 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 | 31556 | continue; |
| 30781 | 31557 | } else { |
| 30782 | 31558 | err_set_ty = chosen_ty; |
| ... | ... | @@ -30789,28 +31565,28 @@ fn resolvePeerTypes( |
| 30789 | 31565 | // At this point, we hit a compile error. We need to recover |
| 30790 | 31566 | // the source locations. |
| 30791 | 31567 | const chosen_src = candidate_srcs.resolve( |
| 30792 | sema.gpa, | |
| 30793 | sema.mod.declPtr(block.src_decl), | |
| 31568 | mod, | |
| 31569 | mod.declPtr(block.src_decl), | |
| 30794 | 31570 | chosen_i, |
| 30795 | 31571 | ); |
| 30796 | 31572 | const candidate_src = candidate_srcs.resolve( |
| 30797 | sema.gpa, | |
| 30798 | sema.mod.declPtr(block.src_decl), | |
| 31573 | mod, | |
| 31574 | mod.declPtr(block.src_decl), | |
| 30799 | 31575 | candidate_i + 1, |
| 30800 | 31576 | ); |
| 30801 | 31577 | |
| 30802 | 31578 | const msg = msg: { |
| 30803 | 31579 | const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{ |
| 30804 | chosen_ty.fmt(sema.mod), | |
| 30805 | candidate_ty.fmt(sema.mod), | |
| 31580 | chosen_ty.fmt(mod), | |
| 31581 | candidate_ty.fmt(mod), | |
| 30806 | 31582 | }); |
| 30807 | 31583 | errdefer msg.destroy(sema.gpa); |
| 30808 | 31584 | |
| 30809 | 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 | 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 | 31591 | break :msg msg; |
| 30816 | 31592 | }; |
| ... | ... | @@ -30821,139 +31597,231 @@ fn resolvePeerTypes( |
| 30821 | 31597 | |
| 30822 | 31598 | if (convert_to_slice) { |
| 30823 | 31599 | // turn *[N]T => []T |
| 30824 | const chosen_child_ty = chosen_ty.childType(); | |
| 30825 | var info = chosen_ty.ptrInfo(); | |
| 30826 | info.data.sentinel = chosen_child_ty.sentinel(); | |
| 30827 | info.data.size = .Slice; | |
| 30828 | info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr()); | |
| 30829 | info.data.pointee_type = chosen_child_ty.elemType2(); | |
| 30830 | ||
| 30831 | const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); | |
| 31600 | const chosen_child_ty = chosen_ty.childType(mod); | |
| 31601 | var info = chosen_ty.ptrInfo(mod); | |
| 31602 | info.sentinel = chosen_child_ty.sentinel(mod); | |
| 31603 | info.size = .Slice; | |
| 31604 | info.mutable = !(seen_const or chosen_child_ty.isConstPtr(mod)); | |
| 31605 | info.pointee_type = chosen_child_ty.elemType2(mod); | |
| 31606 | ||
| 31607 | const new_ptr_ty = try Type.ptr(sema.arena, mod, info); | |
| 30832 | 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 | 31610 | else |
| 30835 | 31611 | new_ptr_ty; |
| 30836 | 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 | 31616 | if (seen_const) { |
| 30841 | 31617 | // turn []T => []const T |
| 30842 | switch (chosen_ty.zigTypeTag()) { | |
| 31618 | switch (chosen_ty.zigTypeTag(mod)) { | |
| 30843 | 31619 | .ErrorUnion => { |
| 30844 | const ptr_ty = chosen_ty.errorUnionPayload(); | |
| 30845 | var info = ptr_ty.ptrInfo(); | |
| 30846 | info.data.mutable = false; | |
| 30847 | const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); | |
| 31620 | const ptr_ty = chosen_ty.errorUnionPayload(mod); | |
| 31621 | var info = ptr_ty.ptrInfo(mod); | |
| 31622 | info.mutable = false; | |
| 31623 | const new_ptr_ty = try Type.ptr(sema.arena, mod, info); | |
| 30848 | 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 | 31626 | else |
| 30851 | 31627 | new_ptr_ty; |
| 30852 | const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); | |
| 30853 | return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod); | |
| 31628 | const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); | |
| 31629 | return try mod.errorUnionType(set_ty, opt_ptr_ty); | |
| 30854 | 31630 | }, |
| 30855 | 31631 | .Pointer => { |
| 30856 | var info = chosen_ty.ptrInfo(); | |
| 30857 | info.data.mutable = false; | |
| 30858 | const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); | |
| 31632 | var info = chosen_ty.ptrInfo(mod); | |
| 31633 | info.mutable = false; | |
| 31634 | const new_ptr_ty = try Type.ptr(sema.arena, mod, info); | |
| 30859 | 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 | 31637 | else |
| 30862 | 31638 | new_ptr_ty; |
| 30863 | 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 | 31642 | else => return chosen_ty, |
| 30867 | 31643 | } |
| 30868 | 31644 | } |
| 30869 | 31645 | |
| 30870 | 31646 | if (any_are_null) { |
| 30871 | const opt_ty = switch (chosen_ty.zigTypeTag()) { | |
| 31647 | const opt_ty = switch (chosen_ty.zigTypeTag(mod)) { | |
| 30872 | 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 | 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 | 31656 | .ErrorSet => return ty, |
| 30881 | 31657 | .ErrorUnion => { |
| 30882 | const payload_ty = chosen_ty.errorUnionPayload(); | |
| 30883 | return try Type.errorUnion(sema.arena, ty, payload_ty, sema.mod); | |
| 31658 | const payload_ty = chosen_ty.errorUnionPayload(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 | 31664 | return chosen_ty; |
| 30889 | 31665 | } |
| 30890 | 31666 | |
| 30891 | pub fn resolveFnTypes(sema: *Sema, fn_info: Type.Payload.Function.Data) CompileError!void { | |
| 30892 | try sema.resolveTypeFully(fn_info.return_type); | |
| 31667 | pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void { | |
| 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 | 31672 | // Ensure the type exists so that backends can assume that. |
| 30896 | 31673 | _ = try sema.getBuiltinType("StackTrace"); |
| 30897 | 31674 | } |
| 30898 | 31675 | |
| 30899 | for (fn_info.param_types) |param_ty| { | |
| 30900 | try sema.resolveTypeFully(param_ty); | |
| 31676 | for (0..mod.typeToFunc(fn_ty).?.param_types.len) |i| { | |
| 31677 | try sema.resolveTypeFully(mod.typeToFunc(fn_ty).?.param_types[i].toType()); | |
| 30901 | 31678 | } |
| 30902 | 31679 | } |
| 30903 | 31680 | |
| 30904 | 31681 | /// Make it so that calling hash() and eql() on `val` will not assert due |
| 30905 | 31682 | /// to a type not having its layout resolved. |
| 30906 | fn resolveLazyValue(sema: *Sema, val: Value) CompileError!void { | |
| 30907 | switch (val.tag()) { | |
| 30908 | .lazy_align => { | |
| 30909 | const ty = val.castTag(.lazy_align).?.data; | |
| 30910 | return sema.resolveTypeLayout(ty); | |
| 30911 | }, | |
| 30912 | .lazy_size => { | |
| 30913 | const ty = val.castTag(.lazy_size).?.data; | |
| 30914 | return sema.resolveTypeLayout(ty); | |
| 30915 | }, | |
| 30916 | .comptime_field_ptr => { | |
| 30917 | const field_ptr = val.castTag(.comptime_field_ptr).?.data; | |
| 30918 | return sema.resolveLazyValue(field_ptr.field_val); | |
| 30919 | }, | |
| 30920 | .eu_payload, | |
| 30921 | .opt_payload, | |
| 30922 | => { | |
| 30923 | const sub_val = val.cast(Value.Payload.SubValue).?.data; | |
| 30924 | return sema.resolveLazyValue(sub_val); | |
| 30925 | }, | |
| 30926 | .@"union" => { | |
| 30927 | const union_val = val.castTag(.@"union").?.data; | |
| 30928 | return sema.resolveLazyValue(union_val.val); | |
| 30929 | }, | |
| 30930 | .aggregate => { | |
| 30931 | const aggregate = val.castTag(.aggregate).?.data; | |
| 30932 | for (aggregate) |elem_val| { | |
| 30933 | try sema.resolveLazyValue(elem_val); | |
| 31683 | fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { | |
| 31684 | const mod = sema.mod; | |
| 31685 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 31686 | .int => |int| switch (int.storage) { | |
| 31687 | .u64, .i64, .big_int => return val, | |
| 31688 | .lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{ | |
| 31689 | .ty = int.ty, | |
| 31690 | .storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? }, | |
| 31691 | } })).toValue(), | |
| 31692 | }, | |
| 31693 | .ptr => |ptr| { | |
| 31694 | const resolved_len = switch (ptr.len) { | |
| 31695 | .none => .none, | |
| 31696 | else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(), | |
| 31697 | }; | |
| 31698 | switch (ptr.addr) { | |
| 31699 | .decl, .mut_decl => return if (resolved_len == ptr.len) | |
| 31700 | val | |
| 31701 | else | |
| 31702 | (try mod.intern(.{ .ptr = .{ | |
| 31703 | .ty = ptr.ty, | |
| 31704 | .addr = switch (ptr.addr) { | |
| 31705 | .decl => |decl| .{ .decl = decl }, | |
| 31706 | .mut_decl => |mut_decl| .{ .mut_decl = mut_decl }, | |
| 31707 | else => unreachable, | |
| 31708 | }, | |
| 31709 | .len = resolved_len, | |
| 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 => { | |
| 30937 | const slice = val.castTag(.slice).?.data; | |
| 30938 | try sema.resolveLazyValue(slice.ptr); | |
| 30939 | return sema.resolveLazyValue(slice.len); | |
| 31772 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 31773 | .bytes => return val, | |
| 31774 | .elems => |elems| { | |
| 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 | 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 | 31816 | .Struct => return sema.resolveStructLayout(ty), |
| 30948 | 31817 | .Union => return sema.resolveUnionLayout(ty), |
| 30949 | 31818 | .Array => { |
| 30950 | if (ty.arrayLenIncludingSentinel() == 0) return; | |
| 30951 | const elem_ty = ty.childType(); | |
| 31819 | if (ty.arrayLenIncludingSentinel(mod) == 0) return; | |
| 31820 | const elem_ty = ty.childType(mod); | |
| 30952 | 31821 | return sema.resolveTypeLayout(elem_ty); |
| 30953 | 31822 | }, |
| 30954 | 31823 | .Optional => { |
| 30955 | var buf: Type.Payload.ElemType = undefined; | |
| 30956 | const payload_ty = ty.optionalChild(&buf); | |
| 31824 | const payload_ty = ty.optionalChild(mod); | |
| 30957 | 31825 | // In case of querying the ABI alignment of this optional, we will ask |
| 30958 | 31826 | // for hasRuntimeBits() of the payload type, so we need "requires comptime" |
| 30959 | 31827 | // to be known already before this function returns. |
| ... | ... | @@ -30961,37 +31829,37 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { |
| 30961 | 31829 | return sema.resolveTypeLayout(payload_ty); |
| 30962 | 31830 | }, |
| 30963 | 31831 | .ErrorUnion => { |
| 30964 | const payload_ty = ty.errorUnionPayload(); | |
| 31832 | const payload_ty = ty.errorUnionPayload(mod); | |
| 30965 | 31833 | return sema.resolveTypeLayout(payload_ty); |
| 30966 | 31834 | }, |
| 30967 | 31835 | .Fn => { |
| 30968 | const info = ty.fnInfo(); | |
| 31836 | const info = mod.typeToFunc(ty).?; | |
| 30969 | 31837 | if (info.is_generic) { |
| 30970 | 31838 | // Resolving of generic function types is deferred to when |
| 30971 | 31839 | // the function is instantiated. |
| 30972 | 31840 | return; |
| 30973 | 31841 | } |
| 30974 | 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 | 31847 | else => {}, |
| 30980 | 31848 | } |
| 30981 | 31849 | } |
| 30982 | 31850 | |
| 30983 | 31851 | fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31852 | const mod = sema.mod; | |
| 30984 | 31853 | const resolved_ty = try sema.resolveTypeFields(ty); |
| 30985 | if (resolved_ty.castTag(.@"struct")) |payload| { | |
| 30986 | const struct_obj = payload.data; | |
| 31854 | if (mod.typeToStruct(resolved_ty)) |struct_obj| { | |
| 30987 | 31855 | switch (struct_obj.status) { |
| 30988 | 31856 | .none, .have_field_types => {}, |
| 30989 | 31857 | .field_types_wip, .layout_wip => { |
| 30990 | 31858 | const msg = try Module.ErrorMsg.create( |
| 30991 | 31859 | sema.gpa, |
| 30992 | struct_obj.srcLoc(sema.mod), | |
| 31860 | struct_obj.srcLoc(mod), | |
| 30993 | 31861 | "struct '{}' depends on itself", |
| 30994 | .{ty.fmt(sema.mod)}, | |
| 31862 | .{ty.fmt(mod)}, | |
| 30995 | 31863 | ); |
| 30996 | 31864 | return sema.failWithOwnedErrorMsg(msg); |
| 30997 | 31865 | }, |
| ... | ... | @@ -31015,35 +31883,27 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31015 | 31883 | } |
| 31016 | 31884 | |
| 31017 | 31885 | if (struct_obj.layout == .Packed) { |
| 31018 | try semaBackingIntType(sema.mod, struct_obj); | |
| 31886 | try semaBackingIntType(mod, struct_obj); | |
| 31019 | 31887 | } |
| 31020 | 31888 | |
| 31021 | 31889 | struct_obj.status = .have_layout; |
| 31022 | 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 | 31893 | const msg = try Module.ErrorMsg.create( |
| 31026 | 31894 | sema.gpa, |
| 31027 | struct_obj.srcLoc(sema.mod), | |
| 31895 | struct_obj.srcLoc(mod), | |
| 31028 | 31896 | "struct layout depends on it having runtime bits", |
| 31029 | 31897 | .{}, |
| 31030 | 31898 | ); |
| 31031 | 31899 | return sema.failWithOwnedErrorMsg(msg); |
| 31032 | 31900 | } |
| 31033 | 31901 | |
| 31034 | if (struct_obj.layout == .Auto and sema.mod.backendSupportsFeature(.field_reordering)) { | |
| 31035 | const optimized_order = if (struct_obj.owner_decl == sema.owner_decl_index) | |
| 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 | }; | |
| 31902 | if (struct_obj.layout == .Auto and mod.backendSupportsFeature(.field_reordering)) { | |
| 31903 | const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count()); | |
| 31044 | 31904 | |
| 31045 | 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 | 31907 | @intCast(u32, i) |
| 31048 | 31908 | else |
| 31049 | 31909 | Module.Struct.omitted_field; |
| ... | ... | @@ -31054,11 +31914,11 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31054 | 31914 | sema: *Sema, |
| 31055 | 31915 | |
| 31056 | 31916 | fn lessThan(ctx: @This(), a: u32, b: u32) bool { |
| 31917 | const m = ctx.sema.mod; | |
| 31057 | 31918 | if (a == Module.Struct.omitted_field) return false; |
| 31058 | 31919 | if (b == Module.Struct.omitted_field) return true; |
| 31059 | const target = ctx.sema.mod.getTarget(); | |
| 31060 | return ctx.struct_obj.fields.values()[a].ty.abiAlignment(target) > | |
| 31061 | ctx.struct_obj.fields.values()[b].ty.abiAlignment(target); | |
| 31920 | return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) > | |
| 31921 | ctx.struct_obj.fields.values()[b].ty.abiAlignment(m); | |
| 31062 | 31922 | } |
| 31063 | 31923 | }; |
| 31064 | 31924 | mem.sort(u32, optimized_order, AlignSortContext{ |
| ... | ... | @@ -31073,20 +31933,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31073 | 31933 | |
| 31074 | 31934 | fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void { |
| 31075 | 31935 | const gpa = mod.gpa; |
| 31076 | const target = mod.getTarget(); | |
| 31077 | 31936 | |
| 31078 | 31937 | var fields_bit_sum: u64 = 0; |
| 31079 | 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 | 31942 | const decl_index = struct_obj.owner_decl; |
| 31084 | 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 | 31946 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; |
| 31091 | 31947 | assert(extended.opcode == .struct_decl); |
| 31092 | 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 | 31959 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 31104 | 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 | 31965 | var sema: Sema = .{ |
| 31107 | 31966 | .mod = mod, |
| 31108 | 31967 | .gpa = gpa, |
| 31109 | 31968 | .arena = analysis_arena.allocator(), |
| 31110 | .perm_arena = decl_arena_allocator, | |
| 31111 | 31969 | .code = zir, |
| 31112 | 31970 | .owner_decl = decl, |
| 31113 | 31971 | .owner_decl_index = decl_index, |
| 31114 | 31972 | .func = null, |
| 31973 | .func_index = .none, | |
| 31115 | 31974 | .fn_ret_ty = Type.void, |
| 31116 | 31975 | .owner_func = null, |
| 31976 | .owner_func_index = .none, | |
| 31977 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 31117 | 31978 | }; |
| 31118 | 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 | 31982 | defer wip_captures.deinit(); |
| 31122 | 31983 | |
| 31123 | 31984 | var block: Block = .{ |
| 31124 | 31985 | .parent = null, |
| 31125 | 31986 | .sema = &sema, |
| 31126 | 31987 | .src_decl = decl_index, |
| 31127 | .namespace = &struct_obj.namespace, | |
| 31988 | .namespace = struct_obj.namespace, | |
| 31128 | 31989 | .wip_capture_scope = wip_captures.scope, |
| 31129 | 31990 | .instructions = .{}, |
| 31130 | 31991 | .inlining = null, |
| ... | ... | @@ -31148,21 +32009,27 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31148 | 32009 | }; |
| 31149 | 32010 | |
| 31150 | 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 | 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 | 32018 | } else { |
| 31154 | 32019 | if (fields_bit_sum > std.math.maxInt(u16)) { |
| 31155 | 32020 | var sema: Sema = .{ |
| 31156 | 32021 | .mod = mod, |
| 31157 | 32022 | .gpa = gpa, |
| 31158 | 32023 | .arena = undefined, |
| 31159 | .perm_arena = decl_arena_allocator, | |
| 31160 | 32024 | .code = zir, |
| 31161 | 32025 | .owner_decl = decl, |
| 31162 | 32026 | .owner_decl_index = decl_index, |
| 31163 | 32027 | .func = null, |
| 32028 | .func_index = .none, | |
| 31164 | 32029 | .fn_ret_ty = Type.void, |
| 31165 | 32030 | .owner_func = null, |
| 32031 | .owner_func_index = .none, | |
| 32032 | .comptime_mutable_decls = undefined, | |
| 31166 | 32033 | }; |
| 31167 | 32034 | defer sema.deinit(); |
| 31168 | 32035 | |
| ... | ... | @@ -31170,7 +32037,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31170 | 32037 | .parent = null, |
| 31171 | 32038 | .sema = &sema, |
| 31172 | 32039 | .src_decl = decl_index, |
| 31173 | .namespace = &struct_obj.namespace, | |
| 32040 | .namespace = struct_obj.namespace, | |
| 31174 | 32041 | .wip_capture_scope = undefined, |
| 31175 | 32042 | .instructions = .{}, |
| 31176 | 32043 | .inlining = null, |
| ... | ... | @@ -31178,32 +32045,29 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31178 | 32045 | }; |
| 31179 | 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 = .{ | |
| 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); | |
| 32048 | struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum)); | |
| 31186 | 32049 | } |
| 31187 | 32050 | } |
| 31188 | 32051 | |
| 31189 | 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 | 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 | 32059 | return sema.fail( |
| 31197 | 32060 | block, |
| 31198 | 32061 | src, |
| 31199 | 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 | 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 | 32071 | const msg = msg: { |
| 31208 | 32072 | const msg = try sema.errMsg(block, src, "type '{}' does not support indexing", .{ty.fmt(sema.mod)}); |
| 31209 | 32073 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -31215,12 +32079,13 @@ fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 31215 | 32079 | } |
| 31216 | 32080 | |
| 31217 | 32081 | fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 31218 | if (ty.zigTypeTag() == .Pointer) { | |
| 31219 | switch (ty.ptrSize()) { | |
| 32082 | const mod = sema.mod; | |
| 32083 | if (ty.zigTypeTag(mod) == .Pointer) { | |
| 32084 | switch (ty.ptrSize(mod)) { | |
| 31220 | 32085 | .Slice, .Many, .C => return, |
| 31221 | 32086 | .One => { |
| 31222 | const elem_ty = ty.childType(); | |
| 31223 | if (elem_ty.zigTypeTag() == .Array) return; | |
| 32087 | const elem_ty = ty.childType(mod); | |
| 32088 | if (elem_ty.zigTypeTag(mod) == .Array) return; | |
| 31224 | 32089 | // TODO https://github.com/ziglang/zig/issues/15479 |
| 31225 | 32090 | // if (elem_ty.isTuple()) return; |
| 31226 | 32091 | }, |
| ... | ... | @@ -31236,8 +32101,9 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void |
| 31236 | 32101 | } |
| 31237 | 32102 | |
| 31238 | 32103 | fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 32104 | const mod = sema.mod; | |
| 31239 | 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 | 32107 | switch (union_obj.status) { |
| 31242 | 32108 | .none, .have_field_types => {}, |
| 31243 | 32109 | .field_types_wip, .layout_wip => { |
| ... | ... | @@ -31270,7 +32136,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31270 | 32136 | union_obj.status = .have_layout; |
| 31271 | 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 | 32140 | const msg = try Module.ErrorMsg.create( |
| 31275 | 32141 | sema.gpa, |
| 31276 | 32142 | union_obj.srcLoc(sema.mod), |
| ... | ... | @@ -31285,188 +32151,154 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31285 | 32151 | // for hasRuntimeBits() of each field, so we need "requires comptime" |
| 31286 | 32152 | // to be known already before this function returns. |
| 31287 | 32153 | pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 31288 | return switch (ty.tag()) { | |
| 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 | }, | |
| 32154 | const mod = sema.mod; | |
| 31404 | 32155 | |
| 31405 | .tuple, .anon_struct => { | |
| 31406 | const tuple = ty.tupleFields(); | |
| 31407 | for (tuple.types, 0..) |field_ty, i| { | |
| 31408 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | |
| 31409 | if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty)) { | |
| 31410 | return true; | |
| 32156 | return switch (ty.toIntern()) { | |
| 32157 | .empty_struct_type => false, | |
| 32158 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 32159 | .int_type => false, | |
| 32160 | .ptr_type => |ptr_type| { | |
| 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 | } | |
| 31413 | return false; | |
| 31414 | }, | |
| 32167 | }, | |
| 32168 | .anyframe_type => |child| { | |
| 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" => { | |
| 31417 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 31418 | switch (struct_obj.requires_comptime) { | |
| 31419 | .no, .wip => return false, | |
| 31420 | .yes => 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; | |
| 32246 | .anon_struct_type => |tuple| { | |
| 32247 | for (tuple.types, tuple.values) |field_ty, field_val| { | |
| 32248 | const have_comptime_val = field_val != .none; | |
| 32249 | if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty.toType())) { | |
| 32250 | return true; | |
| 31426 | 32251 | } |
| 31427 | if (requires_comptime) { | |
| 31428 | struct_obj.requires_comptime = .yes; | |
| 31429 | } else { | |
| 31430 | struct_obj.requires_comptime = .no; | |
| 31431 | } | |
| 31432 | return requires_comptime; | |
| 31433 | }, | |
| 31434 | } | |
| 31435 | }, | |
| 32252 | } | |
| 32253 | return false; | |
| 32254 | }, | |
| 31436 | 32255 | |
| 31437 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 31438 | const union_obj = ty.cast(Type.Payload.Union).?.data; | |
| 31439 | switch (union_obj.requires_comptime) { | |
| 31440 | .no, .wip => return false, | |
| 31441 | .yes => return true, | |
| 31442 | .unknown => { | |
| 31443 | var requires_comptime = false; | |
| 31444 | union_obj.requires_comptime = .wip; | |
| 31445 | for (union_obj.fields.values()) |field| { | |
| 31446 | if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true; | |
| 31447 | } | |
| 31448 | if (requires_comptime) { | |
| 31449 | union_obj.requires_comptime = .yes; | |
| 31450 | } else { | |
| 31451 | union_obj.requires_comptime = .no; | |
| 31452 | } | |
| 31453 | return requires_comptime; | |
| 31454 | }, | |
| 31455 | } | |
| 31456 | }, | |
| 32256 | .union_type => |union_type| { | |
| 32257 | const union_obj = mod.unionPtr(union_type.index); | |
| 32258 | switch (union_obj.requires_comptime) { | |
| 32259 | .no, .wip => return false, | |
| 32260 | .yes => return true, | |
| 32261 | .unknown => { | |
| 32262 | var requires_comptime = false; | |
| 32263 | union_obj.requires_comptime = .wip; | |
| 32264 | for (union_obj.fields.values()) |field| { | |
| 32265 | if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true; | |
| 32266 | } | |
| 32267 | if (requires_comptime) { | |
| 32268 | union_obj.requires_comptime = .yes; | |
| 32269 | } else { | |
| 32270 | union_obj.requires_comptime = .no; | |
| 32271 | } | |
| 32272 | return requires_comptime; | |
| 32273 | }, | |
| 32274 | } | |
| 32275 | }, | |
| 31457 | 32276 | |
| 31458 | .error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()), | |
| 31459 | .anyframe_T => { | |
| 31460 | const child_ty = ty.castTag(.anyframe_T).?.data; | |
| 31461 | return sema.resolveTypeRequiresComptime(child_ty); | |
| 31462 | }, | |
| 31463 | .enum_numbered => { | |
| 31464 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; | |
| 31465 | return sema.resolveTypeRequiresComptime(tag_ty); | |
| 31466 | }, | |
| 31467 | .enum_full, .enum_nonexhaustive => { | |
| 31468 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; | |
| 31469 | return sema.resolveTypeRequiresComptime(tag_ty); | |
| 32277 | .opaque_type => false, | |
| 32278 | ||
| 32279 | .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()), | |
| 32280 | ||
| 32281 | // values, not types | |
| 32282 | .undef, | |
| 32283 | .runtime_value, | |
| 32284 | .simple_value, | |
| 32285 | .variable, | |
| 32286 | .extern_func, | |
| 32287 | .func, | |
| 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 | 32306 | /// Returns `error.AnalysisFail` if any of the types (recursively) failed to |
| 31475 | 32307 | /// be resolved. |
| 31476 | 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 | 32311 | .Pointer => { |
| 31479 | const child_ty = try sema.resolveTypeFields(ty.childType()); | |
| 32312 | const child_ty = try sema.resolveTypeFields(ty.childType(mod)); | |
| 31480 | 32313 | return sema.resolveTypeFully(child_ty); |
| 31481 | 32314 | }, |
| 31482 | .Struct => switch (ty.tag()) { | |
| 31483 | .@"struct" => return sema.resolveStructFully(ty), | |
| 31484 | .tuple, .anon_struct => { | |
| 31485 | const tuple = ty.tupleFields(); | |
| 31486 | ||
| 32315 | .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 32316 | .struct_type => return sema.resolveStructFully(ty), | |
| 32317 | .anon_struct_type => |tuple| { | |
| 31487 | 32318 | for (tuple.types) |field_ty| { |
| 31488 | try sema.resolveTypeFully(field_ty); | |
| 32319 | try sema.resolveTypeFully(field_ty.toType()); | |
| 31489 | 32320 | } |
| 31490 | 32321 | }, |
| 31491 | 32322 | else => {}, |
| 31492 | 32323 | }, |
| 31493 | 32324 | .Union => return sema.resolveUnionFully(ty), |
| 31494 | .Array => return sema.resolveTypeFully(ty.childType()), | |
| 32325 | .Array => return sema.resolveTypeFully(ty.childType(mod)), | |
| 31495 | 32326 | .Optional => { |
| 31496 | var buf: Type.Payload.ElemType = undefined; | |
| 31497 | return sema.resolveTypeFully(ty.optionalChild(&buf)); | |
| 32327 | return sema.resolveTypeFully(ty.optionalChild(mod)); | |
| 31498 | 32328 | }, |
| 31499 | .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload()), | |
| 32329 | .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload(mod)), | |
| 31500 | 32330 | .Fn => { |
| 31501 | const info = ty.fnInfo(); | |
| 32331 | const info = mod.typeToFunc(ty).?; | |
| 31502 | 32332 | if (info.is_generic) { |
| 31503 | 32333 | // Resolving of generic function types is deferred to when |
| 31504 | 32334 | // the function is instantiated. |
| 31505 | 32335 | return; |
| 31506 | 32336 | } |
| 31507 | 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 | 32342 | else => {}, |
| 31513 | 32343 | } |
| ... | ... | @@ -31516,9 +32346,9 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { |
| 31516 | 32346 | fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { |
| 31517 | 32347 | try sema.resolveStructLayout(ty); |
| 31518 | 32348 | |
| 32349 | const mod = sema.mod; | |
| 31519 | 32350 | const resolved_ty = try sema.resolveTypeFields(ty); |
| 31520 | const payload = resolved_ty.castTag(.@"struct").?; | |
| 31521 | const struct_obj = payload.data; | |
| 32351 | const struct_obj = mod.typeToStruct(resolved_ty).?; | |
| 31522 | 32352 | |
| 31523 | 32353 | switch (struct_obj.status) { |
| 31524 | 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 | 32376 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| 31547 | 32377 | try sema.resolveUnionLayout(ty); |
| 31548 | 32378 | |
| 32379 | const mod = sema.mod; | |
| 31549 | 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 | 32382 | switch (union_obj.status) { |
| 31552 | 32383 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, |
| 31553 | 32384 | .fully_resolved_wip, .fully_resolved => return, |
| ... | ... | @@ -31572,30 +32403,111 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| 31572 | 32403 | } |
| 31573 | 32404 | |
| 31574 | 32405 | pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { |
| 31575 | switch (ty.tag()) { | |
| 31576 | .@"struct" => { | |
| 31577 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 31578 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | |
| 31579 | return ty; | |
| 31580 | }, | |
| 31581 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 31582 | const union_obj = ty.cast(Type.Payload.Union).?.data; | |
| 31583 | try sema.resolveTypeFieldsUnion(ty, union_obj); | |
| 31584 | return ty; | |
| 31585 | }, | |
| 31586 | .type_info => return sema.getBuiltinType("Type"), | |
| 31587 | .extern_options => return sema.getBuiltinType("ExternOptions"), | |
| 31588 | .export_options => return sema.getBuiltinType("ExportOptions"), | |
| 31589 | .atomic_order => return sema.getBuiltinType("AtomicOrder"), | |
| 31590 | .atomic_rmw_op => return sema.getBuiltinType("AtomicRmwOp"), | |
| 31591 | .calling_convention => return sema.getBuiltinType("CallingConvention"), | |
| 31592 | .address_space => return sema.getBuiltinType("AddressSpace"), | |
| 31593 | .float_mode => return sema.getBuiltinType("FloatMode"), | |
| 31594 | .reduce_op => return sema.getBuiltinType("ReduceOp"), | |
| 31595 | .modifier => return sema.getBuiltinType("CallModifier"), | |
| 31596 | .prefetch_options => return sema.getBuiltinType("PrefetchOptions"), | |
| 32406 | const mod = sema.mod; | |
| 32407 | ||
| 32408 | switch (ty.toIntern()) { | |
| 32409 | .var_args_param_type => unreachable, | |
| 32410 | ||
| 32411 | .none => unreachable, | |
| 32412 | ||
| 32413 | .u1_type, | |
| 32414 | .u8_type, | |
| 32415 | .i8_type, | |
| 32416 | .u16_type, | |
| 32417 | .i16_type, | |
| 32418 | .u29_type, | |
| 32419 | .u32_type, | |
| 32420 | .i32_type, | |
| 32421 | .u64_type, | |
| 32422 | .i64_type, | |
| 32423 | .u80_type, | |
| 32424 | .u128_type, | |
| 32425 | .i128_type, | |
| 32426 | .usize_type, | |
| 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 | 32594 | sema: *Sema, |
| 31683 | 32595 | block: *Block, |
| 31684 | 32596 | src: LazySrcLoc, |
| 31685 | ies: *Module.Fn.InferredErrorSet, | |
| 32597 | ies_index: Module.Fn.InferredErrorSet.Index, | |
| 31686 | 32598 | ) CompileError!void { |
| 32599 | const mod = sema.mod; | |
| 32600 | const ies = mod.inferredErrorSetPtr(ies_index); | |
| 32601 | ||
| 31687 | 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 | 32606 | return sema.fail(block, src, "unable to resolve inferred error set", .{}); |
| 31691 | 32607 | } |
| 31692 | 32608 | |
| 31693 | 32609 | // In order to ensure that all dependencies are properly added to the set, we |
| 31694 | 32610 | // need to ensure the function body is analyzed of the inferred error set. |
| 31695 | 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 | |
| 31697 | // `*Module.Fn`. Not only is the function not relevant to the inferred error set | |
| 32612 | // each call gets a new InferredErrorSet object, which contains the same | |
| 32613 | // `Module.Fn.Index`. Not only is the function not relevant to the inferred error set | |
| 31698 | 32614 | // in this case, it may be a generic function which would cause an assertion failure |
| 31699 | 32615 | // if we called `ensureFuncBodyAnalyzed` on it here. |
| 31700 | const ies_func_owner_decl = sema.mod.declPtr(ies.func.owner_decl); | |
| 31701 | const ies_func_info = ies_func_owner_decl.ty.fnInfo(); | |
| 32616 | const ies_func_owner_decl = mod.declPtr(func.owner_decl); | |
| 32617 | const ies_func_info = mod.typeToFunc(ies_func_owner_decl.ty).?; | |
| 31702 | 32618 | // if ies declared by a inline function with generic return type, the return_type should be generic_poison, |
| 31703 | 32619 | // because inline function does not create a new declaration, and the ies has been filled with analyzeCall, |
| 31704 | 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 | 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 | 32624 | if (ies_func_info.is_generic) { |
| 31709 | 32625 | const msg = msg: { |
| 31710 | 32626 | const msg = try sema.errMsg(block, src, "unable to resolve inferred error set of generic function", .{}); |
| 31711 | 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 | 32630 | break :msg msg; |
| 31715 | 32631 | }; |
| 31716 | 32632 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -31722,10 +32638,11 @@ fn resolveInferredErrorSet( |
| 31722 | 32638 | |
| 31723 | 32639 | ies.is_resolved = true; |
| 31724 | 32640 | |
| 31725 | for (ies.inferred_error_sets.keys()) |other_ies| { | |
| 31726 | if (ies == other_ies) continue; | |
| 31727 | try sema.resolveInferredErrorSet(block, src, other_ies); | |
| 32641 | for (ies.inferred_error_sets.keys()) |other_ies_index| { | |
| 32642 | if (ies_index == other_ies_index) continue; | |
| 32643 | try sema.resolveInferredErrorSet(block, src, other_ies_index); | |
| 31728 | 32644 | |
| 32645 | const other_ies = mod.inferredErrorSetPtr(other_ies_index); | |
| 31729 | 32646 | for (other_ies.errors.keys()) |key| { |
| 31730 | 32647 | try ies.errors.put(sema.gpa, key, {}); |
| 31731 | 32648 | } |
| ... | ... | @@ -31740,15 +32657,17 @@ fn resolveInferredErrorSetTy( |
| 31740 | 32657 | src: LazySrcLoc, |
| 31741 | 32658 | ty: Type, |
| 31742 | 32659 | ) CompileError!void { |
| 31743 | if (ty.castTag(.error_set_inferred)) |inferred| { | |
| 31744 | try sema.resolveInferredErrorSet(block, src, inferred.data); | |
| 32660 | const mod = sema.mod; | |
| 32661 | if (mod.typeToInferredErrorSetIndex(ty).unwrap()) |ies_index| { | |
| 32662 | try sema.resolveInferredErrorSet(block, src, ies_index); | |
| 31745 | 32663 | } |
| 31746 | 32664 | } |
| 31747 | 32665 | |
| 31748 | 32666 | fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void { |
| 31749 | 32667 | const gpa = mod.gpa; |
| 32668 | const ip = &mod.intern_pool; | |
| 31750 | 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 | 32671 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; |
| 31753 | 32672 | assert(extended.opcode == .struct_decl); |
| 31754 | 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 | 32713 | } |
| 31795 | 32714 | |
| 31796 | 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 | 32717 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 31802 | 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 | 32723 | var sema: Sema = .{ |
| 31805 | 32724 | .mod = mod, |
| 31806 | 32725 | .gpa = gpa, |
| 31807 | 32726 | .arena = analysis_arena.allocator(), |
| 31808 | .perm_arena = decl_arena_allocator, | |
| 31809 | 32727 | .code = zir, |
| 31810 | 32728 | .owner_decl = decl, |
| 31811 | 32729 | .owner_decl_index = decl_index, |
| 31812 | 32730 | .func = null, |
| 32731 | .func_index = .none, | |
| 31813 | 32732 | .fn_ret_ty = Type.void, |
| 31814 | 32733 | .owner_func = null, |
| 32734 | .owner_func_index = .none, | |
| 32735 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 31815 | 32736 | }; |
| 31816 | 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 | 32740 | defer wip_captures.deinit(); |
| 31820 | 32741 | |
| 31821 | 32742 | var block_scope: Block = .{ |
| 31822 | 32743 | .parent = null, |
| 31823 | 32744 | .sema = &sema, |
| 31824 | 32745 | .src_decl = decl_index, |
| 31825 | .namespace = &struct_obj.namespace, | |
| 32746 | .namespace = struct_obj.namespace, | |
| 31826 | 32747 | .wip_capture_scope = wip_captures.scope, |
| 31827 | 32748 | .instructions = .{}, |
| 31828 | 32749 | .inlining = null, |
| ... | ... | @@ -31834,13 +32755,13 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31834 | 32755 | } |
| 31835 | 32756 | |
| 31836 | 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 | 32760 | const Field = struct { |
| 31840 | 32761 | type_body_len: u32 = 0, |
| 31841 | 32762 | align_body_len: u32 = 0, |
| 31842 | 32763 | init_body_len: u32 = 0, |
| 31843 | type_ref: Air.Inst.Ref = .none, | |
| 32764 | type_ref: Zir.Inst.Ref = .none, | |
| 31844 | 32765 | }; |
| 31845 | 32766 | const fields = try sema.arena.alloc(Field, fields_len); |
| 31846 | 32767 | var any_inits = false; |
| ... | ... | @@ -31885,30 +32806,30 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31885 | 32806 | extra_index += 1; |
| 31886 | 32807 | |
| 31887 | 32808 | // This string needs to outlive the ZIR code. |
| 31888 | const field_name = if (field_name_zir) |some| | |
| 31889 | try decl_arena_allocator.dupe(u8, some) | |
| 32809 | const field_name = try ip.getOrPutString(gpa, if (field_name_zir) |s| | |
| 32810 | s | |
| 31890 | 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 | 32814 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); |
| 31894 | 32815 | if (gop.found_existing) { |
| 31895 | 32816 | const msg = msg: { |
| 31896 | const field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; | |
| 31897 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); | |
| 32817 | const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy; | |
| 32818 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)}); | |
| 31898 | 32819 | errdefer msg.destroy(gpa); |
| 31899 | 32820 | |
| 31900 | 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 }); | |
| 31902 | try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); | |
| 32822 | const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index }); | |
| 32823 | try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); | |
| 31903 | 32824 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); |
| 31904 | 32825 | break :msg msg; |
| 31905 | 32826 | }; |
| 31906 | 32827 | return sema.failWithOwnedErrorMsg(msg); |
| 31907 | 32828 | } |
| 31908 | 32829 | gop.value_ptr.* = .{ |
| 31909 | .ty = Type.initTag(.noreturn), | |
| 32830 | .ty = Type.noreturn, | |
| 31910 | 32831 | .abi_align = 0, |
| 31911 | .default_val = Value.initTag(.unreachable_value), | |
| 32832 | .default_val = .none, | |
| 31912 | 32833 | .is_comptime = is_comptime, |
| 31913 | 32834 | .offset = undefined, |
| 31914 | 32835 | }; |
| ... | ... | @@ -31934,7 +32855,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31934 | 32855 | if (zir_field.type_ref != .none) { |
| 31935 | 32856 | break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { |
| 31936 | 32857 | error.NeededSourceLocation => { |
| 31937 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | |
| 32858 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 31938 | 32859 | .index = field_i, |
| 31939 | 32860 | .range = .type, |
| 31940 | 32861 | }).lazy; |
| ... | ... | @@ -31950,7 +32871,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31950 | 32871 | const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); |
| 31951 | 32872 | break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) { |
| 31952 | 32873 | error.NeededSourceLocation => { |
| 31953 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | |
| 32874 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 31954 | 32875 | .index = field_i, |
| 31955 | 32876 | .range = .type, |
| 31956 | 32877 | }).lazy; |
| ... | ... | @@ -31960,16 +32881,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31960 | 32881 | else => |e| return e, |
| 31961 | 32882 | }; |
| 31962 | 32883 | }; |
| 31963 | if (field_ty.tag() == .generic_poison) { | |
| 32884 | if (field_ty.isGenericPoison()) { | |
| 31964 | 32885 | return error.GenericPoison; |
| 31965 | 32886 | } |
| 31966 | 32887 | |
| 31967 | 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 | 32892 | const msg = msg: { |
| 31972 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | |
| 32893 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 31973 | 32894 | .index = field_i, |
| 31974 | 32895 | .range = .type, |
| 31975 | 32896 | }).lazy; |
| ... | ... | @@ -31981,9 +32902,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31981 | 32902 | }; |
| 31982 | 32903 | return sema.failWithOwnedErrorMsg(msg); |
| 31983 | 32904 | } |
| 31984 | if (field_ty.zigTypeTag() == .NoReturn) { | |
| 32905 | if (field_ty.zigTypeTag(mod) == .NoReturn) { | |
| 31985 | 32906 | const msg = msg: { |
| 31986 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | |
| 32907 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 31987 | 32908 | .index = field_i, |
| 31988 | 32909 | .range = .type, |
| 31989 | 32910 | }).lazy; |
| ... | ... | @@ -31997,11 +32918,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31997 | 32918 | } |
| 31998 | 32919 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) { |
| 31999 | 32920 | const msg = msg: { |
| 32000 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | |
| 32921 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 32001 | 32922 | .index = field_i, |
| 32002 | 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 | 32926 | errdefer msg.destroy(sema.gpa); |
| 32006 | 32927 | |
| 32007 | 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 | 32931 | break :msg msg; |
| 32011 | 32932 | }; |
| 32012 | 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 | 32935 | const msg = msg: { |
| 32015 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | |
| 32936 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 32016 | 32937 | .index = field_i, |
| 32017 | 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 | 32941 | errdefer msg.destroy(sema.gpa); |
| 32021 | 32942 | |
| 32022 | 32943 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty); |
| ... | ... | @@ -32033,7 +32954,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32033 | 32954 | const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); |
| 32034 | 32955 | field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { |
| 32035 | 32956 | error.NeededSourceLocation => { |
| 32036 | const align_src = struct_obj.fieldSrcLoc(sema.mod, .{ | |
| 32957 | const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 32037 | 32958 | .index = field_i, |
| 32038 | 32959 | .range = .alignment, |
| 32039 | 32960 | }).lazy; |
| ... | ... | @@ -32061,7 +32982,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32061 | 32982 | const field = &struct_obj.fields.values()[field_i]; |
| 32062 | 32983 | const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) { |
| 32063 | 32984 | error.NeededSourceLocation => { |
| 32064 | const init_src = struct_obj.fieldSrcLoc(sema.mod, .{ | |
| 32985 | const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 32065 | 32986 | .index = field_i, |
| 32066 | 32987 | .range = .value, |
| 32067 | 32988 | }).lazy; |
| ... | ... | @@ -32071,17 +32992,21 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32071 | 32992 | else => |e| return e, |
| 32072 | 32993 | }; |
| 32073 | 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 | 32996 | .index = field_i, |
| 32076 | 32997 | .range = .value, |
| 32077 | 32998 | }).lazy; |
| 32078 | 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 | 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 | 33011 | struct_obj.have_field_inits = true; |
| 32087 | 33012 | } |
| ... | ... | @@ -32091,8 +33016,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32091 | 33016 | defer tracy.end(); |
| 32092 | 33017 | |
| 32093 | 33018 | const gpa = mod.gpa; |
| 33019 | const ip = &mod.intern_pool; | |
| 32094 | 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 | 33022 | const extended = zir.instructions.items(.data)[union_obj.zir_index].extended; |
| 32097 | 33023 | assert(extended.opcode == .union_decl); |
| 32098 | 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 | 33060 | extra_index += body.len; |
| 32135 | 33061 | |
| 32136 | 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 | 33064 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 32142 | 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 | 33070 | var sema: Sema = .{ |
| 32145 | 33071 | .mod = mod, |
| 32146 | 33072 | .gpa = gpa, |
| 32147 | 33073 | .arena = analysis_arena.allocator(), |
| 32148 | .perm_arena = decl_arena_allocator, | |
| 32149 | 33074 | .code = zir, |
| 32150 | 33075 | .owner_decl = decl, |
| 32151 | 33076 | .owner_decl_index = decl_index, |
| 32152 | 33077 | .func = null, |
| 33078 | .func_index = .none, | |
| 32153 | 33079 | .fn_ret_ty = Type.void, |
| 32154 | 33080 | .owner_func = null, |
| 33081 | .owner_func_index = .none, | |
| 33082 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 32155 | 33083 | }; |
| 32156 | 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 | 33087 | defer wip_captures.deinit(); |
| 32160 | 33088 | |
| 32161 | 33089 | var block_scope: Block = .{ |
| 32162 | 33090 | .parent = null, |
| 32163 | 33091 | .sema = &sema, |
| 32164 | 33092 | .src_decl = decl_index, |
| 32165 | .namespace = &union_obj.namespace, | |
| 33093 | .namespace = union_obj.namespace, | |
| 32166 | 33094 | .wip_capture_scope = wip_captures.scope, |
| 32167 | 33095 | .instructions = .{}, |
| 32168 | 33096 | .inlining = null, |
| ... | ... | @@ -32178,66 +33106,61 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32178 | 33106 | } |
| 32179 | 33107 | |
| 32180 | 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 | 33116 | var int_tag_ty: Type = undefined; |
| 32185 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; | |
| 32186 | var enum_value_map: ?*Module.EnumNumbered.ValueMap = null; | |
| 32187 | var tag_ty_field_names: ?Module.EnumFull.NameMap = null; | |
| 33117 | var enum_field_names: []InternPool.NullTerminatedString = &.{}; | |
| 33118 | var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}; | |
| 33119 | var explicit_tags_seen: []bool = &.{}; | |
| 32188 | 33120 | if (tag_type_ref != .none) { |
| 32189 | 33121 | const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x }; |
| 32190 | 33122 | const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref); |
| 32191 | 33123 | if (small.auto_enum_tag) { |
| 32192 | 33124 | // The provided type is an integer type and we must construct the enum tag type here. |
| 32193 | 33125 | int_tag_ty = provided_ty; |
| 32194 | if (int_tag_ty.zigTypeTag() != .Int and int_tag_ty.zigTypeTag() != .ComptimeInt) { | |
| 32195 | return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(sema.mod)}); | |
| 33126 | if (int_tag_ty.zigTypeTag(mod) != .Int and int_tag_ty.zigTypeTag(mod) != .ComptimeInt) { | |
| 33127 | return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(mod)}); | |
| 32196 | 33128 | } |
| 32197 | 33129 | |
| 32198 | 33130 | if (fields_len > 0) { |
| 32199 | var field_count_val: Value.Payload.U64 = .{ | |
| 32200 | .base = .{ .tag = .int_u64 }, | |
| 32201 | .data = fields_len - 1, | |
| 32202 | }; | |
| 32203 | if (!(try sema.intFitsInType(Value.initPayload(&field_count_val.base), int_tag_ty, null))) { | |
| 33131 | const field_count_val = try mod.intValue(Type.comptime_int, fields_len - 1); | |
| 33132 | if (!(try sema.intFitsInType(field_count_val, int_tag_ty, null))) { | |
| 32204 | 33133 | const msg = msg: { |
| 32205 | 33134 | const msg = try sema.errMsg(&block_scope, tag_ty_src, "specified integer tag type cannot represent every field", .{}); |
| 32206 | 33135 | errdefer msg.destroy(sema.gpa); |
| 32207 | 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 | 33138 | fields_len - 1, |
| 32210 | 33139 | }); |
| 32211 | 33140 | break :msg msg; |
| 32212 | 33141 | }; |
| 32213 | 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 | 33147 | } else { |
| 32221 | 33148 | // The provided type is the enum tag type. |
| 32222 | union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator); | |
| 32223 | if (union_obj.tag_ty.zigTypeTag() != .Enum) { | |
| 32224 | return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)}); | |
| 32225 | } | |
| 33149 | union_obj.tag_ty = provided_ty; | |
| 33150 | const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) { | |
| 33151 | .enum_type => |x| x, | |
| 33152 | else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(mod)}), | |
| 33153 | }; | |
| 32226 | 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 | |
| 32228 | // missing or extraneous fields later. | |
| 32229 | tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena); | |
| 33155 | // A flag per field is used to check for missing and extraneous fields. | |
| 33156 | explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); | |
| 33157 | @memset(explicit_tags_seen, false); | |
| 32230 | 33158 | } |
| 32231 | 33159 | } else { |
| 32232 | 33160 | // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis |
| 32233 | 33161 | // purposes, we still auto-generate an enum tag type the same way. That the union is |
| 32234 | 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); | |
| 32236 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; | |
| 32237 | } | |
| 32238 | ||
| 32239 | if (fields_len == 0) { | |
| 32240 | return; | |
| 33163 | enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); | |
| 32241 | 33164 | } |
| 32242 | 33165 | |
| 32243 | 33166 | const bits_per_field = 4; |
| ... | ... | @@ -32281,17 +33204,17 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32281 | 33204 | break :blk align_ref; |
| 32282 | 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 | 33208 | const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); |
| 32286 | 33209 | extra_index += 1; |
| 32287 | 33210 | break :blk try sema.resolveInst(tag_ref); |
| 32288 | 33211 | } else .none; |
| 32289 | 33212 | |
| 32290 | if (enum_value_map) |map| { | |
| 32291 | const copied_val = if (tag_ref != .none) blk: { | |
| 33213 | if (enum_field_vals.capacity() > 0) { | |
| 33214 | const enum_tag_val = if (tag_ref != .none) blk: { | |
| 32292 | 33215 | const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) { |
| 32293 | 33216 | error.NeededSourceLocation => { |
| 32294 | const val_src = union_obj.fieldSrcLoc(sema.mod, .{ | |
| 33217 | const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ | |
| 32295 | 33218 | .index = field_i, |
| 32296 | 33219 | .range = .value, |
| 32297 | 33220 | }).lazy; |
| ... | ... | @@ -32302,27 +33225,22 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32302 | 33225 | }; |
| 32303 | 33226 | last_tag_val = val; |
| 32304 | 33227 | |
| 32305 | // This puts the memory into the union arena, not the enum arena, but | |
| 32306 | // it is OK since they share the same lifetime. | |
| 32307 | break :blk try val.copy(decl_arena_allocator); | |
| 33228 | break :blk val; | |
| 32308 | 33229 | } else blk: { |
| 32309 | 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 | 33232 | else |
| 32312 | Value.zero; | |
| 33233 | try mod.intValue(int_tag_ty, 0); | |
| 32313 | 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, .{ | |
| 32318 | .ty = int_tag_ty, | |
| 32319 | .mod = mod, | |
| 32320 | }); | |
| 33238 | const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern()); | |
| 32321 | 33239 | if (gop.found_existing) { |
| 32322 | const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; | |
| 32323 | const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = gop.index }).lazy; | |
| 33240 | const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy; | |
| 33241 | const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy; | |
| 32324 | 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 | 33244 | errdefer msg.destroy(gpa); |
| 32327 | 33245 | try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{}); |
| 32328 | 33246 | break :msg msg; |
| ... | ... | @@ -32332,19 +33250,19 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32332 | 33250 | } |
| 32333 | 33251 | |
| 32334 | 33252 | // This string needs to outlive the ZIR code. |
| 32335 | const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); | |
| 32336 | if (enum_field_names) |set| { | |
| 32337 | set.putAssumeCapacity(field_name, {}); | |
| 33253 | const field_name = try ip.getOrPutString(gpa, field_name_zir); | |
| 33254 | if (enum_field_names.len != 0) { | |
| 33255 | enum_field_names[field_i] = field_name; | |
| 32338 | 33256 | } |
| 32339 | 33257 | |
| 32340 | 33258 | const field_ty: Type = if (!has_type) |
| 32341 | 33259 | Type.void |
| 32342 | 33260 | else if (field_type_ref == .none) |
| 32343 | Type.initTag(.noreturn) | |
| 33261 | Type.noreturn | |
| 32344 | 33262 | else |
| 32345 | 33263 | sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) { |
| 32346 | 33264 | error.NeededSourceLocation => { |
| 32347 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | |
| 33265 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ | |
| 32348 | 33266 | .index = field_i, |
| 32349 | 33267 | .range = .type, |
| 32350 | 33268 | }).lazy; |
| ... | ... | @@ -32354,46 +33272,54 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32354 | 33272 | else => |e| return e, |
| 32355 | 33273 | }; |
| 32356 | 33274 | |
| 32357 | if (field_ty.tag() == .generic_poison) { | |
| 33275 | if (field_ty.isGenericPoison()) { | |
| 32358 | 33276 | return error.GenericPoison; |
| 32359 | 33277 | } |
| 32360 | 33278 | |
| 32361 | 33279 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 32362 | 33280 | if (gop.found_existing) { |
| 32363 | 33281 | const msg = msg: { |
| 32364 | const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; | |
| 32365 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); | |
| 33282 | const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy; | |
| 33283 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{}'", .{ | |
| 33284 | field_name.fmt(ip), | |
| 33285 | }); | |
| 32366 | 33286 | errdefer msg.destroy(gpa); |
| 32367 | 33287 | |
| 32368 | 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; | |
| 32370 | try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); | |
| 33289 | const prev_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = prev_field_index }).lazy; | |
| 33290 | try mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{}); | |
| 32371 | 33291 | try sema.errNote(&block_scope, src, msg, "union declared here", .{}); |
| 32372 | 33292 | break :msg msg; |
| 32373 | 33293 | }; |
| 32374 | 33294 | return sema.failWithOwnedErrorMsg(msg); |
| 32375 | 33295 | } |
| 32376 | 33296 | |
| 32377 | if (tag_ty_field_names) |*names| { | |
| 32378 | const enum_has_field = names.orderedRemove(field_name); | |
| 32379 | if (!enum_has_field) { | |
| 33297 | if (explicit_tags_seen.len > 0) { | |
| 33298 | const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type; | |
| 33299 | const enum_index = tag_info.nameIndex(ip, field_name) orelse { | |
| 32380 | 33300 | const msg = msg: { |
| 32381 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | |
| 33301 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ | |
| 32382 | 33302 | .index = field_i, |
| 32383 | 33303 | .range = .type, |
| 32384 | 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 | 33308 | errdefer msg.destroy(sema.gpa); |
| 32387 | 33309 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 32388 | 33310 | break :msg msg; |
| 32389 | 33311 | }; |
| 32390 | 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 | 33321 | const msg = msg: { |
| 32396 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | |
| 33322 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ | |
| 32397 | 33323 | .index = field_i, |
| 32398 | 33324 | .range = .type, |
| 32399 | 33325 | }).lazy; |
| ... | ... | @@ -32407,11 +33333,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32407 | 33333 | } |
| 32408 | 33334 | if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { |
| 32409 | 33335 | const msg = msg: { |
| 32410 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | |
| 33336 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ | |
| 32411 | 33337 | .index = field_i, |
| 32412 | 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 | 33341 | errdefer msg.destroy(sema.gpa); |
| 32416 | 33342 | |
| 32417 | 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 | 33346 | break :msg msg; |
| 32421 | 33347 | }; |
| 32422 | 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 | 33350 | const msg = msg: { |
| 32425 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | |
| 33351 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ | |
| 32426 | 33352 | .index = field_i, |
| 32427 | 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 | 33356 | errdefer msg.destroy(sema.gpa); |
| 32431 | 33357 | |
| 32432 | 33358 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); |
| ... | ... | @@ -32438,14 +33364,14 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32438 | 33364 | } |
| 32439 | 33365 | |
| 32440 | 33366 | gop.value_ptr.* = .{ |
| 32441 | .ty = try field_ty.copy(decl_arena_allocator), | |
| 33367 | .ty = field_ty, | |
| 32442 | 33368 | .abi_align = 0, |
| 32443 | 33369 | }; |
| 32444 | 33370 | |
| 32445 | 33371 | if (align_ref != .none) { |
| 32446 | 33372 | gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { |
| 32447 | 33373 | error.NeededSourceLocation => { |
| 32448 | const align_src = union_obj.fieldSrcLoc(sema.mod, .{ | |
| 33374 | const align_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ | |
| 32449 | 33375 | .index = field_i, |
| 32450 | 33376 | .range = .alignment, |
| 32451 | 33377 | }).lazy; |
| ... | ... | @@ -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| { | |
| 32463 | if (names.count() > 0) { | |
| 33388 | if (explicit_tags_seen.len > 0) { | |
| 33389 | const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type; | |
| 33390 | if (tag_info.names.len > fields_len) { | |
| 32464 | 33391 | const msg = msg: { |
| 32465 | 33392 | const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{}); |
| 32466 | 33393 | errdefer msg.destroy(sema.gpa); |
| 32467 | 33394 | |
| 32468 | 33395 | const enum_ty = union_obj.tag_ty; |
| 32469 | for (names.keys()) |field_name| { | |
| 32470 | const field_index = enum_ty.enumFieldIndex(field_name).?; | |
| 32471 | try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); | |
| 33396 | for (tag_info.names, 0..) |field_name, field_index| { | |
| 33397 | if (explicit_tags_seen[field_index]) continue; | |
| 33398 | try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{ | |
| 33399 | field_name.fmt(ip), | |
| 33400 | }); | |
| 32472 | 33401 | } |
| 32473 | 33402 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 32474 | 33403 | break :msg msg; |
| 32475 | 33404 | }; |
| 32476 | 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 | 33419 | fn generateUnionTagTypeNumbered( |
| 32487 | 33420 | sema: *Sema, |
| 32488 | 33421 | block: *Block, |
| 32489 | fields_len: u32, | |
| 32490 | int_ty: Type, | |
| 33422 | enum_field_names: []const InternPool.NullTerminatedString, | |
| 33423 | enum_field_vals: []const InternPool.Index, | |
| 32491 | 33424 | union_obj: *Module.Union, |
| 32492 | 33425 | ) !Type { |
| 32493 | 33426 | const mod = sema.mod; |
| 32494 | ||
| 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); | |
| 33427 | const gpa = sema.gpa; | |
| 32507 | 33428 | |
| 32508 | 33429 | const src_decl = mod.declPtr(block.src_decl); |
| 32509 | 33430 | const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); |
| 32510 | 33431 | errdefer mod.destroyDecl(new_decl_index); |
| 32511 | const name = name: { | |
| 32512 | const fqn = try union_obj.getFullyQualifiedName(mod); | |
| 32513 | defer sema.gpa.free(fqn); | |
| 32514 | break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); | |
| 32515 | }; | |
| 33432 | 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)}); | |
| 32516 | 33434 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ |
| 32517 | .ty = Type.type, | |
| 32518 | .val = enum_val, | |
| 33435 | .ty = Type.noreturn, | |
| 33436 | .val = Value.@"unreachable", | |
| 32519 | 33437 | }, name); |
| 32520 | sema.mod.declPtr(new_decl_index).name_fully_qualified = true; | |
| 33438 | errdefer mod.abortAnonDecl(new_decl_index); | |
| 32521 | 33439 | |
| 32522 | 33440 | const new_decl = mod.declPtr(new_decl_index); |
| 33441 | new_decl.name_fully_qualified = true; | |
| 32523 | 33442 | new_decl.owns_tv = true; |
| 32524 | 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); | |
| 32528 | enum_obj.* = .{ | |
| 32529 | .owner_decl = new_decl_index, | |
| 32530 | .tag_ty = copied_int_ty, | |
| 32531 | .fields = .{}, | |
| 32532 | .values = .{}, | |
| 32533 | }; | |
| 32534 | // Here we pre-allocate the maps using the decl arena. | |
| 32535 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | |
| 32536 | try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ | |
| 32537 | .ty = copied_int_ty, | |
| 32538 | .mod = mod, | |
| 32539 | }); | |
| 32540 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 32541 | return enum_ty; | |
| 32542 | } | |
| 33445 | const enum_ty = try mod.intern(.{ .enum_type = .{ | |
| 33446 | .decl = new_decl_index, | |
| 33447 | .namespace = .none, | |
| 33448 | .tag_ty = if (enum_field_vals.len == 0) | |
| 33449 | (try mod.intType(.unsigned, 0)).toIntern() | |
| 33450 | else | |
| 33451 | mod.intern_pool.typeOf(enum_field_vals[0]), | |
| 33452 | .names = enum_field_names, | |
| 33453 | .values = enum_field_vals, | |
| 33454 | .tag_mode = .explicit, | |
| 33455 | } }); | |
| 32543 | 33456 | |
| 32544 | fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type { | |
| 32545 | const mod = sema.mod; | |
| 33457 | new_decl.ty = Type.type; | |
| 33458 | new_decl.val = enum_ty.toValue(); | |
| 32546 | 33459 | |
| 32547 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | |
| 32548 | errdefer new_decl_arena.deinit(); | |
| 32549 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 33460 | try mod.finalizeAnonDecl(new_decl_index); | |
| 33461 | return enum_ty.toType(); | |
| 33462 | } | |
| 32550 | 33463 | |
| 32551 | const enum_obj = try new_decl_arena_allocator.create(Module.EnumSimple); | |
| 32552 | const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumSimple); | |
| 32553 | enum_ty_payload.* = .{ | |
| 32554 | .base = .{ .tag = .enum_simple }, | |
| 32555 | .data = enum_obj, | |
| 32556 | }; | |
| 32557 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | |
| 32558 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | |
| 33464 | fn generateUnionTagTypeSimple( | |
| 33465 | sema: *Sema, | |
| 33466 | block: *Block, | |
| 33467 | enum_field_names: []const InternPool.NullTerminatedString, | |
| 33468 | maybe_union_obj: ?*Module.Union, | |
| 33469 | ) !Type { | |
| 33470 | const mod = sema.mod; | |
| 33471 | const gpa = sema.gpa; | |
| 32559 | 33472 | |
| 32560 | 33473 | const new_decl_index = new_decl_index: { |
| 32561 | 33474 | const union_obj = maybe_union_obj orelse { |
| 32562 | 33475 | break :new_decl_index try mod.createAnonymousDecl(block, .{ |
| 32563 | .ty = Type.type, | |
| 32564 | .val = enum_val, | |
| 33476 | .ty = Type.noreturn, | |
| 33477 | .val = Value.@"unreachable", | |
| 32565 | 33478 | }); |
| 32566 | 33479 | }; |
| 32567 | 33480 | const src_decl = mod.declPtr(block.src_decl); |
| 32568 | 33481 | const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); |
| 32569 | 33482 | errdefer mod.destroyDecl(new_decl_index); |
| 32570 | const name = name: { | |
| 32571 | const fqn = try union_obj.getFullyQualifiedName(mod); | |
| 32572 | defer sema.gpa.free(fqn); | |
| 32573 | break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); | |
| 32574 | }; | |
| 33483 | 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)}); | |
| 32575 | 33485 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ |
| 32576 | .ty = Type.type, | |
| 32577 | .val = enum_val, | |
| 33486 | .ty = Type.noreturn, | |
| 33487 | .val = Value.@"unreachable", | |
| 32578 | 33488 | }, name); |
| 32579 | sema.mod.declPtr(new_decl_index).name_fully_qualified = true; | |
| 33489 | mod.declPtr(new_decl_index).name_fully_qualified = true; | |
| 32580 | 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 | 33506 | const new_decl = mod.declPtr(new_decl_index); |
| 32584 | 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.* = .{ | |
| 32588 | .owner_decl = new_decl_index, | |
| 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; | |
| 33511 | try mod.finalizeAnonDecl(new_decl_index); | |
| 33512 | return enum_ty.toType(); | |
| 32595 | 33513 | } |
| 32596 | 33514 | |
| 32597 | 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 | 33519 | defer wip_captures.deinit(); |
| 32600 | 33520 | |
| 32601 | 33521 | var block: Block = .{ |
| ... | ... | @@ -32609,19 +33529,20 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { |
| 32609 | 33529 | .is_comptime = true, |
| 32610 | 33530 | }; |
| 32611 | 33531 | defer { |
| 32612 | block.instructions.deinit(sema.gpa); | |
| 32613 | block.params.deinit(sema.gpa); | |
| 33532 | block.instructions.deinit(gpa); | |
| 33533 | block.params.deinit(gpa); | |
| 32614 | 33534 | } |
| 32615 | 33535 | const src = LazySrcLoc.nodeOffset(0); |
| 32616 | 33536 | |
| 32617 | 33537 | const mod = sema.mod; |
| 33538 | const ip = &mod.intern_pool; | |
| 32618 | 33539 | const std_pkg = mod.main_pkg.table.get("std").?; |
| 32619 | 33540 | const std_file = (mod.importPkg(std_pkg) catch unreachable).file; |
| 32620 | 33541 | const opt_builtin_inst = (try sema.namespaceLookupRef( |
| 32621 | 33542 | &block, |
| 32622 | 33543 | src, |
| 32623 | 33544 | mod.declPtr(std_file.root_decl.unwrap().?).src_namespace, |
| 32624 | "builtin", | |
| 33545 | try ip.getOrPutString(gpa, "builtin"), | |
| 32625 | 33546 | )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'"); |
| 32626 | 33547 | const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src); |
| 32627 | 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 | 33552 | const opt_ty_decl = (try sema.namespaceLookup( |
| 32632 | 33553 | &block, |
| 32633 | 33554 | src, |
| 32634 | builtin_ty.getNamespace().?, | |
| 32635 | name, | |
| 33555 | builtin_ty.getNamespaceIndex(mod).unwrap().?, | |
| 33556 | try ip.getOrPutString(gpa, name), | |
| 32636 | 33557 | )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name}); |
| 32637 | 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 | 33561 | fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type { |
| 32641 | 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 | 33565 | defer wip_captures.deinit(); |
| 32645 | 33566 | |
| 32646 | 33567 | var block: Block = .{ |
| ... | ... | @@ -32673,341 +33594,287 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type { |
| 32673 | 33594 | /// that the types are already resolved. |
| 32674 | 33595 | /// TODO assert the return value matches `ty.onePossibleValue` |
| 32675 | 33596 | pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 32676 | switch (ty.tag()) { | |
| 32677 | .f16, | |
| 32678 | .f32, | |
| 32679 | .f64, | |
| 32680 | .f80, | |
| 32681 | .f128, | |
| 32682 | .c_longdouble, | |
| 32683 | .comptime_int, | |
| 32684 | .comptime_float, | |
| 32685 | .u1, | |
| 32686 | .u8, | |
| 32687 | .i8, | |
| 32688 | .u16, | |
| 32689 | .i16, | |
| 32690 | .u29, | |
| 32691 | .u32, | |
| 32692 | .i32, | |
| 32693 | .u64, | |
| 32694 | .i64, | |
| 32695 | .u128, | |
| 32696 | .i128, | |
| 32697 | .usize, | |
| 32698 | .isize, | |
| 32699 | .c_char, | |
| 32700 | .c_short, | |
| 32701 | .c_ushort, | |
| 32702 | .c_int, | |
| 32703 | .c_uint, | |
| 32704 | .c_long, | |
| 32705 | .c_ulong, | |
| 32706 | .c_longlong, | |
| 32707 | .c_ulonglong, | |
| 32708 | .bool, | |
| 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 { | |
| 33597 | const mod = sema.mod; | |
| 33598 | return switch (ty.toIntern()) { | |
| 33599 | .empty_struct_type => Value.empty_struct, | |
| 33600 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 33601 | .int_type => |int_type| { | |
| 33602 | if (int_type.bits == 0) { | |
| 33603 | return try mod.intValue(ty, 0); | |
| 33604 | } else { | |
| 33605 | return null; | |
| 33606 | } | |
| 33607 | }, | |
| 33608 | ||
| 33609 | .ptr_type, | |
| 33610 | .error_union_type, | |
| 33611 | .func_type, | |
| 33612 | .anyframe_type, | |
| 33613 | .error_set_type, | |
| 33614 | .inferred_error_set_type, | |
| 33615 | => null, | |
| 33616 | ||
| 33617 | inline .array_type, .vector_type => |seq_type, seq_tag| { | |
| 33618 | const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none; | |
| 33619 | if (seq_type.len + @boolToInt(has_sentinel) == 0) return (try mod.intern(.{ .aggregate = .{ | |
| 33620 | .ty = ty.toIntern(), | |
| 33621 | .storage = .{ .elems = &.{} }, | |
| 33622 | } })).toValue(); | |
| 33623 | ||
| 33624 | if (try sema.typeHasOnePossibleValue(seq_type.child.toType())) |opv| { | |
| 33625 | return (try mod.intern(.{ .aggregate = .{ | |
| 33626 | .ty = ty.toIntern(), | |
| 33627 | .storage = .{ .repeated_elem = opv.toIntern() }, | |
| 33628 | } })).toValue(); | |
| 33629 | } | |
| 32765 | 33630 | return null; |
| 32766 | } | |
| 32767 | }, | |
| 33631 | }, | |
| 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" => { | |
| 32770 | const resolved_ty = try sema.resolveTypeFields(ty); | |
| 32771 | const s = resolved_ty.castTag(.@"struct").?.data; | |
| 32772 | for (s.fields.values(), 0..) |field, i| { | |
| 32773 | if (field.is_comptime) continue; | |
| 32774 | if (field.ty.eql(resolved_ty, sema.mod)) { | |
| 33640 | .simple_type => |t| switch (t) { | |
| 33641 | .f16, | |
| 33642 | .f32, | |
| 33643 | .f64, | |
| 33644 | .f80, | |
| 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 | 33750 | const msg = try Module.ErrorMsg.create( |
| 32776 | 33751 | sema.gpa, |
| 32777 | s.srcLoc(sema.mod), | |
| 32778 | "struct '{}' depends on itself", | |
| 33752 | union_obj.srcLoc(sema.mod), | |
| 33753 | "union '{}' depends on itself", | |
| 32779 | 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 | 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 | 33760 | return null; |
| 32786 | } | |
| 32787 | } | |
| 32788 | return Value.initTag(.empty_struct_value); | |
| 32789 | }, | |
| 32790 | ||
| 32791 | .tuple, .anon_struct => { | |
| 32792 | const tuple = ty.tupleFields(); | |
| 32793 | for (tuple.values, 0..) |val, i| { | |
| 32794 | const is_comptime = val.tag() != .unreachable_value; | |
| 32795 | if (is_comptime) continue; | |
| 32796 | if ((try sema.typeHasOnePossibleValue(tuple.types[i])) != null) continue; | |
| 32797 | return null; | |
| 32798 | } | |
| 32799 | return Value.initTag(.empty_struct_value); | |
| 32800 | }, | |
| 33761 | const only = try mod.intern(.{ .un = .{ | |
| 33762 | .ty = resolved_ty.toIntern(), | |
| 33763 | .tag = tag_val.toIntern(), | |
| 33764 | .val = val_val.toIntern(), | |
| 33765 | } }); | |
| 33766 | return only.toValue(); | |
| 33767 | }, | |
| 33768 | .opaque_type => null, | |
| 33769 | .enum_type => |enum_type| switch (enum_type.tag_mode) { | |
| 33770 | .nonexhaustive => { | |
| 33771 | if (enum_type.tag_ty == .comptime_int_type) return null; | |
| 33772 | ||
| 33773 | if (try sema.typeHasOnePossibleValue(enum_type.tag_ty.toType())) |int_opv| { | |
| 33774 | const only = try mod.intern(.{ .enum_tag = .{ | |
| 33775 | .ty = ty.toIntern(), | |
| 33776 | .int = int_opv.toIntern(), | |
| 33777 | } }); | |
| 33778 | return only.toValue(); | |
| 33779 | } | |
| 32801 | 33780 | |
| 32802 | .enum_numbered => { | |
| 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]; | |
| 33781 | return null; | |
| 32831 | 33782 | }, |
| 32832 | else => return null, | |
| 32833 | } | |
| 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 | }, | |
| 33783 | .auto, .explicit => { | |
| 33784 | if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; | |
| 32879 | 33785 | |
| 32880 | .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), | |
| 32881 | .void => return Value.void, | |
| 32882 | .noreturn => return Value.initTag(.unreachable_value), | |
| 32883 | .null => return Value.null, | |
| 32884 | .undefined => return Value.initTag(.undef), | |
| 33786 | switch (enum_type.names.len) { | |
| 33787 | 0 => { | |
| 33788 | const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); | |
| 33789 | return only.toValue(); | |
| 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 => { | |
| 32887 | if (ty.cast(Type.Payload.Bits).?.data == 0) { | |
| 32888 | return Value.zero; | |
| 32889 | } else { | |
| 32890 | return null; | |
| 32891 | } | |
| 32892 | }, | |
| 32893 | .vector, .array, .array_u8 => { | |
| 32894 | if (ty.arrayLen() == 0) | |
| 32895 | return Value.initTag(.empty_array); | |
| 32896 | if ((try sema.typeHasOnePossibleValue(ty.elemType())) != null) { | |
| 32897 | return Value.initTag(.the_only_possible_value); | |
| 32898 | } | |
| 32899 | return null; | |
| 33803 | // values, not types | |
| 33804 | .undef, | |
| 33805 | .runtime_value, | |
| 33806 | .simple_value, | |
| 33807 | .variable, | |
| 33808 | .extern_func, | |
| 33809 | .func, | |
| 33810 | .int, | |
| 33811 | .err, | |
| 33812 | .error_union, | |
| 33813 | .enum_literal, | |
| 33814 | .enum_tag, | |
| 33815 | .empty_enum_value, | |
| 33816 | .float, | |
| 33817 | .ptr, | |
| 33818 | .opt, | |
| 33819 | .aggregate, | |
| 33820 | .un, | |
| 33821 | // memoization, not types | |
| 33822 | .memoized_call, | |
| 33823 | => unreachable, | |
| 32900 | 33824 | }, |
| 32901 | ||
| 32902 | .inferred_alloc_const => unreachable, | |
| 32903 | .inferred_alloc_mut => unreachable, | |
| 32904 | .generic_poison => return error.GenericPoison, | |
| 32905 | } | |
| 33825 | }; | |
| 32906 | 33826 | } |
| 32907 | 33827 | |
| 32908 | 33828 | /// Returns the type of the AIR instruction. |
| 32909 | 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 | 33833 | pub fn getTmpAir(sema: Sema) Air { |
| 32914 | 33834 | return .{ |
| 32915 | 33835 | .instructions = sema.air_instructions.slice(), |
| 32916 | 33836 | .extra = sema.air_extra.items, |
| 32917 | .values = sema.air_values.items, | |
| 32918 | 33837 | }; |
| 32919 | 33838 | } |
| 32920 | 33839 | |
| 32921 | 33840 | pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { |
| 32922 | switch (ty.tag()) { | |
| 32923 | .u1 => return .u1_type, | |
| 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 | } | |
| 33841 | if (@enumToInt(ty.toIntern()) < Air.ref_start_index) | |
| 33842 | return @intToEnum(Air.Inst.Ref, @enumToInt(ty.toIntern())); | |
| 32986 | 33843 | try sema.air_instructions.append(sema.gpa, .{ |
| 32987 | .tag = .const_ty, | |
| 32988 | .data = .{ .ty = ty }, | |
| 33844 | .tag = .interned, | |
| 33845 | .data = .{ .interned = ty.toIntern() }, | |
| 32989 | 33846 | }); |
| 32990 | 33847 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); |
| 32991 | 33848 | } |
| 32992 | 33849 | |
| 32993 | 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 | 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 | 33859 | pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref { |
| 33860 | const mod = sema.mod; | |
| 33002 | 33861 | const gpa = sema.gpa; |
| 33003 | const ty_inst = try sema.addType(ty); | |
| 33004 | try sema.air_values.append(gpa, val); | |
| 33862 | ||
| 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 | 33875 | try sema.air_instructions.append(gpa, .{ |
| 33006 | .tag = .constant, | |
| 33007 | .data = .{ .ty_pl = .{ | |
| 33008 | .ty = ty_inst, | |
| 33009 | .payload = @intCast(u32, sema.air_values.items.len - 1), | |
| 33010 | } }, | |
| 33876 | .tag = .interned, | |
| 33877 | .data = .{ .interned = val.toIntern() }, | |
| 33011 | 33878 | }); |
| 33012 | 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 | 33893 | u32 => @field(extra, field.name), |
| 33027 | 33894 | Air.Inst.Ref => @enumToInt(@field(extra, field.name)), |
| 33028 | 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 | 33900 | return result; |
| ... | ... | @@ -33072,21 +33940,25 @@ fn analyzeComptimeAlloc( |
| 33072 | 33940 | defer anon_decl.deinit(); |
| 33073 | 33941 | |
| 33074 | 33942 | const decl_index = try anon_decl.finish( |
| 33075 | try var_type.copy(anon_decl.arena()), | |
| 33943 | var_type, | |
| 33076 | 33944 | // There will be stores before the first load, but they may be to sub-elements or |
| 33077 | 33945 | // sub-fields. So we need to initialize with undef to allow the mechanism to expand |
| 33078 | 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 | 33948 | alignment, |
| 33081 | 33949 | ); |
| 33082 | 33950 | const decl = sema.mod.declPtr(decl_index); |
| 33083 | 33951 | decl.@"align" = alignment; |
| 33084 | 33952 | |
| 33953 | try sema.comptime_mutable_decls.append(decl_index); | |
| 33085 | 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, .{ | |
| 33087 | .runtime_index = block.runtime_index, | |
| 33088 | .decl_index = decl_index, | |
| 33089 | })); | |
| 33955 | return sema.addConstant(ptr_type, (try sema.mod.intern(.{ .ptr = .{ | |
| 33956 | .ty = ptr_type.toIntern(), | |
| 33957 | .addr = .{ .mut_decl = .{ | |
| 33958 | .decl = decl_index, | |
| 33959 | .runtime_index = block.runtime_index, | |
| 33960 | } }, | |
| 33961 | } })).toValue()); | |
| 33090 | 33962 | } |
| 33091 | 33963 | |
| 33092 | 33964 | /// The places where a user can specify an address space attribute |
| ... | ... | @@ -33114,8 +33986,9 @@ pub fn analyzeAddressSpace( |
| 33114 | 33986 | zir_ref: Zir.Inst.Ref, |
| 33115 | 33987 | ctx: AddressSpaceContext, |
| 33116 | 33988 | ) !std.builtin.AddressSpace { |
| 33989 | const mod = sema.mod; | |
| 33117 | 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 | 33992 | const target = sema.mod.getTarget(); |
| 33120 | 33993 | const arch = target.cpu.arch; |
| 33121 | 33994 | |
| ... | ... | @@ -33158,8 +34031,9 @@ pub fn analyzeAddressSpace( |
| 33158 | 34031 | /// Asserts the value is a pointer and dereferences it. |
| 33159 | 34032 | /// Returns `null` if the pointer contents cannot be loaded at comptime. |
| 33160 | 34033 | fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { |
| 33161 | const load_ty = ptr_ty.childType(); | |
| 33162 | const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true); | |
| 34034 | const mod = sema.mod; | |
| 34035 | const load_ty = ptr_ty.childType(mod); | |
| 34036 | const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty); | |
| 33163 | 34037 | switch (res) { |
| 33164 | 34038 | .runtime_load => return null, |
| 33165 | 34039 | .val => |v| return v, |
| ... | ... | @@ -33185,8 +34059,9 @@ const DerefResult = union(enum) { |
| 33185 | 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 { | |
| 33189 | const target = sema.mod.getTarget(); | |
| 34062 | fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult { | |
| 34063 | const mod = sema.mod; | |
| 34064 | const target = mod.getTarget(); | |
| 33190 | 34065 | const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { |
| 33191 | 34066 | error.RuntimeLoad => return DerefResult{ .runtime_load = {} }, |
| 33192 | 34067 | else => |e| return e, |
| ... | ... | @@ -33199,19 +34074,17 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value |
| 33199 | 34074 | if (coerce_in_mem_ok) { |
| 33200 | 34075 | // We have a Value that lines up in virtual memory exactly with what we want to load, |
| 33201 | 34076 | // and it is in-memory coercible to load_ty. It may be returned without modifications. |
| 33202 | if (deref.is_mutable and want_mutable) { | |
| 33203 | // The decl whose value we are obtaining here may be overwritten with | |
| 33204 | // a different value upon further semantic analysis, which would | |
| 33205 | // invalidate this memory. So we must copy here. | |
| 33206 | return DerefResult{ .val = try tv.val.copy(sema.arena) }; | |
| 33207 | } | |
| 33208 | return DerefResult{ .val = tv.val }; | |
| 34077 | // Move mutable decl values to the InternPool and assert other decls are already in | |
| 34078 | // the InternPool. | |
| 34079 | const uncoerced_val = if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern(); | |
| 34080 | const coerced_val = try sema.coerceValueInMemory(block, uncoerced_val.toValue(), tv.ty, load_ty, src); | |
| 34081 | return .{ .val = coerced_val }; | |
| 33209 | 34082 | } |
| 33210 | 34083 | } |
| 33211 | 34084 | |
| 33212 | 34085 | // The type is not in-memory coercible or the direct dereference failed, so it must |
| 33213 | 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 | 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 | 34121 | /// This can return `error.AnalysisFail` because it sometimes requires resolving whether |
| 33249 | 34122 | /// a type has zero bits, which can cause a "foo depends on itself" compile error. |
| 33250 | 34123 | /// This logic must be kept in sync with `Type.isPtrLikeOptional`. |
| 33251 | fn typePtrOrOptionalPtrTy( | |
| 33252 | sema: *Sema, | |
| 33253 | ty: Type, | |
| 33254 | buf: *Type.Payload.ElemType, | |
| 33255 | ) !?Type { | |
| 33256 | switch (ty.tag()) { | |
| 33257 | .optional_single_const_pointer, | |
| 33258 | .optional_single_mut_pointer, | |
| 33259 | .c_const_pointer, | |
| 33260 | .c_mut_pointer, | |
| 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, | |
| 34124 | fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type { | |
| 34125 | const mod = sema.mod; | |
| 34126 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 34127 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 34128 | .One, .Many, .C => ty, | |
| 34129 | .Slice => null, | |
| 34130 | }, | |
| 34131 | .opt_type => |opt_child| switch (mod.intern_pool.indexToKey(opt_child)) { | |
| 34132 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 34133 | .Slice, .C => null, | |
| 33289 | 34134 | .Many, .One => { |
| 33290 | if (info.@"allowzero") return null; | |
| 34135 | if (ptr_type.flags.is_allowzero) return null; | |
| 33291 | 34136 | |
| 33292 | 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 | 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 | ||
| 33302 | else => return null, | |
| 33303 | } | |
| 34148 | else => null, | |
| 34149 | }; | |
| 33304 | 34150 | } |
| 33305 | 34151 | |
| 33306 | 34152 | /// `generic_poison` will return false. |
| ... | ... | @@ -33310,201 +34156,170 @@ fn typePtrOrOptionalPtrTy( |
| 33310 | 34156 | /// TODO merge these implementations together with the "advanced"/opt_sema pattern seen |
| 33311 | 34157 | /// elsewhere in value.zig |
| 33312 | 34158 | pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33313 | return switch (ty.tag()) { | |
| 33314 | .u1, | |
| 33315 | .u8, | |
| 33316 | .i8, | |
| 33317 | .u16, | |
| 33318 | .i16, | |
| 33319 | .u29, | |
| 33320 | .u32, | |
| 33321 | .i32, | |
| 33322 | .u64, | |
| 33323 | .i64, | |
| 33324 | .u128, | |
| 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; | |
| 34159 | const mod = sema.mod; | |
| 34160 | return switch (ty.toIntern()) { | |
| 34161 | .empty_struct_type => false, | |
| 34162 | ||
| 34163 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 34164 | .int_type => return false, | |
| 34165 | .ptr_type => |ptr_type| { | |
| 34166 | const child_ty = ptr_type.child.toType(); | |
| 34167 | if (child_ty.zigTypeTag(mod) == .Fn) { | |
| 34168 | return mod.typeToFunc(child_ty).?.is_generic; | |
| 34169 | } else { | |
| 34170 | return sema.typeRequiresComptime(child_ty); | |
| 33436 | 34171 | } |
| 33437 | } | |
| 33438 | return false; | |
| 33439 | }, | |
| 33440 | ||
| 33441 | .@"struct" => { | |
| 33442 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 33443 | switch (struct_obj.requires_comptime) { | |
| 33444 | .no, .wip => return false, | |
| 33445 | .yes => return true, | |
| 33446 | .unknown => { | |
| 33447 | if (struct_obj.status == .field_types_wip) | |
| 33448 | return false; | |
| 34172 | }, | |
| 34173 | .anyframe_type => |child| { | |
| 34174 | if (child == .none) return false; | |
| 34175 | return sema.typeRequiresComptime(child.toType()); | |
| 34176 | }, | |
| 34177 | .array_type => |array_type| return sema.typeRequiresComptime(array_type.child.toType()), | |
| 34178 | .vector_type => |vector_type| return sema.typeRequiresComptime(vector_type.child.toType()), | |
| 34179 | .opt_type => |child| return sema.typeRequiresComptime(child.toType()), | |
| 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; | |
| 33453 | for (struct_obj.fields.values()) |field| { | |
| 33454 | if (field.is_comptime) continue; | |
| 33455 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 33456 | struct_obj.requires_comptime = .yes; | |
| 33457 | return true; | |
| 34185 | .error_set_type, .inferred_error_set_type => false, | |
| 34186 | ||
| 34187 | .func_type => true, | |
| 34188 | ||
| 34189 | .simple_type => |t| return switch (t) { | |
| 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 | } | |
| 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) | |
| 34253 | struct_obj.requires_comptime = .no; | |
| 33473 | 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); | |
| 33476 | ||
| 33477 | union_obj.requires_comptime = .wip; | |
| 33478 | for (union_obj.fields.values()) |field| { | |
| 33479 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 33480 | union_obj.requires_comptime = .yes; | |
| 33481 | return true; | |
| 34268 | .union_type => |union_type| { | |
| 34269 | const union_obj = mod.unionPtr(union_type.index); | |
| 34270 | switch (union_obj.requires_comptime) { | |
| 34271 | .no, .wip => return false, | |
| 34272 | .yes => return true, | |
| 34273 | .unknown => { | |
| 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 | } | |
| 33484 | union_obj.requires_comptime = .no; | |
| 33485 | return false; | |
| 33486 | }, | |
| 33487 | } | |
| 33488 | }, | |
| 34286 | union_obj.requires_comptime = .no; | |
| 34287 | return false; | |
| 34288 | }, | |
| 34289 | } | |
| 34290 | }, | |
| 33489 | 34291 | |
| 33490 | .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()), | |
| 33491 | .anyframe_T => { | |
| 33492 | const child_ty = ty.castTag(.anyframe_T).?.data; | |
| 33493 | return sema.typeRequiresComptime(child_ty); | |
| 33494 | }, | |
| 33495 | .enum_numbered => { | |
| 33496 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; | |
| 33497 | return sema.typeRequiresComptime(tag_ty); | |
| 33498 | }, | |
| 33499 | .enum_full, .enum_nonexhaustive => { | |
| 33500 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; | |
| 33501 | return sema.typeRequiresComptime(tag_ty); | |
| 34292 | .opaque_type => false, | |
| 34293 | .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()), | |
| 34294 | ||
| 34295 | // values, not types | |
| 34296 | .undef, | |
| 34297 | .runtime_value, | |
| 34298 | .simple_value, | |
| 34299 | .variable, | |
| 34300 | .extern_func, | |
| 34301 | .func, | |
| 34302 | .int, | |
| 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 | 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 | 34323 | error.NeedLazy => unreachable, |
| 33509 | 34324 | else => |e| return e, |
| 33510 | 34325 | }; |
| ... | ... | @@ -33512,19 +34327,18 @@ pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { |
| 33512 | 34327 | |
| 33513 | 34328 | fn typeAbiSize(sema: *Sema, ty: Type) !u64 { |
| 33514 | 34329 | try sema.resolveTypeLayout(ty); |
| 33515 | const target = sema.mod.getTarget(); | |
| 33516 | return ty.abiSize(target); | |
| 34330 | return ty.abiSize(sema.mod); | |
| 33517 | 34331 | } |
| 33518 | 34332 | |
| 33519 | 34333 | fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 { |
| 33520 | const target = sema.mod.getTarget(); | |
| 33521 | return (try ty.abiAlignmentAdvanced(target, .{ .sema = sema })).scalar; | |
| 34334 | return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar; | |
| 33522 | 34335 | } |
| 33523 | 34336 | |
| 33524 | 34337 | /// Not valid to call for packed unions. |
| 33525 | 34338 | /// Keep implementation in sync with `Module.Union.Field.normalAlignment`. |
| 33526 | 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 | 34342 | return @as(u32, 0); |
| 33529 | 34343 | } else if (field.abi_align == 0) { |
| 33530 | 34344 | return sema.typeAbiAlignment(field.ty); |
| ... | ... | @@ -33535,7 +34349,8 @@ fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 { |
| 33535 | 34349 | |
| 33536 | 34350 | /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. |
| 33537 | 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 | 34354 | if (fn_info.is_generic) return false; |
| 33540 | 34355 | if (fn_info.is_var_args) return true; |
| 33541 | 34356 | switch (fn_info.cc) { |
| ... | ... | @@ -33543,7 +34358,7 @@ pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { |
| 33543 | 34358 | .Inline => return false, |
| 33544 | 34359 | else => {}, |
| 33545 | 34360 | } |
| 33546 | if (try sema.typeRequiresComptime(fn_info.return_type)) { | |
| 34361 | if (try sema.typeRequiresComptime(fn_info.return_type.toType())) { | |
| 33547 | 34362 | return false; |
| 33548 | 34363 | } |
| 33549 | 34364 | return true; |
| ... | ... | @@ -33553,11 +34368,12 @@ fn unionFieldIndex( |
| 33553 | 34368 | sema: *Sema, |
| 33554 | 34369 | block: *Block, |
| 33555 | 34370 | unresolved_union_ty: Type, |
| 33556 | field_name: []const u8, | |
| 34371 | field_name: InternPool.NullTerminatedString, | |
| 33557 | 34372 | field_src: LazySrcLoc, |
| 33558 | 34373 | ) !u32 { |
| 34374 | const mod = sema.mod; | |
| 33559 | 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 | 34377 | const field_index_usize = union_obj.fields.getIndex(field_name) orelse |
| 33562 | 34378 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); |
| 33563 | 34379 | return @intCast(u32, field_index_usize); |
| ... | ... | @@ -33567,14 +34383,15 @@ fn structFieldIndex( |
| 33567 | 34383 | sema: *Sema, |
| 33568 | 34384 | block: *Block, |
| 33569 | 34385 | unresolved_struct_ty: Type, |
| 33570 | field_name: []const u8, | |
| 34386 | field_name: InternPool.NullTerminatedString, | |
| 33571 | 34387 | field_src: LazySrcLoc, |
| 33572 | 34388 | ) !u32 { |
| 34389 | const mod = sema.mod; | |
| 33573 | 34390 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 33574 | if (struct_ty.isAnonStruct()) { | |
| 34391 | if (struct_ty.isAnonStruct(mod)) { | |
| 33575 | 34392 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); |
| 33576 | 34393 | } else { |
| 33577 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | |
| 34394 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 33578 | 34395 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| 33579 | 34396 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); |
| 33580 | 34397 | return @intCast(u32, field_index_usize); |
| ... | ... | @@ -33585,55 +34402,98 @@ fn anonStructFieldIndex( |
| 33585 | 34402 | sema: *Sema, |
| 33586 | 34403 | block: *Block, |
| 33587 | 34404 | struct_ty: Type, |
| 33588 | field_name: []const u8, | |
| 34405 | field_name: InternPool.NullTerminatedString, | |
| 33589 | 34406 | field_src: LazySrcLoc, |
| 33590 | 34407 | ) !u32 { |
| 33591 | const anon_struct = struct_ty.castTag(.anon_struct).?.data; | |
| 33592 | for (anon_struct.names, 0..) |name, i| { | |
| 33593 | if (mem.eql(u8, name, field_name)) { | |
| 33594 | return @intCast(u32, i); | |
| 33595 | } | |
| 34408 | const mod = sema.mod; | |
| 34409 | switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { | |
| 34410 | .anon_struct_type => |anon_struct_type| for (anon_struct_type.names, 0..) |name, i| { | |
| 34411 | if (name == field_name) return @intCast(u32, i); | |
| 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 '{}'", .{ | |
| 33598 | field_name, struct_ty.fmt(sema.mod), | |
| 34422 | return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{ | |
| 34423 | field_name.fmt(&mod.intern_pool), struct_ty.fmt(sema.mod), | |
| 33599 | 34424 | }); |
| 33600 | 34425 | } |
| 33601 | 34426 | |
| 33602 | 34427 | fn queueFullTypeResolution(sema: *Sema, ty: Type) !void { |
| 33603 | const inst_ref = try sema.addType(ty); | |
| 33604 | try sema.types_to_resolve.append(sema.gpa, inst_ref); | |
| 34428 | try sema.types_to_resolve.put(sema.gpa, ty.toIntern(), {}); | |
| 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 { | |
| 33608 | if (ty.zigTypeTag() == .Vector) { | |
| 33609 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | |
| 34452 | fn intAddInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize) !Value { | |
| 34453 | const mod = sema.mod; | |
| 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 | 34457 | for (result_data, 0..) |*scalar, i| { |
| 33611 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 33612 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 33613 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | |
| 33614 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | |
| 33615 | scalar.* = try sema.intAddScalar(lhs_elem, rhs_elem); | |
| 34458 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 34459 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 34460 | const val = sema.intAddScalar(lhs_elem, rhs_elem, scalar_ty) catch |err| switch (err) { | |
| 34461 | error.Overflow => { | |
| 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 | 34484 | // TODO is this a performance issue? maybe we should try the operation without |
| 33624 | 34485 | // resorting to BigInt first. |
| 33625 | 34486 | var lhs_space: Value.BigIntSpace = undefined; |
| 33626 | 34487 | var rhs_space: Value.BigIntSpace = undefined; |
| 33627 | const target = sema.mod.getTarget(); | |
| 33628 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | |
| 33629 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | |
| 34488 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); | |
| 34489 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); | |
| 33630 | 34490 | const limbs = try sema.arena.alloc( |
| 33631 | 34491 | std.math.big.Limb, |
| 33632 | 34492 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, |
| 33633 | 34493 | ); |
| 33634 | 34494 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 33635 | 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 | 34499 | /// Supports both floats and ints; handles undefined. |
| ... | ... | @@ -33643,55 +34503,87 @@ fn numberAddWrapScalar( |
| 33643 | 34503 | rhs: Value, |
| 33644 | 34504 | ty: Type, |
| 33645 | 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) { | |
| 33649 | return sema.intAdd(lhs, rhs, ty); | |
| 34509 | if (ty.zigTypeTag(mod) == .ComptimeInt) { | |
| 34510 | return sema.intAdd(lhs, rhs, ty, undefined); | |
| 33650 | 34511 | } |
| 33651 | 34512 | |
| 33652 | 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 | 34517 | const overflow_result = try sema.intAddWithOverflow(lhs, rhs, ty); |
| 33657 | 34518 | return overflow_result.wrapped_result; |
| 33658 | 34519 | } |
| 33659 | 34520 | |
| 33660 | fn intSub( | |
| 33661 | sema: *Sema, | |
| 33662 | lhs: Value, | |
| 33663 | rhs: Value, | |
| 33664 | ty: Type, | |
| 33665 | ) !Value { | |
| 33666 | if (ty.zigTypeTag() == .Vector) { | |
| 33667 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | |
| 34521 | /// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting | |
| 34522 | /// overflow_idx to the vector index the overflow was at (or 0 for a scalar). | |
| 34523 | fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize) !Value { | |
| 34524 | var overflow: usize = undefined; | |
| 34525 | return sema.intSubInner(lhs, rhs, ty, &overflow) catch |err| switch (err) { | |
| 34526 | error.Overflow => { | |
| 34527 | const is_vec = ty.isVector(sema.mod); | |
| 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 | 34547 | for (result_data, 0..) |*scalar, i| { |
| 33669 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 33670 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 33671 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | |
| 33672 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | |
| 33673 | scalar.* = try sema.intSubScalar(lhs_elem, rhs_elem); | |
| 34548 | const lhs_elem = try lhs.elemValue(sema.mod, i); | |
| 34549 | const rhs_elem = try rhs.elemValue(sema.mod, i); | |
| 34550 | const val = sema.intSubScalar(lhs_elem, rhs_elem, scalar_ty) catch |err| switch (err) { | |
| 34551 | error.Overflow => { | |
| 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 | 34574 | // TODO is this a performance issue? maybe we should try the operation without |
| 33682 | 34575 | // resorting to BigInt first. |
| 33683 | 34576 | var lhs_space: Value.BigIntSpace = undefined; |
| 33684 | 34577 | var rhs_space: Value.BigIntSpace = undefined; |
| 33685 | const target = sema.mod.getTarget(); | |
| 33686 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | |
| 33687 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | |
| 34578 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); | |
| 34579 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); | |
| 33688 | 34580 | const limbs = try sema.arena.alloc( |
| 33689 | 34581 | std.math.big.Limb, |
| 33690 | 34582 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, |
| 33691 | 34583 | ); |
| 33692 | 34584 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 33693 | 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 | 34589 | /// Supports both floats and ints; handles undefined. |
| ... | ... | @@ -33701,155 +34593,49 @@ fn numberSubWrapScalar( |
| 33701 | 34593 | rhs: Value, |
| 33702 | 34594 | ty: Type, |
| 33703 | 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) { | |
| 33707 | return sema.intSub(lhs, rhs, ty); | |
| 34599 | if (ty.zigTypeTag(mod) == .ComptimeInt) { | |
| 34600 | return sema.intSub(lhs, rhs, ty, undefined); | |
| 33708 | 34601 | } |
| 33709 | 34602 | |
| 33710 | 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 | 34607 | const overflow_result = try sema.intSubWithOverflow(lhs, rhs, ty); |
| 33715 | 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 | 34611 | fn intSubWithOverflow( |
| 33833 | 34612 | sema: *Sema, |
| 33834 | 34613 | lhs: Value, |
| 33835 | 34614 | rhs: Value, |
| 33836 | 34615 | ty: Type, |
| 33837 | 34616 | ) !Value.OverflowArithmeticResult { |
| 33838 | if (ty.zigTypeTag() == .Vector) { | |
| 33839 | const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen()); | |
| 33840 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | |
| 33841 | for (result_data, 0..) |*scalar, i| { | |
| 33842 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 33843 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 33844 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | |
| 33845 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | |
| 33846 | const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType()); | |
| 33847 | overflowed_data[i] = of_math_result.overflow_bit; | |
| 33848 | scalar.* = of_math_result.wrapped_result; | |
| 34617 | const mod = sema.mod; | |
| 34618 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 34619 | const vec_len = ty.vectorLen(mod); | |
| 34620 | const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 34621 | const result_data = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 34622 | const scalar_ty = ty.scalarType(mod); | |
| 34623 | for (overflowed_data, result_data, 0..) |*of, *scalar, i| { | |
| 34624 | const lhs_elem = try lhs.elemValue(sema.mod, i); | |
| 34625 | const rhs_elem = try rhs.elemValue(sema.mod, i); | |
| 34626 | const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty); | |
| 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 | 34630 | return Value.OverflowArithmeticResult{ |
| 33851 | .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data), | |
| 33852 | .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data), | |
| 34631 | .overflow_bit = (try mod.intern(.{ .aggregate = .{ | |
| 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 | 34641 | return sema.intSubWithOverflowScalar(lhs, rhs, ty); |
| ... | ... | @@ -33861,22 +34647,22 @@ fn intSubWithOverflowScalar( |
| 33861 | 34647 | rhs: Value, |
| 33862 | 34648 | ty: Type, |
| 33863 | 34649 | ) !Value.OverflowArithmeticResult { |
| 33864 | const target = sema.mod.getTarget(); | |
| 33865 | const info = ty.intInfo(target); | |
| 34650 | const mod = sema.mod; | |
| 34651 | const info = ty.intInfo(mod); | |
| 33866 | 34652 | |
| 33867 | 34653 | var lhs_space: Value.BigIntSpace = undefined; |
| 33868 | 34654 | var rhs_space: Value.BigIntSpace = undefined; |
| 33869 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | |
| 33870 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | |
| 34655 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); | |
| 34656 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); | |
| 33871 | 34657 | const limbs = try sema.arena.alloc( |
| 33872 | 34658 | std.math.big.Limb, |
| 33873 | 34659 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 33874 | 34660 | ); |
| 33875 | 34661 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 33876 | 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 | 34664 | return Value.OverflowArithmeticResult{ |
| 33879 | .overflow_bit = Value.boolToInt(overflowed), | |
| 34665 | .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), | |
| 33880 | 34666 | .wrapped_result = wrapped_result, |
| 33881 | 34667 | }; |
| 33882 | 34668 | } |
| ... | ... | @@ -33889,15 +34675,19 @@ fn floatToInt( |
| 33889 | 34675 | float_ty: Type, |
| 33890 | 34676 | int_ty: Type, |
| 33891 | 34677 | ) CompileError!Value { |
| 33892 | if (float_ty.zigTypeTag() == .Vector) { | |
| 33893 | const elem_ty = float_ty.childType(); | |
| 33894 | const result_data = try sema.arena.alloc(Value, float_ty.vectorLen()); | |
| 34678 | const mod = sema.mod; | |
| 34679 | if (float_ty.zigTypeTag(mod) == .Vector) { | |
| 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 | 34683 | for (result_data, 0..) |*scalar, i| { |
| 33896 | var buf: Value.ElemValueBuffer = undefined; | |
| 33897 | const elem_val = val.elemValueBuffer(sema.mod, i, &buf); | |
| 33898 | scalar.* = try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType()); | |
| 34684 | const elem_val = try val.elemValue(sema.mod, i); | |
| 34685 | scalar.* = try (try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod))).intern(scalar_ty, mod); | |
| 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 | 34692 | return sema.floatToIntScalar(block, src, val, float_ty, int_ty); |
| 33903 | 34693 | } |
| ... | ... | @@ -33935,9 +34725,9 @@ fn floatToIntScalar( |
| 33935 | 34725 | float_ty: Type, |
| 33936 | 34726 | int_ty: Type, |
| 33937 | 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 | 34731 | if (std.math.isNan(float)) { |
| 33942 | 34732 | return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{ |
| 33943 | 34733 | int_ty.fmt(sema.mod), |
| ... | ... | @@ -33952,18 +34742,14 @@ fn floatToIntScalar( |
| 33952 | 34742 | var big_int = try float128IntPartToBigInt(sema.arena, float); |
| 33953 | 34743 | defer big_int.deinit(); |
| 33954 | 34744 | |
| 33955 | const result_limbs = try sema.arena.dupe(Limb, big_int.toConst().limbs); | |
| 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); | |
| 34745 | const cti_result = try mod.intValue_big(Type.comptime_int, big_int.toConst()); | |
| 33960 | 34746 | |
| 33961 | if (!(try sema.intFitsInType(result, int_ty, null))) { | |
| 34747 | if (!(try sema.intFitsInType(cti_result, int_ty, null))) { | |
| 33962 | 34748 | return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ |
| 33963 | 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 | 34755 | /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. |
| ... | ... | @@ -33976,208 +34762,91 @@ fn intFitsInType( |
| 33976 | 34762 | ty: Type, |
| 33977 | 34763 | vector_index: ?*usize, |
| 33978 | 34764 | ) CompileError!bool { |
| 33979 | const target = sema.mod.getTarget(); | |
| 33980 | switch (val.tag()) { | |
| 33981 | .zero, | |
| 33982 | .undef, | |
| 33983 | .bool_false, | |
| 33984 | => return true, | |
| 33985 | ||
| 33986 | .one, | |
| 33987 | .bool_true, | |
| 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); | |
| 34765 | const mod = sema.mod; | |
| 34766 | if (ty.toIntern() == .comptime_int_type) return true; | |
| 34767 | const info = ty.intInfo(mod); | |
| 34768 | switch (val.toIntern()) { | |
| 34769 | .zero_usize, .zero_u8 => return true, | |
| 34770 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 34771 | .undef => return true, | |
| 34772 | .variable, .extern_func, .func, .ptr => { | |
| 34773 | const target = mod.getTarget(); | |
| 34083 | 34774 | const ptr_bits = target.ptrBitWidth(); |
| 34084 | 34775 | return switch (info.signedness) { |
| 34085 | 34776 | .signed => info.bits > ptr_bits, |
| 34086 | 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 | 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( | |
| 34109 | sema: *Sema, | |
| 34110 | tag_ty: Type, | |
| 34111 | int_val: Value, | |
| 34112 | end: usize, | |
| 34113 | ) !bool { | |
| 34831 | fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool { | |
| 34832 | const mod = sema.mod; | |
| 34114 | 34833 | if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema))) return false; |
| 34115 | var end_payload: Value.Payload.U64 = .{ | |
| 34116 | .base = .{ .tag = .int_u64 }, | |
| 34117 | .data = end, | |
| 34118 | }; | |
| 34119 | const end_val = Value.initPayload(&end_payload.base); | |
| 34834 | const end_val = try mod.intValue(tag_ty, end); | |
| 34120 | 34835 | if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false; |
| 34121 | 34836 | return true; |
| 34122 | 34837 | } |
| 34123 | 34838 | |
| 34124 | 34839 | /// Asserts the type is an enum. |
| 34125 | fn enumHasInt( | |
| 34126 | sema: *Sema, | |
| 34127 | ty: Type, | |
| 34128 | int: Value, | |
| 34129 | ) CompileError!bool { | |
| 34130 | switch (ty.tag()) { | |
| 34131 | .enum_nonexhaustive => unreachable, | |
| 34132 | .enum_full => { | |
| 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, | |
| 34840 | fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool { | |
| 34841 | const mod = sema.mod; | |
| 34842 | const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type; | |
| 34843 | assert(enum_type.tag_mode != .nonexhaustive); | |
| 34844 | // The `tagValueIndex` function call below relies on the type being the integer tag type. | |
| 34845 | // `getCoerced` assumes the value will fit the new type. | |
| 34846 | if (!(try sema.intFitsInType(int, enum_type.tag_ty.toType(), null))) return false; | |
| 34847 | const int_coerced = try mod.getCoerced(int, enum_type.tag_ty.toType()); | |
| 34178 | 34848 | |
| 34179 | else => unreachable, | |
| 34180 | } | |
| 34849 | return enum_type.tagValueIndex(&mod.intern_pool, int_coerced.toIntern()) != null; | |
| 34181 | 34850 | } |
| 34182 | 34851 | |
| 34183 | 34852 | fn intAddWithOverflow( |
| ... | ... | @@ -34186,21 +34855,28 @@ fn intAddWithOverflow( |
| 34186 | 34855 | rhs: Value, |
| 34187 | 34856 | ty: Type, |
| 34188 | 34857 | ) !Value.OverflowArithmeticResult { |
| 34189 | if (ty.zigTypeTag() == .Vector) { | |
| 34190 | const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen()); | |
| 34191 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | |
| 34192 | for (result_data, 0..) |*scalar, i| { | |
| 34193 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 34194 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 34195 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | |
| 34196 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | |
| 34197 | const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType()); | |
| 34198 | overflowed_data[i] = of_math_result.overflow_bit; | |
| 34199 | scalar.* = of_math_result.wrapped_result; | |
| 34858 | const mod = sema.mod; | |
| 34859 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 34860 | const vec_len = ty.vectorLen(mod); | |
| 34861 | const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 34862 | const result_data = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 34863 | const scalar_ty = ty.scalarType(mod); | |
| 34864 | for (overflowed_data, result_data, 0..) |*of, *scalar, i| { | |
| 34865 | const lhs_elem = try lhs.elemValue(sema.mod, i); | |
| 34866 | const rhs_elem = try rhs.elemValue(sema.mod, i); | |
| 34867 | const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty); | |
| 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 | 34871 | return Value.OverflowArithmeticResult{ |
| 34202 | .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data), | |
| 34203 | .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data), | |
| 34872 | .overflow_bit = (try mod.intern(.{ .aggregate = .{ | |
| 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 | 34882 | return sema.intAddWithOverflowScalar(lhs, rhs, ty); |
| ... | ... | @@ -34212,22 +34888,22 @@ fn intAddWithOverflowScalar( |
| 34212 | 34888 | rhs: Value, |
| 34213 | 34889 | ty: Type, |
| 34214 | 34890 | ) !Value.OverflowArithmeticResult { |
| 34215 | const target = sema.mod.getTarget(); | |
| 34216 | const info = ty.intInfo(target); | |
| 34891 | const mod = sema.mod; | |
| 34892 | const info = ty.intInfo(mod); | |
| 34217 | 34893 | |
| 34218 | 34894 | var lhs_space: Value.BigIntSpace = undefined; |
| 34219 | 34895 | var rhs_space: Value.BigIntSpace = undefined; |
| 34220 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | |
| 34221 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | |
| 34896 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); | |
| 34897 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); | |
| 34222 | 34898 | const limbs = try sema.arena.alloc( |
| 34223 | 34899 | std.math.big.Limb, |
| 34224 | 34900 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 34225 | 34901 | ); |
| 34226 | 34902 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 34227 | 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 | 34905 | return Value.OverflowArithmeticResult{ |
| 34230 | .overflow_bit = Value.boolToInt(overflowed), | |
| 34906 | .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), | |
| 34231 | 34907 | .wrapped_result = result, |
| 34232 | 34908 | }; |
| 34233 | 34909 | } |
| ... | ... | @@ -34243,14 +34919,13 @@ fn compareAll( |
| 34243 | 34919 | rhs: Value, |
| 34244 | 34920 | ty: Type, |
| 34245 | 34921 | ) CompileError!bool { |
| 34246 | if (ty.zigTypeTag() == .Vector) { | |
| 34922 | const mod = sema.mod; | |
| 34923 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 34247 | 34924 | var i: usize = 0; |
| 34248 | while (i < ty.vectorLen()) : (i += 1) { | |
| 34249 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 34250 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 34251 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | |
| 34252 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | |
| 34253 | if (!(try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType()))) { | |
| 34925 | while (i < ty.vectorLen(mod)) : (i += 1) { | |
| 34926 | const lhs_elem = try lhs.elemValue(sema.mod, i); | |
| 34927 | const rhs_elem = try rhs.elemValue(sema.mod, i); | |
| 34928 | if (!(try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)))) { | |
| 34254 | 34929 | return false; |
| 34255 | 34930 | } |
| 34256 | 34931 | } |
| ... | ... | @@ -34267,10 +34942,13 @@ fn compareScalar( |
| 34267 | 34942 | rhs: Value, |
| 34268 | 34943 | ty: Type, |
| 34269 | 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 | 34948 | switch (op) { |
| 34271 | .eq => return sema.valuesEqual(lhs, rhs, ty), | |
| 34272 | .neq => return !(try sema.valuesEqual(lhs, rhs, ty)), | |
| 34273 | else => return Value.compareHeteroAdvanced(lhs, op, rhs, sema.mod.getTarget(), sema), | |
| 34949 | .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty), | |
| 34950 | .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)), | |
| 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 | 34969 | rhs: Value, |
| 34292 | 34970 | ty: Type, |
| 34293 | 34971 | ) !Value { |
| 34294 | assert(ty.zigTypeTag() == .Vector); | |
| 34295 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | |
| 34972 | const mod = sema.mod; | |
| 34973 | assert(ty.zigTypeTag(mod) == .Vector); | |
| 34974 | const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 34296 | 34975 | for (result_data, 0..) |*scalar, i| { |
| 34297 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 34298 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 34299 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | |
| 34300 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | |
| 34301 | const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType()); | |
| 34302 | scalar.* = Value.makeBool(res_bool); | |
| 34976 | const lhs_elem = try lhs.elemValue(sema.mod, i); | |
| 34977 | const rhs_elem = try rhs.elemValue(sema.mod, i); | |
| 34978 | const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)); | |
| 34979 | scalar.* = try Value.makeBool(res_bool).intern(Type.bool, mod); | |
| 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 | 34987 | /// Returns the type of a pointer to an element. |
| ... | ... | @@ -34312,11 +34992,11 @@ fn compareVector( |
| 34312 | 34992 | /// Handles const-ness and address spaces in particular. |
| 34313 | 34993 | /// This code is duplicated in `analyzePtrArithmetic`. |
| 34314 | 34994 | fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 34315 | const ptr_info = ptr_ty.ptrInfo().data; | |
| 34316 | const elem_ty = ptr_ty.elemType2(); | |
| 34995 | const mod = sema.mod; | |
| 34996 | const ptr_info = ptr_ty.ptrInfo(mod); | |
| 34997 | const elem_ty = ptr_ty.elemType2(mod); | |
| 34317 | 34998 | const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0; |
| 34318 | const target = sema.mod.getTarget(); | |
| 34319 | const parent_ty = ptr_ty.childType(); | |
| 34999 | const parent_ty = ptr_ty.childType(mod); | |
| 34320 | 35000 | |
| 34321 | 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 | 35004 | host_size: u16 = 0, |
| 34325 | 35005 | alignment: u32 = 0, |
| 34326 | 35006 | vector_index: VI = .none, |
| 34327 | } = if (parent_ty.tag() == .vector and ptr_info.size == .One) blk: { | |
| 34328 | const elem_bits = elem_ty.bitSize(target); | |
| 35007 | } = if (parent_ty.isVector(mod) and ptr_info.size == .One) blk: { | |
| 35008 | const elem_bits = elem_ty.bitSize(mod); | |
| 34329 | 35009 | if (elem_bits == 0) break :blk .{}; |
| 34330 | 35010 | const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits); |
| 34331 | 35011 | if (!is_packed) break :blk .{}; |
| 34332 | 35012 | |
| 34333 | 35013 | break :blk .{ |
| 34334 | .host_size = @intCast(u16, parent_ty.arrayLen()), | |
| 34335 | .alignment = @intCast(u16, parent_ty.abiAlignment(target)), | |
| 35014 | .host_size = @intCast(u16, parent_ty.arrayLen(mod)), | |
| 35015 | .alignment = @intCast(u16, parent_ty.abiAlignment(mod)), | |
| 34336 | 35016 | .vector_index = if (offset) |some| @intToEnum(VI, some) else .runtime, |
| 34337 | 35017 | }; |
| 34338 | 35018 | } else .{}; |
| ... | ... | @@ -34366,3 +35046,42 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 34366 | 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 | 27 | /// Assumes arena allocation. Does a recursive copy. |
| 28 | 28 | pub fn copy(self: TypedValue, arena: Allocator) error{OutOfMemory}!TypedValue { |
| 29 | 29 | return TypedValue{ |
| 30 | .ty = try self.ty.copy(arena), | |
| 30 | .ty = self.ty, | |
| 31 | 31 | .val = try self.val.copy(arena), |
| 32 | 32 | }; |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 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 | 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 | 41 | return tv.val.hash(tv.ty, hasher, mod); |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | pub fn enumToInt(tv: TypedValue, buffer: *Value.Payload.U64) Value { | |
| 45 | return tv.val.enumToInt(tv.ty, buffer); | |
| 44 | pub fn enumToInt(tv: TypedValue, mod: *Module) Allocator.Error!Value { | |
| 45 | return tv.val.enumToInt(tv.ty, mod); | |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | 48 | const max_aggregate_items = 100; |
| ... | ... | @@ -61,7 +61,10 @@ pub fn format( |
| 61 | 61 | ) !void { |
| 62 | 62 | _ = options; |
| 63 | 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 | 70 | /// Prints the Value according to the Type, not according to the Value Tag. |
| ... | ... | @@ -70,106 +73,61 @@ pub fn print( |
| 70 | 73 | writer: anytype, |
| 71 | 74 | level: u8, |
| 72 | 75 | mod: *Module, |
| 73 | ) @TypeOf(writer).Error!void { | |
| 74 | const target = mod.getTarget(); | |
| 76 | ) (@TypeOf(writer).Error || Allocator.Error)!void { | |
| 75 | 77 | var val = tv.val; |
| 76 | 78 | var ty = tv.ty; |
| 77 | if (val.isVariable(mod)) | |
| 78 | return writer.writeAll("(variable)"); | |
| 79 | ||
| 80 | while (true) switch (val.tag()) { | |
| 81 | .u1_type => return writer.writeAll("u1"), | |
| 82 | .u8_type => return writer.writeAll("u8"), | |
| 83 | .i8_type => return writer.writeAll("i8"), | |
| 84 | .u16_type => return writer.writeAll("u16"), | |
| 85 | .i16_type => return writer.writeAll("i16"), | |
| 86 | .u29_type => return writer.writeAll("u29"), | |
| 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"), | |
| 79 | const ip = &mod.intern_pool; | |
| 80 | while (true) switch (val.ip_index) { | |
| 81 | .none => switch (val.tag()) { | |
| 82 | .aggregate => return printAggregate(ty, val, writer, level, mod), | |
| 83 | .@"union" => { | |
| 84 | if (level == 0) { | |
| 85 | return writer.writeAll(".{ ... }"); | |
| 86 | } | |
| 87 | const union_val = val.castTag(.@"union").?.data; | |
| 88 | try writer.writeAll(".{ "); | |
| 145 | 89 | |
| 146 | .empty_struct_value, .aggregate => { | |
| 147 | if (level == 0) { | |
| 148 | return writer.writeAll(".{ ... }"); | |
| 149 | } | |
| 150 | if (ty.zigTypeTag() == .Struct) { | |
| 151 | try writer.writeAll(".{"); | |
| 152 | const max_len = std.math.min(ty.structFieldCount(), max_aggregate_items); | |
| 90 | try print(.{ | |
| 91 | .ty = mod.unionPtr(ip.indexToKey(ty.toIntern()).union_type.index).tag_ty, | |
| 92 | .val = union_val.tag, | |
| 93 | }, writer, level - 1, mod); | |
| 94 | try writer.writeAll(" = "); | |
| 95 | try print(.{ | |
| 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 | 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 | 115 | while (i < max_len) : (i += 1) { |
| 156 | 116 | if (i != 0) try writer.writeAll(", "); |
| 157 | switch (ty.tag()) { | |
| 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); | |
| 117 | try print(elem_tv, writer, level - 1, mod); | |
| 165 | 118 | } |
| 166 | if (ty.structFieldCount() > max_aggregate_items) { | |
| 119 | if (len > max_aggregate_items) { | |
| 167 | 120 | try writer.writeAll(", ..."); |
| 168 | 121 | } |
| 169 | return writer.writeAll("}"); | |
| 170 | } else { | |
| 171 | const elem_ty = ty.elemType2(); | |
| 172 | const len = ty.arrayLen(); | |
| 122 | return writer.writeAll(" }"); | |
| 123 | }, | |
| 124 | .slice => { | |
| 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 | 132 | if (elem_ty.eql(Type.u8, mod)) str: { |
| 175 | 133 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); |
| ... | ... | @@ -177,11 +135,14 @@ pub fn print( |
| 177 | 135 | |
| 178 | 136 | var i: u32 = 0; |
| 179 | 137 | while (i < max_len) : (i += 1) { |
| 180 | const elem = val.fieldValue(ty, i); | |
| 181 | if (elem.isUndef()) break :str; | |
| 182 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(target)) orelse break :str; | |
| 138 | const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) { | |
| 139 | error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic | |
| 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 | 146 | const truncated = if (len > max_string_len) " (truncated)" else ""; |
| 186 | 147 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); |
| 187 | 148 | } |
| ... | ... | @@ -192,315 +153,334 @@ pub fn print( |
| 192 | 153 | var i: u32 = 0; |
| 193 | 154 | while (i < max_len) : (i += 1) { |
| 194 | 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 | 159 | try print(.{ |
| 196 | 160 | .ty = elem_ty, |
| 197 | .val = val.fieldValue(ty, i), | |
| 161 | .val = elem_val, | |
| 198 | 162 | }, writer, level - 1, mod); |
| 199 | 163 | } |
| 200 | 164 | if (len > max_aggregate_items) { |
| 201 | 165 | try writer.writeAll(", ..."); |
| 202 | 166 | } |
| 203 | 167 | return writer.writeAll(" }"); |
| 204 | } | |
| 205 | }, | |
| 206 | .@"union" => { | |
| 207 | if (level == 0) { | |
| 208 | return writer.writeAll(".{ ... }"); | |
| 209 | } | |
| 210 | const union_val = val.castTag(.@"union").?.data; | |
| 211 | try writer.writeAll(".{ "); | |
| 212 | ||
| 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}); | |
| 168 | }, | |
| 169 | .eu_payload => { | |
| 170 | val = val.castTag(.eu_payload).?.data; | |
| 171 | ty = ty.errorUnionPayload(mod); | |
| 172 | }, | |
| 173 | .opt_payload => { | |
| 174 | val = val.castTag(.opt_payload).?.data; | |
| 175 | ty = ty.optionalChild(mod); | |
| 176 | }, | |
| 250 | 177 | }, |
| 251 | .lazy_size => { | |
| 252 | const sub_ty = val.castTag(.lazy_size).?.data; | |
| 253 | const x = sub_ty.abiSize(target); | |
| 254 | return writer.print("{d}", .{x}); | |
| 255 | }, | |
| 256 | .function => return writer.print("(function '{s}')", .{ | |
| 257 | mod.declPtr(val.castTag(.function).?.data.owner_decl).name, | |
| 258 | }), | |
| 259 | .extern_fn => return writer.writeAll("(extern function)"), | |
| 260 | .variable => unreachable, | |
| 261 | .decl_ref_mut => { | |
| 262 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 263 | const decl = mod.declPtr(decl_index); | |
| 264 | if (level == 0) { | |
| 265 | return writer.print("(decl ref mut '{s}')", .{decl.name}); | |
| 266 | } | |
| 267 | return print(.{ | |
| 268 | .ty = decl.ty, | |
| 269 | .val = decl.val, | |
| 270 | }, writer, level - 1, mod); | |
| 271 | }, | |
| 272 | .decl_ref => { | |
| 273 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 274 | const decl = mod.declPtr(decl_index); | |
| 275 | if (level == 0) { | |
| 276 | return writer.print("(decl ref '{s}')", .{decl.name}); | |
| 277 | } | |
| 278 | return print(.{ | |
| 279 | .ty = decl.ty, | |
| 280 | .val = decl.val, | |
| 281 | }, writer, level - 1, mod); | |
| 282 | }, | |
| 283 | .comptime_field_ptr => { | |
| 284 | const payload = val.castTag(.comptime_field_ptr).?.data; | |
| 285 | if (level == 0) { | |
| 286 | return writer.writeAll("(comptime field ptr)"); | |
| 287 | } | |
| 288 | return print(.{ | |
| 289 | .ty = payload.field_ty, | |
| 290 | .val = payload.field_val, | |
| 291 | }, writer, level - 1, mod); | |
| 292 | }, | |
| 293 | .elem_ptr => { | |
| 294 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 295 | try writer.writeAll("&"); | |
| 296 | if (level == 0) { | |
| 297 | try writer.writeAll("(ptr)"); | |
| 298 | } else { | |
| 178 | else => switch (ip.indexToKey(val.toIntern())) { | |
| 179 | .int_type, | |
| 180 | .ptr_type, | |
| 181 | .array_type, | |
| 182 | .vector_type, | |
| 183 | .opt_type, | |
| 184 | .anyframe_type, | |
| 185 | .error_union_type, | |
| 186 | .simple_type, | |
| 187 | .struct_type, | |
| 188 | .anon_struct_type, | |
| 189 | .union_type, | |
| 190 | .opaque_type, | |
| 191 | .enum_type, | |
| 192 | .func_type, | |
| 193 | .error_set_type, | |
| 194 | .inferred_error_set_type, | |
| 195 | => return Type.print(val.toType(), writer, mod), | |
| 196 | .undef => return writer.writeAll("undefined"), | |
| 197 | .runtime_value => return writer.writeAll("(runtime value)"), | |
| 198 | .simple_value => |simple_value| switch (simple_value) { | |
| 199 | .empty_struct => return printAggregate(ty, val, writer, level, mod), | |
| 200 | .generic_poison => return writer.writeAll("(generic poison)"), | |
| 201 | else => return writer.writeAll(@tagName(simple_value)), | |
| 202 | }, | |
| 203 | .variable => return writer.writeAll("(variable)"), | |
| 204 | .extern_func => |extern_func| return writer.print("(extern function '{}')", .{ | |
| 205 | mod.declPtr(extern_func.decl).name.fmt(ip), | |
| 206 | }), | |
| 207 | .func => |func| return writer.print("(function '{}')", .{ | |
| 208 | mod.declPtr(mod.funcPtr(func.index).owner_decl).name.fmt(ip), | |
| 209 | }), | |
| 210 | .int => |int| switch (int.storage) { | |
| 211 | inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), | |
| 212 | .lazy_align => |lazy_ty| return writer.print("{d}", .{ | |
| 213 | lazy_ty.toType().abiAlignment(mod), | |
| 214 | }), | |
| 215 | .lazy_size => |lazy_ty| return writer.print("{d}", .{ | |
| 216 | lazy_ty.toType().abiSize(mod), | |
| 217 | }), | |
| 218 | }, | |
| 219 | .err => |err| return writer.print("error.{}", .{ | |
| 220 | err.name.fmt(ip), | |
| 221 | }), | |
| 222 | .error_union => |error_union| switch (error_union.val) { | |
| 223 | .err_name => |err_name| return writer.print("error.{}", .{ | |
| 224 | err_name.fmt(ip), | |
| 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 | 244 | try print(.{ |
| 300 | .ty = elem_ptr.elem_ty, | |
| 301 | .val = elem_ptr.array_ptr, | |
| 245 | .ty = Type.type, | |
| 246 | .val = enum_tag.ty.toValue(), | |
| 302 | 247 | }, writer, level - 1, mod); |
| 303 | } | |
| 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 { | |
| 248 | try writer.writeAll(", "); | |
| 312 | 249 | try print(.{ |
| 313 | .ty = field_ptr.container_ty, | |
| 314 | .val = field_ptr.container_ptr, | |
| 250 | .ty = ip.typeOf(enum_tag.int).toType(), | |
| 251 | .val = enum_tag.int.toValue(), | |
| 315 | 252 | }, writer, level - 1, mod); |
| 316 | } | |
| 317 | ||
| 318 | if (field_ptr.container_ty.zigTypeTag() == .Struct) { | |
| 319 | switch (field_ptr.container_ty.tag()) { | |
| 320 | .tuple => return writer.print(".@\"{d}\"", .{field_ptr.field_index}), | |
| 321 | else => { | |
| 322 | const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index); | |
| 323 | return writer.print(".{s}", .{field_name}); | |
| 324 | }, | |
| 325 | } | |
| 326 | } else if (field_ptr.container_ty.zigTypeTag() == .Union) { | |
| 327 | const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index]; | |
| 328 | return writer.print(".{s}", .{field_name}); | |
| 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, | |
| 253 | try writer.writeAll(")"); | |
| 254 | return; | |
| 255 | }, | |
| 256 | .empty_enum_value => return writer.writeAll("(empty enum value)"), | |
| 257 | .float => |float| switch (float.storage) { | |
| 258 | inline else => |x| return writer.print("{d}", .{@floatCast(f64, x)}), | |
| 259 | }, | |
| 260 | .ptr => |ptr| { | |
| 261 | if (ptr.addr == .int) { | |
| 262 | const i = ip.indexToKey(ptr.addr.int).int; | |
| 263 | switch (i.storage) { | |
| 264 | inline else => |addr| return writer.print("{x:0>8}", .{addr}), | |
| 265 | } | |
| 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: { | |
| 389 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); | |
| 390 | var buf: [max_string_len]u8 = undefined; | |
| 391 | ||
| 392 | var i: u32 = 0; | |
| 393 | while (i < max_len) : (i += 1) { | |
| 394 | var elem_buf: Value.ElemValueBuffer = undefined; | |
| 395 | const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf); | |
| 396 | if (elem_val.isUndef()) break :str; | |
| 397 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(target)) orelse break :str; | |
| 268 | const ptr_ty = ip.indexToKey(ty.toIntern()).ptr_type; | |
| 269 | if (ptr_ty.flags.size == .Slice) { | |
| 270 | if (level == 0) { | |
| 271 | return writer.writeAll(".{ ... }"); | |
| 272 | } | |
| 273 | const elem_ty = ptr_ty.child.toType(); | |
| 274 | const len = ptr.len.toValue().toUnsignedInt(mod); | |
| 275 | if (elem_ty.eql(Type.u8, mod)) str: { | |
| 276 | const max_len = @min(len, max_string_len); | |
| 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. | |
| 401 | const truncated = if (len > max_string_len) " (truncated)" else ""; | |
| 402 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | |
| 403 | } | |
| 404 | ||
| 405 | try writer.writeAll(".{ "); | |
| 406 | ||
| 407 | const max_len = std.math.min(len, max_aggregate_items); | |
| 408 | var i: u32 = 0; | |
| 409 | while (i < max_len) : (i += 1) { | |
| 410 | if (i != 0) try writer.writeAll(", "); | |
| 411 | var buf: Value.ElemValueBuffer = undefined; | |
| 412 | try print(.{ | |
| 413 | .ty = elem_ty, | |
| 414 | .val = payload.ptr.elemValueBuffer(mod, i, &buf), | |
| 415 | }, writer, level - 1, mod); | |
| 416 | } | |
| 417 | if (len > max_aggregate_items) { | |
| 418 | try writer.writeAll(", ..."); | |
| 419 | } | |
| 420 | return writer.writeAll(" }"); | |
| 421 | }, | |
| 422 | .float_16 => return writer.print("{d}", .{val.castTag(.float_16).?.data}), | |
| 423 | .float_32 => return writer.print("{d}", .{val.castTag(.float_32).?.data}), | |
| 424 | .float_64 => return writer.print("{d}", .{val.castTag(.float_64).?.data}), | |
| 425 | .float_80 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_80).?.data)}), | |
| 426 | .float_128 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_128).?.data)}), | |
| 427 | .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}), | |
| 428 | .eu_payload => { | |
| 429 | val = val.castTag(.eu_payload).?.data; | |
| 430 | ty = ty.errorUnionPayload(); | |
| 431 | }, | |
| 432 | .opt_payload => { | |
| 433 | val = val.castTag(.opt_payload).?.data; | |
| 434 | var buf: Type.Payload.ElemType = undefined; | |
| 435 | ty = ty.optionalChild(&buf); | |
| 436 | return print(.{ .ty = ty, .val = val }, writer, level, mod); | |
| 301 | switch (ptr.addr) { | |
| 302 | .decl => |decl_index| { | |
| 303 | const decl = mod.declPtr(decl_index); | |
| 304 | if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)}); | |
| 305 | return print(.{ | |
| 306 | .ty = decl.ty, | |
| 307 | .val = decl.val, | |
| 308 | }, writer, level - 1, mod); | |
| 309 | }, | |
| 310 | .mut_decl => |mut_decl| { | |
| 311 | const decl = mod.declPtr(mut_decl.decl); | |
| 312 | if (level == 0) return writer.print("(mut decl '{}')", .{decl.name.fmt(ip)}); | |
| 313 | return print(.{ | |
| 314 | .ty = decl.ty, | |
| 315 | .val = decl.val, | |
| 316 | }, writer, level - 1, mod); | |
| 317 | }, | |
| 318 | .comptime_field => |field_val_ip| { | |
| 319 | return print(.{ | |
| 320 | .ty = ip.typeOf(field_val_ip).toType(), | |
| 321 | .val = field_val_ip.toValue(), | |
| 322 | }, writer, level - 1, mod); | |
| 323 | }, | |
| 324 | .int => unreachable, | |
| 325 | .eu_payload => |eu_ip| { | |
| 326 | try writer.writeAll("(payload of "); | |
| 327 | try print(.{ | |
| 328 | .ty = ip.typeOf(eu_ip).toType(), | |
| 329 | .val = eu_ip.toValue(), | |
| 330 | }, writer, level - 1, mod); | |
| 331 | try writer.writeAll(")"); | |
| 332 | }, | |
| 333 | .opt_payload => |opt_ip| { | |
| 334 | try print(.{ | |
| 335 | .ty = ip.typeOf(opt_ip).toType(), | |
| 336 | .val = opt_ip.toValue(), | |
| 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 => { | |
| 439 | try writer.writeAll("&"); | |
| 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 | }; | |
| 415 | }; | |
| 416 | } | |
| 447 | 417 | |
| 448 | try writer.writeAll("@as("); | |
| 449 | try print(.{ | |
| 450 | .ty = Type.type, | |
| 451 | .val = Value.initPayload(&ty_val.base), | |
| 452 | }, writer, level - 1, mod); | |
| 418 | fn printAggregate( | |
| 419 | ty: Type, | |
| 420 | val: Value, | |
| 421 | writer: anytype, | |
| 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 = .{ | |
| 457 | .base = .{ .tag = .single_mut_pointer }, | |
| 458 | .data = data.container_ty, | |
| 435 | const field_name = switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 436 | .struct_type => |x| mod.structPtrUnwrap(x.index).?.fields.keys()[i].toOptional(), | |
| 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 | 442 | try print(.{ |
| 462 | .ty = Type.initPayload(&ptr_ty.base), | |
| 463 | .val = data.container_ptr, | |
| 443 | .ty = ty.structFieldType(i, mod), | |
| 444 | .val = try val.fieldValue(mod, i), | |
| 464 | 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("))"); | |
| 467 | return; | |
| 468 | }, | |
| 469 | .opt_payload_ptr => { | |
| 470 | const data = val.castTag(.opt_payload_ptr).?.data; | |
| 471 | ||
| 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); | |
| 459 | var i: u32 = 0; | |
| 460 | while (i < max_len) : (i += 1) { | |
| 461 | const elem = try val.fieldValue(mod, i); | |
| 462 | if (elem.isUndef(mod)) break :str; | |
| 463 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str; | |
| 464 | } | |
| 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 = .{ | |
| 486 | .base = .{ .tag = .single_mut_pointer }, | |
| 487 | .data = data.container_ty, | |
| 488 | }; | |
| 470 | try writer.writeAll(".{ "); | |
| 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 | 476 | try print(.{ |
| 491 | .ty = Type.initPayload(&ptr_ty.base), | |
| 492 | .val = data.container_ptr, | |
| 477 | .ty = elem_ty, | |
| 478 | .val = try val.fieldValue(mod, i), | |
| 493 | 479 | }, writer, level - 1, mod); |
| 494 | ||
| 495 | try writer.writeAll("))"); | |
| 496 | return; | |
| 497 | }, | |
| 498 | ||
| 499 | // TODO these should not appear in this function | |
| 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 | }; | |
| 480 | } | |
| 481 | if (len > max_aggregate_items) { | |
| 482 | try writer.writeAll(", ..."); | |
| 483 | } | |
| 484 | return writer.writeAll(" }"); | |
| 485 | } | |
| 506 | 486 | } |
src/Zir.zig+97-435| ... | ... | @@ -19,6 +19,7 @@ const BigIntConst = std.math.big.int.Const; |
| 19 | 19 | const BigIntMutable = std.math.big.int.Mutable; |
| 20 | 20 | const Ast = std.zig.Ast; |
| 21 | 21 | |
| 22 | const InternPool = @import("InternPool.zig"); | |
| 22 | 23 | const Zir = @This(); |
| 23 | 24 | const Type = @import("type.zig").Type; |
| 24 | 25 | const Value = @import("value.zig").Value; |
| ... | ... | @@ -2041,448 +2042,103 @@ pub const Inst = struct { |
| 2041 | 2042 | /// The position of a ZIR instruction within the `Zir` instructions array. |
| 2042 | 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 | /// | |
| 2048 | /// If the value of a Ref does not have a tag, it refers to a ZIR 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. | |
| 2047 | /// If the integer tag value is < InternPool.static_len, then it | |
| 2048 | /// corresponds to an InternPool index. Otherwise, this refers to a ZIR | |
| 2049 | /// instruction. | |
| 2055 | 2050 | /// |
| 2056 | 2051 | /// The tag type is specified so that it is safe to bitcast between `[]u32` |
| 2057 | 2052 | /// and `[]Ref`. |
| 2058 | 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 | 2138 | /// This Ref does not correspond to any ZIR instruction or constant |
| 2060 | 2139 | /// value and may instead be used as a sentinel to indicate null. |
| 2061 | 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 | ||
| 2140 | none = @enumToInt(InternPool.Index.none), | |
| 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 | 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 | 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 | 3824 | pub fn indexToRef(inst: Inst.Index) Inst.Ref { |
| 4169 | 3825 | return @intToEnum(Inst.Ref, ref_start_index + inst); |
| 4170 | 3826 | } |
| 4171 | 3827 | |
| 4172 | 3828 | pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { |
| 3829 | assert(inst != .none); | |
| 4173 | 3830 | const ref_int = @enumToInt(inst); |
| 4174 | 3831 | if (ref_int >= ref_start_index) { |
| 4175 | 3832 | return ref_int - ref_start_index; |
| ... | ... | @@ -4177,3 +3834,8 @@ pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { |
| 4177 | 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 | 328 | pub fn generate( |
| 329 | 329 | bin_file: *link.File, |
| 330 | 330 | src_loc: Module.SrcLoc, |
| 331 | module_fn: *Module.Fn, | |
| 331 | module_fn_index: Module.Fn.Index, | |
| 332 | 332 | air: Air, |
| 333 | 333 | liveness: Liveness, |
| 334 | 334 | code: *std.ArrayList(u8), |
| ... | ... | @@ -339,6 +339,7 @@ pub fn generate( |
| 339 | 339 | } |
| 340 | 340 | |
| 341 | 341 | const mod = bin_file.options.module.?; |
| 342 | const module_fn = mod.funcPtr(module_fn_index); | |
| 342 | 343 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 343 | 344 | assert(fn_owner_decl.has_tv); |
| 344 | 345 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -471,7 +472,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 471 | 472 | } |
| 472 | 473 | |
| 473 | 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 | 477 | if (cc != .Naked) { |
| 476 | 478 | // stp fp, lr, [sp, #-16]! |
| 477 | 479 | _ = try self.addInst(.{ |
| ... | ... | @@ -520,10 +522,10 @@ fn gen(self: *Self) !void { |
| 520 | 522 | const inst = self.air.getMainBody()[arg_index]; |
| 521 | 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.*)); | |
| 526 | const abi_align = ty.abiAlignment(self.target.*); | |
| 527 | const abi_size = @intCast(u32, ty.abiSize(mod)); | |
| 528 | const abi_align = ty.abiAlignment(mod); | |
| 527 | 529 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 528 | 530 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 529 | 531 | |
| ... | ... | @@ -652,13 +654,14 @@ fn gen(self: *Self) !void { |
| 652 | 654 | } |
| 653 | 655 | |
| 654 | 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 | 659 | const air_tags = self.air.instructions.items(.tag); |
| 656 | 660 | |
| 657 | 661 | for (body) |inst| { |
| 658 | 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 | 664 | continue; |
| 661 | } | |
| 662 | 665 | |
| 663 | 666 | const old_air_bookkeeping = self.air_bookkeeping; |
| 664 | 667 | try self.ensureProcessDeathCapacity(Liveness.bpi); |
| ... | ... | @@ -842,8 +845,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 842 | 845 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 843 | 846 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 844 | 847 | |
| 845 | .constant => unreachable, // excluded from function bodies | |
| 846 | .const_ty => unreachable, // excluded from function bodies | |
| 848 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 847 | 849 | .unreach => self.finishAirBookkeeping(), |
| 848 | 850 | |
| 849 | 851 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | ... | @@ -916,8 +918,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 916 | 918 | |
| 917 | 919 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 918 | 920 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 919 | const air_tags = self.air.instructions.items(.tag); | |
| 920 | if (air_tags[inst] == .constant) return; // Constants are immortal. | |
| 921 | assert(self.air.instructions.items(.tag)[inst] != .interned); | |
| 921 | 922 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 922 | 923 | const prev_value = self.getResolvedInstValue(inst); |
| 923 | 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 | 952 | tomb_bits >>= 1; |
| 952 | 953 | if (!dies) continue; |
| 953 | 954 | const op_int = @enumToInt(op); |
| 954 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | |
| 955 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 955 | if (op_int < Air.ref_start_index) continue; | |
| 956 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); | |
| 956 | 957 | self.processDeath(op_index); |
| 957 | 958 | } |
| 958 | 959 | const is_used = @truncate(u1, tomb_bits) == 0; |
| ... | ... | @@ -1026,31 +1027,31 @@ fn allocMem( |
| 1026 | 1027 | |
| 1027 | 1028 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 1028 | 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 | 1034 | // return the stack offset 0. Stack offset 0 will be where all |
| 1033 | 1035 | // zero-sized stack allocations live as non-zero-sized |
| 1034 | 1036 | // allocations will always have an offset > 0. |
| 1035 | 1037 | return @as(u32, 0); |
| 1036 | 1038 | } |
| 1037 | 1039 | |
| 1038 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | |
| 1039 | const mod = self.bin_file.options.module.?; | |
| 1040 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { | |
| 1040 | 1041 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 1041 | 1042 | }; |
| 1042 | 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 | 1046 | return self.allocMem(abi_size, abi_align, inst); |
| 1046 | 1047 | } |
| 1047 | 1048 | |
| 1048 | 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 | 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 | 1056 | if (reg_ok) { |
| 1056 | 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 | 1067 | } |
| 1067 | 1068 | |
| 1068 | 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 | 1071 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); |
| 1071 | 1072 | |
| 1072 | 1073 | const reg_mcv = self.getResolvedInstValue(inst); |
| ... | ... | @@ -1078,14 +1079,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 1078 | 1079 | |
| 1079 | 1080 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1080 | 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 | 1085 | /// Save the current instruction stored in the compare flags if |
| 1085 | 1086 | /// occupied |
| 1086 | 1087 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 1087 | 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 | 1090 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 1090 | 1091 | const new_mcv = switch (mcv) { |
| 1091 | 1092 | .compare_flags => try self.allocRegOrMem(ty, true, inst_to_save), |
| ... | ... | @@ -1093,7 +1094,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 1093 | 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 | 1098 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); |
| 1098 | 1099 | |
| 1099 | 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 | 1126 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 1126 | 1127 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 1127 | 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 | 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 | 1132 | return MCValue{ .register = reg }; |
| 1132 | 1133 | } |
| 1133 | 1134 | |
| ... | ... | @@ -1137,17 +1138,14 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 1137 | 1138 | } |
| 1138 | 1139 | |
| 1139 | 1140 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1141 | const mod = self.bin_file.options.module.?; | |
| 1140 | 1142 | const result: MCValue = switch (self.ret_mcv) { |
| 1141 | 1143 | .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, |
| 1142 | 1144 | .stack_offset => blk: { |
| 1143 | 1145 | // self.ret_mcv is an address to where this function |
| 1144 | 1146 | // should store its result into |
| 1145 | const ret_ty = self.fn_type.fnReturnType(); | |
| 1146 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 1147 | .base = .{ .tag = .single_mut_pointer }, | |
| 1148 | .data = ret_ty, | |
| 1149 | }; | |
| 1150 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 1147 | const ret_ty = self.fn_type.fnReturnType(mod); | |
| 1148 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | |
| 1151 | 1149 | |
| 1152 | 1150 | // addr_reg will contain the address of where to store the |
| 1153 | 1151 | // result into |
| ... | ... | @@ -1177,13 +1175,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1177 | 1175 | if (self.liveness.isUnused(inst)) |
| 1178 | 1176 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1179 | 1177 | |
| 1178 | const mod = self.bin_file.options.module.?; | |
| 1180 | 1179 | const operand = ty_op.operand; |
| 1181 | 1180 | const operand_mcv = try self.resolveInst(operand); |
| 1182 | const operand_ty = self.air.typeOf(operand); | |
| 1183 | const operand_info = operand_ty.intInfo(self.target.*); | |
| 1181 | const operand_ty = self.typeOf(operand); | |
| 1182 | const operand_info = operand_ty.intInfo(mod); | |
| 1184 | 1183 | |
| 1185 | const dest_ty = self.air.typeOfIndex(inst); | |
| 1186 | const dest_info = dest_ty.intInfo(self.target.*); | |
| 1184 | const dest_ty = self.typeOfIndex(inst); | |
| 1185 | const dest_info = dest_ty.intInfo(mod); | |
| 1187 | 1186 | |
| 1188 | 1187 | const result: MCValue = result: { |
| 1189 | 1188 | const operand_lock: ?RegisterLock = switch (operand_mcv) { |
| ... | ... | @@ -1199,14 +1198,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1199 | 1198 | |
| 1200 | 1199 | if (dest_info.bits > operand_info.bits) { |
| 1201 | 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 | 1202 | break :result dest_mcv; |
| 1204 | 1203 | } else { |
| 1205 | 1204 | if (self.reuseOperand(inst, operand, 0, truncated)) { |
| 1206 | 1205 | break :result truncated; |
| 1207 | 1206 | } else { |
| 1208 | 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 | 1209 | break :result dest_mcv; |
| 1211 | 1210 | } |
| 1212 | 1211 | } |
| ... | ... | @@ -1257,8 +1256,9 @@ fn trunc( |
| 1257 | 1256 | operand_ty: Type, |
| 1258 | 1257 | dest_ty: Type, |
| 1259 | 1258 | ) !MCValue { |
| 1260 | const info_a = operand_ty.intInfo(self.target.*); | |
| 1261 | const info_b = dest_ty.intInfo(self.target.*); | |
| 1259 | const mod = self.bin_file.options.module.?; | |
| 1260 | const info_a = operand_ty.intInfo(mod); | |
| 1261 | const info_b = dest_ty.intInfo(mod); | |
| 1262 | 1262 | |
| 1263 | 1263 | if (info_b.bits <= 64) { |
| 1264 | 1264 | const operand_reg = switch (operand) { |
| ... | ... | @@ -1300,8 +1300,8 @@ fn trunc( |
| 1300 | 1300 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1301 | 1301 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1302 | 1302 | const operand = try self.resolveInst(ty_op.operand); |
| 1303 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 1304 | const dest_ty = self.air.typeOfIndex(inst); | |
| 1303 | const operand_ty = self.typeOf(ty_op.operand); | |
| 1304 | const dest_ty = self.typeOfIndex(inst); | |
| 1305 | 1305 | |
| 1306 | 1306 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 1307 | 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 | 1319 | |
| 1320 | 1320 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1321 | 1321 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1322 | const mod = self.bin_file.options.module.?; | |
| 1322 | 1323 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1323 | 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 | 1326 | switch (operand) { |
| 1326 | 1327 | .dead => unreachable, |
| 1327 | 1328 | .unreach => unreachable, |
| 1328 | 1329 | .compare_flags => |cond| break :result MCValue{ .compare_flags = cond.negate() }, |
| 1329 | 1330 | else => { |
| 1330 | switch (operand_ty.zigTypeTag()) { | |
| 1331 | switch (operand_ty.zigTypeTag(mod)) { | |
| 1331 | 1332 | .Bool => { |
| 1332 | 1333 | // TODO convert this to mvn + and |
| 1333 | 1334 | const op_reg = switch (operand) { |
| ... | ... | @@ -1361,7 +1362,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1361 | 1362 | }, |
| 1362 | 1363 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), |
| 1363 | 1364 | .Int => { |
| 1364 | const int_info = operand_ty.intInfo(self.target.*); | |
| 1365 | const int_info = operand_ty.intInfo(mod); | |
| 1365 | 1366 | if (int_info.bits <= 64) { |
| 1366 | 1367 | const op_reg = switch (operand) { |
| 1367 | 1368 | .register => |r| r, |
| ... | ... | @@ -1413,13 +1414,13 @@ fn minMax( |
| 1413 | 1414 | rhs_ty: Type, |
| 1414 | 1415 | maybe_inst: ?Air.Inst.Index, |
| 1415 | 1416 | ) !MCValue { |
| 1416 | switch (lhs_ty.zigTypeTag()) { | |
| 1417 | const mod = self.bin_file.options.module.?; | |
| 1418 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 1417 | 1419 | .Float => return self.fail("TODO ARM min/max on floats", .{}), |
| 1418 | 1420 | .Vector => return self.fail("TODO ARM min/max on vectors", .{}), |
| 1419 | 1421 | .Int => { |
| 1420 | const mod = self.bin_file.options.module.?; | |
| 1421 | 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 | 1424 | if (int_info.bits <= 64) { |
| 1424 | 1425 | var lhs_reg: Register = undefined; |
| 1425 | 1426 | var rhs_reg: Register = undefined; |
| ... | ... | @@ -1488,8 +1489,8 @@ fn minMax( |
| 1488 | 1489 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1489 | 1490 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1490 | 1491 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1491 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1492 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1492 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1493 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1493 | 1494 | |
| 1494 | 1495 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1495 | 1496 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | ... | @@ -1508,9 +1509,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1508 | 1509 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1509 | 1510 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1510 | 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 | 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 | 1516 | const ptr_bits = self.target.ptrBitWidth(); |
| 1516 | 1517 | const ptr_bytes = @divExact(ptr_bits, 8); |
| ... | ... | @@ -1907,12 +1908,12 @@ fn addSub( |
| 1907 | 1908 | maybe_inst: ?Air.Inst.Index, |
| 1908 | 1909 | ) InnerError!MCValue { |
| 1909 | 1910 | const mod = self.bin_file.options.module.?; |
| 1910 | switch (lhs_ty.zigTypeTag()) { | |
| 1911 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 1911 | 1912 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 1912 | 1913 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 1913 | 1914 | .Int => { |
| 1914 | 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 | 1917 | if (int_info.bits <= 64) { |
| 1917 | 1918 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 1918 | 1919 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| ... | ... | @@ -1968,11 +1969,11 @@ fn mul( |
| 1968 | 1969 | maybe_inst: ?Air.Inst.Index, |
| 1969 | 1970 | ) InnerError!MCValue { |
| 1970 | 1971 | const mod = self.bin_file.options.module.?; |
| 1971 | switch (lhs_ty.zigTypeTag()) { | |
| 1972 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 1972 | 1973 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 1973 | 1974 | .Int => { |
| 1974 | 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 | 1977 | if (int_info.bits <= 64) { |
| 1977 | 1978 | // TODO add optimisations for multiplication |
| 1978 | 1979 | // with immediates, for example a * 2 can be |
| ... | ... | @@ -1999,7 +2000,8 @@ fn divFloat( |
| 1999 | 2000 | _ = rhs_ty; |
| 2000 | 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 | 2005 | .Float => return self.fail("TODO div_float", .{}), |
| 2004 | 2006 | .Vector => return self.fail("TODO div_float on vectors", .{}), |
| 2005 | 2007 | else => unreachable, |
| ... | ... | @@ -2015,12 +2017,12 @@ fn divTrunc( |
| 2015 | 2017 | maybe_inst: ?Air.Inst.Index, |
| 2016 | 2018 | ) InnerError!MCValue { |
| 2017 | 2019 | const mod = self.bin_file.options.module.?; |
| 2018 | switch (lhs_ty.zigTypeTag()) { | |
| 2020 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2019 | 2021 | .Float => return self.fail("TODO div on floats", .{}), |
| 2020 | 2022 | .Vector => return self.fail("TODO div on vectors", .{}), |
| 2021 | 2023 | .Int => { |
| 2022 | 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 | 2026 | if (int_info.bits <= 64) { |
| 2025 | 2027 | switch (int_info.signedness) { |
| 2026 | 2028 | .signed => { |
| ... | ... | @@ -2049,12 +2051,12 @@ fn divFloor( |
| 2049 | 2051 | maybe_inst: ?Air.Inst.Index, |
| 2050 | 2052 | ) InnerError!MCValue { |
| 2051 | 2053 | const mod = self.bin_file.options.module.?; |
| 2052 | switch (lhs_ty.zigTypeTag()) { | |
| 2054 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2053 | 2055 | .Float => return self.fail("TODO div on floats", .{}), |
| 2054 | 2056 | .Vector => return self.fail("TODO div on vectors", .{}), |
| 2055 | 2057 | .Int => { |
| 2056 | 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 | 2060 | if (int_info.bits <= 64) { |
| 2059 | 2061 | switch (int_info.signedness) { |
| 2060 | 2062 | .signed => { |
| ... | ... | @@ -2082,12 +2084,12 @@ fn divExact( |
| 2082 | 2084 | maybe_inst: ?Air.Inst.Index, |
| 2083 | 2085 | ) InnerError!MCValue { |
| 2084 | 2086 | const mod = self.bin_file.options.module.?; |
| 2085 | switch (lhs_ty.zigTypeTag()) { | |
| 2087 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2086 | 2088 | .Float => return self.fail("TODO div on floats", .{}), |
| 2087 | 2089 | .Vector => return self.fail("TODO div on vectors", .{}), |
| 2088 | 2090 | .Int => { |
| 2089 | 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 | 2093 | if (int_info.bits <= 64) { |
| 2092 | 2094 | switch (int_info.signedness) { |
| 2093 | 2095 | .signed => { |
| ... | ... | @@ -2118,12 +2120,12 @@ fn rem( |
| 2118 | 2120 | _ = maybe_inst; |
| 2119 | 2121 | |
| 2120 | 2122 | const mod = self.bin_file.options.module.?; |
| 2121 | switch (lhs_ty.zigTypeTag()) { | |
| 2123 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2122 | 2124 | .Float => return self.fail("TODO rem/mod on floats", .{}), |
| 2123 | 2125 | .Vector => return self.fail("TODO rem/mod on vectors", .{}), |
| 2124 | 2126 | .Int => { |
| 2125 | 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 | 2129 | if (int_info.bits <= 64) { |
| 2128 | 2130 | var lhs_reg: Register = undefined; |
| 2129 | 2131 | var rhs_reg: Register = undefined; |
| ... | ... | @@ -2188,7 +2190,8 @@ fn modulo( |
| 2188 | 2190 | _ = rhs_ty; |
| 2189 | 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 | 2195 | .Float => return self.fail("TODO mod on floats", .{}), |
| 2193 | 2196 | .Vector => return self.fail("TODO mod on vectors", .{}), |
| 2194 | 2197 | .Int => return self.fail("TODO mod on ints", .{}), |
| ... | ... | @@ -2205,10 +2208,11 @@ fn wrappingArithmetic( |
| 2205 | 2208 | rhs_ty: Type, |
| 2206 | 2209 | maybe_inst: ?Air.Inst.Index, |
| 2207 | 2210 | ) InnerError!MCValue { |
| 2208 | switch (lhs_ty.zigTypeTag()) { | |
| 2211 | const mod = self.bin_file.options.module.?; | |
| 2212 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2209 | 2213 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2210 | 2214 | .Int => { |
| 2211 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 2215 | const int_info = lhs_ty.intInfo(mod); | |
| 2212 | 2216 | if (int_info.bits <= 64) { |
| 2213 | 2217 | // Generate an add/sub/mul |
| 2214 | 2218 | const result: MCValue = switch (tag) { |
| ... | ... | @@ -2240,11 +2244,11 @@ fn bitwise( |
| 2240 | 2244 | maybe_inst: ?Air.Inst.Index, |
| 2241 | 2245 | ) InnerError!MCValue { |
| 2242 | 2246 | const mod = self.bin_file.options.module.?; |
| 2243 | switch (lhs_ty.zigTypeTag()) { | |
| 2247 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2244 | 2248 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2245 | 2249 | .Int => { |
| 2246 | 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 | 2252 | if (int_info.bits <= 64) { |
| 2249 | 2253 | // TODO implement bitwise operations with immediates |
| 2250 | 2254 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| ... | ... | @@ -2274,10 +2278,11 @@ fn shiftExact( |
| 2274 | 2278 | ) InnerError!MCValue { |
| 2275 | 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 | 2283 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2279 | 2284 | .Int => { |
| 2280 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 2285 | const int_info = lhs_ty.intInfo(mod); | |
| 2281 | 2286 | if (int_info.bits <= 64) { |
| 2282 | 2287 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 2283 | 2288 | |
| ... | ... | @@ -2323,10 +2328,11 @@ fn shiftNormal( |
| 2323 | 2328 | rhs_ty: Type, |
| 2324 | 2329 | maybe_inst: ?Air.Inst.Index, |
| 2325 | 2330 | ) InnerError!MCValue { |
| 2326 | switch (lhs_ty.zigTypeTag()) { | |
| 2331 | const mod = self.bin_file.options.module.?; | |
| 2332 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2327 | 2333 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2328 | 2334 | .Int => { |
| 2329 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 2335 | const int_info = lhs_ty.intInfo(mod); | |
| 2330 | 2336 | if (int_info.bits <= 64) { |
| 2331 | 2337 | // Generate a shl_exact/shr_exact |
| 2332 | 2338 | const result: MCValue = switch (tag) { |
| ... | ... | @@ -2362,7 +2368,8 @@ fn booleanOp( |
| 2362 | 2368 | rhs_ty: Type, |
| 2363 | 2369 | maybe_inst: ?Air.Inst.Index, |
| 2364 | 2370 | ) InnerError!MCValue { |
| 2365 | switch (lhs_ty.zigTypeTag()) { | |
| 2371 | const mod = self.bin_file.options.module.?; | |
| 2372 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2366 | 2373 | .Bool => { |
| 2367 | 2374 | assert((try lhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema |
| 2368 | 2375 | assert((try rhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema |
| ... | ... | @@ -2388,17 +2395,17 @@ fn ptrArithmetic( |
| 2388 | 2395 | rhs_ty: Type, |
| 2389 | 2396 | maybe_inst: ?Air.Inst.Index, |
| 2390 | 2397 | ) InnerError!MCValue { |
| 2391 | switch (lhs_ty.zigTypeTag()) { | |
| 2398 | const mod = self.bin_file.options.module.?; | |
| 2399 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2392 | 2400 | .Pointer => { |
| 2393 | const mod = self.bin_file.options.module.?; | |
| 2394 | 2401 | assert(rhs_ty.eql(Type.usize, mod)); |
| 2395 | 2402 | |
| 2396 | 2403 | const ptr_ty = lhs_ty; |
| 2397 | const elem_ty = switch (ptr_ty.ptrSize()) { | |
| 2398 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | |
| 2399 | else => ptr_ty.childType(), | |
| 2404 | const elem_ty = switch (ptr_ty.ptrSize(mod)) { | |
| 2405 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type | |
| 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 | 2410 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 2404 | 2411 | .ptr_add => .add, |
| ... | ... | @@ -2426,8 +2433,8 @@ fn ptrArithmetic( |
| 2426 | 2433 | |
| 2427 | 2434 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2428 | 2435 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2429 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 2430 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 2436 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 2437 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 2431 | 2438 | |
| 2432 | 2439 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2433 | 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 | 2484 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2478 | 2485 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2479 | 2486 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2480 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 2481 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 2487 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 2488 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 2482 | 2489 | |
| 2483 | 2490 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2484 | 2491 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | ... | @@ -2511,23 +2518,23 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2511 | 2518 | const tag = self.air.instructions.items(.tag)[inst]; |
| 2512 | 2519 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2513 | 2520 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2521 | const mod = self.bin_file.options.module.?; | |
| 2514 | 2522 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2515 | 2523 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2516 | 2524 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2517 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 2518 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 2525 | const lhs_ty = self.typeOf(extra.lhs); | |
| 2526 | const rhs_ty = self.typeOf(extra.rhs); | |
| 2519 | 2527 | |
| 2520 | const tuple_ty = self.air.typeOfIndex(inst); | |
| 2521 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | |
| 2522 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | |
| 2523 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | |
| 2528 | const tuple_ty = self.typeOfIndex(inst); | |
| 2529 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); | |
| 2530 | const tuple_align = tuple_ty.abiAlignment(mod); | |
| 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 | 2534 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), |
| 2527 | 2535 | .Int => { |
| 2528 | const mod = self.bin_file.options.module.?; | |
| 2529 | 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 | 2538 | switch (int_info.bits) { |
| 2532 | 2539 | 1...31, 33...63 => { |
| 2533 | 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 | 2572 | }); |
| 2566 | 2573 | |
| 2567 | 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 | 2577 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2571 | 2578 | }, |
| ... | ... | @@ -2639,24 +2646,23 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2639 | 2646 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2640 | 2647 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2641 | 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 | 2650 | const result: MCValue = result: { |
| 2643 | const mod = self.bin_file.options.module.?; | |
| 2644 | ||
| 2645 | 2651 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2646 | 2652 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2647 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 2648 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 2653 | const lhs_ty = self.typeOf(extra.lhs); | |
| 2654 | const rhs_ty = self.typeOf(extra.rhs); | |
| 2649 | 2655 | |
| 2650 | const tuple_ty = self.air.typeOfIndex(inst); | |
| 2651 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | |
| 2652 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | |
| 2653 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | |
| 2656 | const tuple_ty = self.typeOfIndex(inst); | |
| 2657 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); | |
| 2658 | const tuple_align = tuple_ty.abiAlignment(mod); | |
| 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 | 2662 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 2657 | 2663 | .Int => { |
| 2658 | 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 | 2666 | if (int_info.bits <= 32) { |
| 2661 | 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 | 2715 | } |
| 2710 | 2716 | |
| 2711 | 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 | 2720 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2715 | 2721 | } else if (int_info.bits <= 64) { |
| ... | ... | @@ -2849,7 +2855,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2849 | 2855 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 2850 | 2856 | |
| 2851 | 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 | 2860 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2855 | 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 | 2870 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2865 | 2871 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2866 | 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 | 2874 | const result: MCValue = result: { |
| 2868 | 2875 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2869 | 2876 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2870 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 2871 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 2877 | const lhs_ty = self.typeOf(extra.lhs); | |
| 2878 | const rhs_ty = self.typeOf(extra.rhs); | |
| 2872 | 2879 | |
| 2873 | const tuple_ty = self.air.typeOfIndex(inst); | |
| 2874 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | |
| 2875 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | |
| 2876 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | |
| 2880 | const tuple_ty = self.typeOfIndex(inst); | |
| 2881 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); | |
| 2882 | const tuple_align = tuple_ty.abiAlignment(mod); | |
| 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 | 2886 | .Vector => return self.fail("TODO implement shl_with_overflow for vectors", .{}), |
| 2880 | 2887 | .Int => { |
| 2881 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 2888 | const int_info = lhs_ty.intInfo(mod); | |
| 2882 | 2889 | if (int_info.bits <= 64) { |
| 2883 | 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 | 2988 | }); |
| 2982 | 2989 | |
| 2983 | 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 | 2993 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2987 | 2994 | } else { |
| ... | ... | @@ -3003,7 +3010,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3003 | 3010 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3004 | 3011 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3005 | 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 | 3014 | const mcv = try self.resolveInst(ty_op.operand); |
| 3008 | 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 | 3018 | } |
| 3012 | 3019 | |
| 3013 | 3020 | fn optionalPayload(self: *Self, inst: Air.Inst.Index, mcv: MCValue, optional_ty: Type) !MCValue { |
| 3014 | var opt_buf: Type.Payload.ElemType = undefined; | |
| 3015 | const payload_ty = optional_ty.optionalChild(&opt_buf); | |
| 3016 | if (!payload_ty.hasRuntimeBits()) return MCValue.none; | |
| 3017 | if (optional_ty.isPtrLikeOptional()) { | |
| 3021 | const mod = self.bin_file.options.module.?; | |
| 3022 | const payload_ty = optional_ty.optionalChild(mod); | |
| 3023 | if (!payload_ty.hasRuntimeBits(mod)) return MCValue.none; | |
| 3024 | if (optional_ty.isPtrLikeOptional(mod)) { | |
| 3018 | 3025 | // TODO should we reuse the operand here? |
| 3019 | 3026 | const raw_reg = try self.register_manager.allocReg(inst, gp); |
| 3020 | 3027 | const reg = self.registerAlias(raw_reg, payload_ty); |
| ... | ... | @@ -3055,16 +3062,17 @@ fn errUnionErr( |
| 3055 | 3062 | error_union_ty: Type, |
| 3056 | 3063 | maybe_inst: ?Air.Inst.Index, |
| 3057 | 3064 | ) !MCValue { |
| 3058 | const err_ty = error_union_ty.errorUnionSet(); | |
| 3059 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 3060 | if (err_ty.errorSetIsEmpty()) { | |
| 3065 | const mod = self.bin_file.options.module.?; | |
| 3066 | const err_ty = error_union_ty.errorUnionSet(mod); | |
| 3067 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 3068 | if (err_ty.errorSetIsEmpty(mod)) { | |
| 3061 | 3069 | return MCValue{ .immediate = 0 }; |
| 3062 | 3070 | } |
| 3063 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3071 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3064 | 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 | 3076 | switch (try error_union_bind.resolveToMcv(self)) { |
| 3069 | 3077 | .register => { |
| 3070 | 3078 | var operand_reg: Register = undefined; |
| ... | ... | @@ -3086,7 +3094,7 @@ fn errUnionErr( |
| 3086 | 3094 | ); |
| 3087 | 3095 | |
| 3088 | 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 | 3099 | _ = try self.addInst(.{ |
| 3092 | 3100 | .tag = .ubfx, // errors are unsigned integers |
| ... | ... | @@ -3120,7 +3128,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3120 | 3128 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3121 | 3129 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3122 | 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 | 3133 | break :result try self.errUnionErr(error_union_bind, error_union_ty, inst); |
| 3126 | 3134 | }; |
| ... | ... | @@ -3134,16 +3142,17 @@ fn errUnionPayload( |
| 3134 | 3142 | error_union_ty: Type, |
| 3135 | 3143 | maybe_inst: ?Air.Inst.Index, |
| 3136 | 3144 | ) !MCValue { |
| 3137 | const err_ty = error_union_ty.errorUnionSet(); | |
| 3138 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 3139 | if (err_ty.errorSetIsEmpty()) { | |
| 3145 | const mod = self.bin_file.options.module.?; | |
| 3146 | const err_ty = error_union_ty.errorUnionSet(mod); | |
| 3147 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 3148 | if (err_ty.errorSetIsEmpty(mod)) { | |
| 3140 | 3149 | return try error_union_bind.resolveToMcv(self); |
| 3141 | 3150 | } |
| 3142 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3151 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3143 | 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 | 3156 | switch (try error_union_bind.resolveToMcv(self)) { |
| 3148 | 3157 | .register => { |
| 3149 | 3158 | var operand_reg: Register = undefined; |
| ... | ... | @@ -3165,10 +3174,10 @@ fn errUnionPayload( |
| 3165 | 3174 | ); |
| 3166 | 3175 | |
| 3167 | 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 | 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 | 3181 | .data = .{ |
| 3173 | 3182 | .rr_lsb_width = .{ |
| 3174 | 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 | 3208 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3200 | 3209 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3201 | 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 | 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 | 3254 | } |
| 3246 | 3255 | |
| 3247 | 3256 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3257 | const mod = self.bin_file.options.module.?; | |
| 3248 | 3258 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3249 | 3259 | |
| 3250 | 3260 | if (self.liveness.isUnused(inst)) { |
| ... | ... | @@ -3252,12 +3262,12 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3252 | 3262 | } |
| 3253 | 3263 | |
| 3254 | 3264 | const result: MCValue = result: { |
| 3255 | const payload_ty = self.air.typeOf(ty_op.operand); | |
| 3256 | if (!payload_ty.hasRuntimeBits()) { | |
| 3265 | const payload_ty = self.typeOf(ty_op.operand); | |
| 3266 | if (!payload_ty.hasRuntimeBits(mod)) { | |
| 3257 | 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 | 3271 | const operand = try self.resolveInst(ty_op.operand); |
| 3262 | 3272 | const operand_lock: ?RegisterLock = switch (operand) { |
| 3263 | 3273 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -3265,7 +3275,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3265 | 3275 | }; |
| 3266 | 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 | 3279 | // TODO should we check if we can reuse the operand? |
| 3270 | 3280 | const raw_reg = try self.register_manager.allocReg(inst, gp); |
| 3271 | 3281 | const reg = self.registerAlias(raw_reg, payload_ty); |
| ... | ... | @@ -3273,9 +3283,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3273 | 3283 | break :result MCValue{ .register = reg }; |
| 3274 | 3284 | } |
| 3275 | 3285 | |
| 3276 | const optional_abi_size = @intCast(u32, optional_ty.abiSize(self.target.*)); | |
| 3277 | const optional_abi_align = optional_ty.abiAlignment(self.target.*); | |
| 3278 | const offset = @intCast(u32, payload_ty.abiSize(self.target.*)); | |
| 3286 | const optional_abi_size = @intCast(u32, optional_ty.abiSize(mod)); | |
| 3287 | const optional_abi_align = optional_ty.abiAlignment(mod); | |
| 3288 | const offset = @intCast(u32, payload_ty.abiSize(mod)); | |
| 3279 | 3289 | |
| 3280 | 3290 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); |
| 3281 | 3291 | try self.genSetStack(payload_ty, stack_offset, operand); |
| ... | ... | @@ -3289,19 +3299,20 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3289 | 3299 | |
| 3290 | 3300 | /// T to E!T |
| 3291 | 3301 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3302 | const mod = self.bin_file.options.module.?; | |
| 3292 | 3303 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3293 | 3304 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3294 | 3305 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 3295 | const error_ty = error_union_ty.errorUnionSet(); | |
| 3296 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 3306 | const error_ty = error_union_ty.errorUnionSet(mod); | |
| 3307 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 3297 | 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.*)); | |
| 3301 | const abi_align = error_union_ty.abiAlignment(self.target.*); | |
| 3311 | const abi_size = @intCast(u32, error_union_ty.abiSize(mod)); | |
| 3312 | const abi_align = error_union_ty.abiAlignment(mod); | |
| 3302 | 3313 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 3303 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | |
| 3304 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | |
| 3314 | const payload_off = errUnionPayloadOffset(payload_ty, mod); | |
| 3315 | const err_off = errUnionErrorOffset(payload_ty, mod); | |
| 3305 | 3316 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); |
| 3306 | 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 | 3325 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3315 | 3326 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3316 | 3327 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3328 | const mod = self.bin_file.options.module.?; | |
| 3317 | 3329 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 3318 | const error_ty = error_union_ty.errorUnionSet(); | |
| 3319 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 3330 | const error_ty = error_union_ty.errorUnionSet(mod); | |
| 3331 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 3320 | 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.*)); | |
| 3324 | const abi_align = error_union_ty.abiAlignment(self.target.*); | |
| 3335 | const abi_size = @intCast(u32, error_union_ty.abiSize(mod)); | |
| 3336 | const abi_align = error_union_ty.abiAlignment(mod); | |
| 3325 | 3337 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 3326 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | |
| 3327 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | |
| 3338 | const payload_off = errUnionPayloadOffset(payload_ty, mod); | |
| 3339 | const err_off = errUnionErrorOffset(payload_ty, mod); | |
| 3328 | 3340 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand); |
| 3329 | 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 | 3428 | } |
| 3417 | 3429 | |
| 3418 | 3430 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3431 | const mod = self.bin_file.options.module.?; | |
| 3419 | 3432 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3420 | const slice_ty = self.air.typeOf(bin_op.lhs); | |
| 3421 | const result: MCValue = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: { | |
| 3422 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 3423 | const ptr_ty = slice_ty.slicePtrFieldType(&buf); | |
| 3433 | const slice_ty = self.typeOf(bin_op.lhs); | |
| 3434 | const result: MCValue = if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { | |
| 3435 | const ptr_ty = slice_ty.slicePtrFieldType(mod); | |
| 3424 | 3436 | |
| 3425 | 3437 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 3426 | 3438 | const base_mcv = slicePtr(slice_mcv); |
| ... | ... | @@ -3440,8 +3452,9 @@ fn ptrElemVal( |
| 3440 | 3452 | ptr_ty: Type, |
| 3441 | 3453 | maybe_inst: ?Air.Inst.Index, |
| 3442 | 3454 | ) !MCValue { |
| 3443 | const elem_ty = ptr_ty.childType(); | |
| 3444 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | |
| 3455 | const mod = self.bin_file.options.module.?; | |
| 3456 | const elem_ty = ptr_ty.childType(mod); | |
| 3457 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | |
| 3445 | 3458 | |
| 3446 | 3459 | // TODO optimize for elem_sizes of 1, 2, 4, 8 |
| 3447 | 3460 | switch (elem_size) { |
| ... | ... | @@ -3465,8 +3478,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3465 | 3478 | const base_bind: ReadArg.Bind = .{ .mcv = base_mcv }; |
| 3466 | 3479 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 3467 | 3480 | |
| 3468 | const slice_ty = self.air.typeOf(extra.lhs); | |
| 3469 | const index_ty = self.air.typeOf(extra.rhs); | |
| 3481 | const slice_ty = self.typeOf(extra.lhs); | |
| 3482 | const index_ty = self.typeOf(extra.rhs); | |
| 3470 | 3483 | |
| 3471 | 3484 | const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null); |
| 3472 | 3485 | break :result addr; |
| ... | ... | @@ -3481,9 +3494,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3481 | 3494 | } |
| 3482 | 3495 | |
| 3483 | 3496 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3497 | const mod = self.bin_file.options.module.?; | |
| 3484 | 3498 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3485 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 3486 | const result: MCValue = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: { | |
| 3499 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 3500 | const result: MCValue = if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { | |
| 3487 | 3501 | const base_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 3488 | 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 | 3513 | const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 3500 | 3514 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 3501 | 3515 | |
| 3502 | const ptr_ty = self.air.typeOf(extra.lhs); | |
| 3503 | const index_ty = self.air.typeOf(extra.rhs); | |
| 3516 | const ptr_ty = self.typeOf(extra.lhs); | |
| 3517 | const index_ty = self.typeOf(extra.rhs); | |
| 3504 | 3518 | |
| 3505 | 3519 | const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null); |
| 3506 | 3520 | break :result addr; |
| ... | ... | @@ -3597,8 +3611,9 @@ fn reuseOperand( |
| 3597 | 3611 | } |
| 3598 | 3612 | |
| 3599 | 3613 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 3600 | const elem_ty = ptr_ty.elemType(); | |
| 3601 | const elem_size = elem_ty.abiSize(self.target.*); | |
| 3614 | const mod = self.bin_file.options.module.?; | |
| 3615 | const elem_ty = ptr_ty.childType(mod); | |
| 3616 | const elem_size = elem_ty.abiSize(mod); | |
| 3602 | 3617 | |
| 3603 | 3618 | switch (ptr) { |
| 3604 | 3619 | .none => unreachable, |
| ... | ... | @@ -3753,14 +3768,14 @@ fn genInlineMemset( |
| 3753 | 3768 | ) !void { |
| 3754 | 3769 | const dst_reg = switch (dst) { |
| 3755 | 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 | 3773 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 3759 | 3774 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3760 | 3775 | |
| 3761 | 3776 | const val_reg = switch (val) { |
| 3762 | 3777 | .register => |r| r, |
| 3763 | else => try self.copyToTmpRegister(Type.initTag(.u8), val), | |
| 3778 | else => try self.copyToTmpRegister(Type.u8, val), | |
| 3764 | 3779 | }; |
| 3765 | 3780 | const val_reg_lock = self.register_manager.lockReg(val_reg); |
| 3766 | 3781 | defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -3844,15 +3859,16 @@ fn genInlineMemsetCode( |
| 3844 | 3859 | } |
| 3845 | 3860 | |
| 3846 | 3861 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3862 | const mod = self.bin_file.options.module.?; | |
| 3847 | 3863 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3848 | const elem_ty = self.air.typeOfIndex(inst); | |
| 3849 | const elem_size = elem_ty.abiSize(self.target.*); | |
| 3864 | const elem_ty = self.typeOfIndex(inst); | |
| 3865 | const elem_size = elem_ty.abiSize(mod); | |
| 3850 | 3866 | const result: MCValue = result: { |
| 3851 | if (!elem_ty.hasRuntimeBits()) | |
| 3867 | if (!elem_ty.hasRuntimeBits(mod)) | |
| 3852 | 3868 | break :result MCValue.none; |
| 3853 | 3869 | |
| 3854 | 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 | 3872 | if (self.liveness.isUnused(inst) and !is_volatile) |
| 3857 | 3873 | break :result MCValue.dead; |
| 3858 | 3874 | |
| ... | ... | @@ -3867,18 +3883,19 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3867 | 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 | 3887 | break :result dst_mcv; |
| 3872 | 3888 | }; |
| 3873 | 3889 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3874 | 3890 | } |
| 3875 | 3891 | |
| 3876 | 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 | 3896 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3880 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate, | |
| 3881 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate, | |
| 3897 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate, | |
| 3898 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate, | |
| 3882 | 3899 | 4 => .ldr_immediate, |
| 3883 | 3900 | 8 => .ldr_immediate, |
| 3884 | 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 | 3913 | } |
| 3897 | 3914 | |
| 3898 | 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 | 3919 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3902 | 3920 | 1 => .strb_immediate, |
| ... | ... | @@ -3917,8 +3935,9 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type |
| 3917 | 3935 | } |
| 3918 | 3936 | |
| 3919 | 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 | 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 | 3942 | switch (ptr) { |
| 3924 | 3943 | .none => unreachable, |
| ... | ... | @@ -4046,8 +4065,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 4046 | 4065 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4047 | 4066 | const ptr = try self.resolveInst(bin_op.lhs); |
| 4048 | 4067 | const value = try self.resolveInst(bin_op.rhs); |
| 4049 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 4050 | const value_ty = self.air.typeOf(bin_op.rhs); | |
| 4068 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 4069 | const value_ty = self.typeOf(bin_op.rhs); | |
| 4051 | 4070 | |
| 4052 | 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 | 4088 | |
| 4070 | 4089 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 4071 | 4090 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 4091 | const mod = self.bin_file.options.module.?; | |
| 4072 | 4092 | const mcv = try self.resolveInst(operand); |
| 4073 | const ptr_ty = self.air.typeOf(operand); | |
| 4074 | const struct_ty = ptr_ty.childType(); | |
| 4075 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | |
| 4093 | const ptr_ty = self.typeOf(operand); | |
| 4094 | const struct_ty = ptr_ty.childType(mod); | |
| 4095 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); | |
| 4076 | 4096 | switch (mcv) { |
| 4077 | 4097 | .ptr_stack_offset => |off| { |
| 4078 | 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 | 4113 | const operand = extra.struct_operand; |
| 4094 | 4114 | const index = extra.field_index; |
| 4095 | 4115 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4116 | const mod = self.bin_file.options.module.?; | |
| 4096 | 4117 | const mcv = try self.resolveInst(operand); |
| 4097 | const struct_ty = self.air.typeOf(operand); | |
| 4098 | const struct_field_ty = struct_ty.structFieldType(index); | |
| 4099 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | |
| 4118 | const struct_ty = self.typeOf(operand); | |
| 4119 | const struct_field_ty = struct_ty.structFieldType(index, mod); | |
| 4120 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); | |
| 4100 | 4121 | |
| 4101 | 4122 | switch (mcv) { |
| 4102 | 4123 | .dead, .unreach => unreachable, |
| ... | ... | @@ -4142,12 +4163,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4142 | 4163 | } |
| 4143 | 4164 | |
| 4144 | 4165 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4166 | const mod = self.bin_file.options.module.?; | |
| 4145 | 4167 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4146 | 4168 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 4147 | 4169 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4148 | 4170 | const field_ptr = try self.resolveInst(extra.field_ptr); |
| 4149 | const struct_ty = self.air.getRefType(ty_pl.ty).childType(); | |
| 4150 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, self.target.*)); | |
| 4171 | const struct_ty = self.air.getRefType(ty_pl.ty).childType(mod); | |
| 4172 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, mod)); | |
| 4151 | 4173 | switch (field_ptr) { |
| 4152 | 4174 | .ptr_stack_offset => |off| { |
| 4153 | 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 | 4191 | while (self.args[arg_index] == .none) arg_index += 1; |
| 4170 | 4192 | self.arg_index = arg_index + 1; |
| 4171 | 4193 | |
| 4172 | const ty = self.air.typeOfIndex(inst); | |
| 4194 | const ty = self.typeOfIndex(inst); | |
| 4173 | 4195 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4174 | 4196 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 4175 | 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 | 4244 | const callee = pl_op.operand; |
| 4223 | 4245 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 4224 | 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 | 4251 | .Fn => ty, |
| 4229 | .Pointer => ty.childType(), | |
| 4252 | .Pointer => ty.childType(mod), | |
| 4230 | 4253 | else => unreachable, |
| 4231 | 4254 | }; |
| 4232 | 4255 | |
| ... | ... | @@ -4245,18 +4268,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4245 | 4268 | |
| 4246 | 4269 | if (info.return_value == .stack_offset) { |
| 4247 | 4270 | log.debug("airCall: return by reference", .{}); |
| 4248 | const ret_ty = fn_ty.fnReturnType(); | |
| 4249 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | |
| 4250 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); | |
| 4271 | const ret_ty = fn_ty.fnReturnType(mod); | |
| 4272 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(mod)); | |
| 4273 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(mod)); | |
| 4251 | 4274 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4252 | 4275 | |
| 4253 | 4276 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); |
| 4254 | 4277 | |
| 4255 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 4256 | .base = .{ .tag = .single_mut_pointer }, | |
| 4257 | .data = ret_ty, | |
| 4258 | }; | |
| 4259 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 4278 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | |
| 4260 | 4279 | try self.register_manager.getReg(ret_ptr_reg, null); |
| 4261 | 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 | 4287 | |
| 4269 | 4288 | for (info.args, 0..) |mc_arg, arg_i| { |
| 4270 | 4289 | const arg = args[arg_i]; |
| 4271 | const arg_ty = self.air.typeOf(arg); | |
| 4290 | const arg_ty = self.typeOf(arg); | |
| 4272 | 4291 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 4273 | 4292 | |
| 4274 | 4293 | switch (mc_arg) { |
| ... | ... | @@ -4289,21 +4308,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4289 | 4308 | |
| 4290 | 4309 | // Due to incremental compilation, how function calls are generated depends |
| 4291 | 4310 | // on linking. |
| 4292 | const mod = self.bin_file.options.module.?; | |
| 4293 | if (self.air.value(callee)) |func_value| { | |
| 4294 | if (func_value.castTag(.function)) |func_payload| { | |
| 4295 | const func = func_payload.data; | |
| 4296 | ||
| 4311 | if (try self.air.value(callee, mod)) |func_value| { | |
| 4312 | if (func_value.getFunction(mod)) |func| { | |
| 4297 | 4313 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4298 | 4314 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4299 | 4315 | const atom = elf_file.getAtom(atom_index); |
| 4300 | 4316 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 4301 | 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 | 4319 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 4304 | 4320 | const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4305 | 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 | 4323 | .linker_load = .{ |
| 4308 | 4324 | .type = .got, |
| 4309 | 4325 | .sym_index = sym_index, |
| ... | ... | @@ -4312,7 +4328,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4312 | 4328 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4313 | 4329 | const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4314 | 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 | 4332 | .linker_load = .{ |
| 4317 | 4333 | .type = .got, |
| 4318 | 4334 | .sym_index = sym_index, |
| ... | ... | @@ -4326,17 +4342,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4326 | 4342 | const got_addr = p9.bases.data; |
| 4327 | 4343 | const got_index = decl_block.got_index.?; |
| 4328 | 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 | 4346 | } else unreachable; |
| 4331 | 4347 | |
| 4332 | 4348 | _ = try self.addInst(.{ |
| 4333 | 4349 | .tag = .blr, |
| 4334 | 4350 | .data = .{ .reg = .x30 }, |
| 4335 | 4351 | }); |
| 4336 | } else if (func_value.castTag(.extern_fn)) |func_payload| { | |
| 4337 | const extern_fn = func_payload.data; | |
| 4338 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); | |
| 4339 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | |
| 4352 | } else if (func_value.getExternFunc(mod)) |extern_func| { | |
| 4353 | const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name); | |
| 4354 | const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); | |
| 4340 | 4355 | if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 4341 | 4356 | const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); |
| 4342 | 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 | 4367 | }); |
| 4353 | 4368 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4354 | 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 | 4371 | .linker_load = .{ |
| 4357 | 4372 | .type = .import, |
| 4358 | 4373 | .sym_index = sym_index, |
| ... | ... | @@ -4369,7 +4384,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4369 | 4384 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 4370 | 4385 | } |
| 4371 | 4386 | } else { |
| 4372 | assert(ty.zigTypeTag() == .Pointer); | |
| 4387 | assert(ty.zigTypeTag(mod) == .Pointer); | |
| 4373 | 4388 | const mcv = try self.resolveInst(callee); |
| 4374 | 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 | 4422 | } |
| 4408 | 4423 | |
| 4409 | 4424 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4425 | const mod = self.bin_file.options.module.?; | |
| 4410 | 4426 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4411 | 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 | 4430 | switch (self.ret_mcv) { |
| 4415 | 4431 | .none => {}, |
| 4416 | 4432 | .immediate => { |
| 4417 | assert(ret_ty.isError()); | |
| 4433 | assert(ret_ty.isError(mod)); | |
| 4418 | 4434 | }, |
| 4419 | 4435 | .register => |reg| { |
| 4420 | 4436 | // Return result by value |
| ... | ... | @@ -4425,11 +4441,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4425 | 4441 | // |
| 4426 | 4442 | // self.ret_mcv is an address to where this function |
| 4427 | 4443 | // should store its result into |
| 4428 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 4429 | .base = .{ .tag = .single_mut_pointer }, | |
| 4430 | .data = ret_ty, | |
| 4431 | }; | |
| 4432 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 4444 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | |
| 4433 | 4445 | try self.store(self.ret_mcv, operand, ptr_ty, ret_ty); |
| 4434 | 4446 | }, |
| 4435 | 4447 | else => unreachable, |
| ... | ... | @@ -4442,10 +4454,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4442 | 4454 | } |
| 4443 | 4455 | |
| 4444 | 4456 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4457 | const mod = self.bin_file.options.module.?; | |
| 4445 | 4458 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4446 | 4459 | const ptr = try self.resolveInst(un_op); |
| 4447 | const ptr_ty = self.air.typeOf(un_op); | |
| 4448 | const ret_ty = self.fn_type.fnReturnType(); | |
| 4460 | const ptr_ty = self.typeOf(un_op); | |
| 4461 | const ret_ty = self.fn_type.fnReturnType(mod); | |
| 4449 | 4462 | |
| 4450 | 4463 | switch (self.ret_mcv) { |
| 4451 | 4464 | .none => {}, |
| ... | ... | @@ -4465,8 +4478,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4465 | 4478 | // location. |
| 4466 | 4479 | const op_inst = Air.refToIndex(un_op).?; |
| 4467 | 4480 | if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) { |
| 4468 | const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | |
| 4469 | const abi_align = ret_ty.abiAlignment(self.target.*); | |
| 4481 | const abi_size = @intCast(u32, ret_ty.abiSize(mod)); | |
| 4482 | const abi_align = ret_ty.abiAlignment(mod); | |
| 4470 | 4483 | |
| 4471 | 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 | 4498 | |
| 4486 | 4499 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4487 | 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 | 4503 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 4491 | 4504 | break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op); |
| ... | ... | @@ -4501,29 +4514,28 @@ fn cmp( |
| 4501 | 4514 | lhs_ty: Type, |
| 4502 | 4515 | op: math.CompareOperator, |
| 4503 | 4516 | ) !MCValue { |
| 4504 | var int_buffer: Type.Payload.Bits = undefined; | |
| 4505 | const int_ty = switch (lhs_ty.zigTypeTag()) { | |
| 4517 | const mod = self.bin_file.options.module.?; | |
| 4518 | const int_ty = switch (lhs_ty.zigTypeTag(mod)) { | |
| 4506 | 4519 | .Optional => blk: { |
| 4507 | var opt_buffer: Type.Payload.ElemType = undefined; | |
| 4508 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); | |
| 4509 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4510 | break :blk Type.initTag(.u1); | |
| 4511 | } else if (lhs_ty.isPtrLikeOptional()) { | |
| 4520 | const payload_ty = lhs_ty.optionalChild(mod); | |
| 4521 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4522 | break :blk Type.u1; | |
| 4523 | } else if (lhs_ty.isPtrLikeOptional(mod)) { | |
| 4512 | 4524 | break :blk Type.usize; |
| 4513 | 4525 | } else { |
| 4514 | 4526 | return self.fail("TODO ARM cmp non-pointer optionals", .{}); |
| 4515 | 4527 | } |
| 4516 | 4528 | }, |
| 4517 | 4529 | .Float => return self.fail("TODO ARM cmp floats", .{}), |
| 4518 | .Enum => lhs_ty.intTagType(&int_buffer), | |
| 4530 | .Enum => lhs_ty.intTagType(mod), | |
| 4519 | 4531 | .Int => lhs_ty, |
| 4520 | .Bool => Type.initTag(.u1), | |
| 4532 | .Bool => Type.u1, | |
| 4521 | 4533 | .Pointer => Type.usize, |
| 4522 | .ErrorSet => Type.initTag(.u16), | |
| 4534 | .ErrorSet => Type.u16, | |
| 4523 | 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 | 4539 | if (int_info.bits <= 64) { |
| 4528 | 4540 | try self.spillCompareFlagsIfOccupied(); |
| 4529 | 4541 | |
| ... | ... | @@ -4609,8 +4621,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 4609 | 4621 | } |
| 4610 | 4622 | |
| 4611 | 4623 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 4612 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 4613 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 4624 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; | |
| 4625 | const mod = self.bin_file.options.module.?; | |
| 4626 | const function = mod.funcPtr(ty_fn.func); | |
| 4614 | 4627 | // TODO emit debug info for function change |
| 4615 | 4628 | _ = function; |
| 4616 | 4629 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | ... | @@ -4625,7 +4638,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4625 | 4638 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4626 | 4639 | const operand = pl_op.operand; |
| 4627 | 4640 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4628 | const ty = self.air.typeOf(operand); | |
| 4641 | const ty = self.typeOf(operand); | |
| 4629 | 4642 | const mcv = try self.resolveInst(operand); |
| 4630 | 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 | 4700 | // whether it needs to be spilled in the branches |
| 4688 | 4701 | if (self.liveness.operandDies(inst, 0)) { |
| 4689 | 4702 | const op_int = @enumToInt(pl_op.operand); |
| 4690 | if (op_int >= Air.Inst.Ref.typed_value_map.len) { | |
| 4691 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 4703 | if (op_int >= Air.ref_start_index) { | |
| 4704 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); | |
| 4692 | 4705 | self.processDeath(op_index); |
| 4693 | 4706 | } |
| 4694 | 4707 | } |
| ... | ... | @@ -4777,7 +4790,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4777 | 4790 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); |
| 4778 | 4791 | // TODO make sure the destination stack offset / register does not already have something |
| 4779 | 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 | 4794 | // TODO track the new register / stack allocation |
| 4782 | 4795 | } |
| 4783 | 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 | 4817 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); |
| 4805 | 4818 | // TODO make sure the destination stack offset / register does not already have something |
| 4806 | 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 | 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 | 4832 | } |
| 4820 | 4833 | |
| 4821 | 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: { | |
| 4823 | var buf: Type.Payload.ElemType = undefined; | |
| 4824 | const payload_ty = operand_ty.optionalChild(&buf); | |
| 4825 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) | |
| 4835 | const mod = self.bin_file.options.module.?; | |
| 4836 | const sentinel: struct { ty: Type, bind: ReadArg.Bind } = if (!operand_ty.isPtrLikeOptional(mod)) blk: { | |
| 4837 | const payload_ty = operand_ty.optionalChild(mod); | |
| 4838 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 4826 | 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 | 4842 | const operand_mcv = try operand_bind.resolveToMcv(self); |
| 4830 | 4843 | const new_mcv: MCValue = switch (operand_mcv) { |
| 4831 | 4844 | .register => |source_reg| new: { |
| ... | ... | @@ -4838,7 +4851,7 @@ fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue { |
| 4838 | 4851 | try self.genSetReg(payload_ty, dest_reg, operand_mcv); |
| 4839 | 4852 | } else { |
| 4840 | 4853 | _ = try self.addInst(.{ |
| 4841 | .tag = if (payload_ty.isSignedInt()) | |
| 4854 | .tag = if (payload_ty.isSignedInt(mod)) | |
| 4842 | 4855 | Mir.Inst.Tag.asr_immediate |
| 4843 | 4856 | else |
| 4844 | 4857 | Mir.Inst.Tag.lsr_immediate, |
| ... | ... | @@ -4875,9 +4888,10 @@ fn isErr( |
| 4875 | 4888 | error_union_bind: ReadArg.Bind, |
| 4876 | 4889 | error_union_ty: Type, |
| 4877 | 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 | 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 | 4922 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4909 | 4923 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4910 | 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 | 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 | 4930 | } |
| 4917 | 4931 | |
| 4918 | 4932 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4933 | const mod = self.bin_file.options.module.?; | |
| 4919 | 4934 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4920 | 4935 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4921 | 4936 | const operand_ptr = try self.resolveInst(un_op); |
| 4922 | const ptr_ty = self.air.typeOf(un_op); | |
| 4923 | const elem_ty = ptr_ty.elemType(); | |
| 4937 | const ptr_ty = self.typeOf(un_op); | |
| 4938 | const elem_ty = ptr_ty.childType(mod); | |
| 4924 | 4939 | |
| 4925 | 4940 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4926 | 4941 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | ... | @@ -4934,7 +4949,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4934 | 4949 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4935 | 4950 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4936 | 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 | 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 | 4957 | } |
| 4943 | 4958 | |
| 4944 | 4959 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4960 | const mod = self.bin_file.options.module.?; | |
| 4945 | 4961 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4946 | 4962 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4947 | 4963 | const operand_ptr = try self.resolveInst(un_op); |
| 4948 | const ptr_ty = self.air.typeOf(un_op); | |
| 4949 | const elem_ty = ptr_ty.elemType(); | |
| 4964 | const ptr_ty = self.typeOf(un_op); | |
| 4965 | const elem_ty = ptr_ty.childType(mod); | |
| 4950 | 4966 | |
| 4951 | 4967 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4952 | 4968 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | ... | @@ -4960,7 +4976,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4960 | 4976 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4961 | 4977 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4962 | 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 | 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 | 4984 | } |
| 4969 | 4985 | |
| 4970 | 4986 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4987 | const mod = self.bin_file.options.module.?; | |
| 4971 | 4988 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4972 | 4989 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4973 | 4990 | const operand_ptr = try self.resolveInst(un_op); |
| 4974 | const ptr_ty = self.air.typeOf(un_op); | |
| 4975 | const elem_ty = ptr_ty.elemType(); | |
| 4991 | const ptr_ty = self.typeOf(un_op); | |
| 4992 | const elem_ty = ptr_ty.childType(mod); | |
| 4976 | 4993 | |
| 4977 | 4994 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4978 | 4995 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | ... | @@ -4986,7 +5003,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4986 | 5003 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4987 | 5004 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4988 | 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 | 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 | 5011 | } |
| 4995 | 5012 | |
| 4996 | 5013 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5014 | const mod = self.bin_file.options.module.?; | |
| 4997 | 5015 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4998 | 5016 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4999 | 5017 | const operand_ptr = try self.resolveInst(un_op); |
| 5000 | const ptr_ty = self.air.typeOf(un_op); | |
| 5001 | const elem_ty = ptr_ty.elemType(); | |
| 5018 | const ptr_ty = self.typeOf(un_op); | |
| 5019 | const elem_ty = ptr_ty.childType(mod); | |
| 5002 | 5020 | |
| 5003 | 5021 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 5004 | 5022 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | ... | @@ -5065,7 +5083,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 5065 | 5083 | |
| 5066 | 5084 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 5067 | 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 | 5087 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 5070 | 5088 | const liveness = try self.liveness.getSwitchBr( |
| 5071 | 5089 | self.gpa, |
| ... | ... | @@ -5210,9 +5228,10 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 5210 | 5228 | } |
| 5211 | 5229 | |
| 5212 | 5230 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5231 | const mod = self.bin_file.options.module.?; | |
| 5213 | 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 | 5235 | const operand_mcv = try self.resolveInst(operand); |
| 5217 | 5236 | const block_mcv = block_data.mcv; |
| 5218 | 5237 | if (block_mcv == .none) { |
| ... | ... | @@ -5220,14 +5239,14 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5220 | 5239 | .none, .dead, .unreach => unreachable, |
| 5221 | 5240 | .register, .stack_offset, .memory => operand_mcv, |
| 5222 | 5241 | .immediate, .stack_argument_offset, .compare_flags => blk: { |
| 5223 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); | |
| 5224 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | |
| 5242 | const new_mcv = try self.allocRegOrMem(self.typeOfIndex(block), true, block); | |
| 5243 | try self.setRegOrMem(self.typeOfIndex(block), new_mcv, operand_mcv); | |
| 5225 | 5244 | break :blk new_mcv; |
| 5226 | 5245 | }, |
| 5227 | 5246 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), |
| 5228 | 5247 | }; |
| 5229 | 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 | 5252 | return self.brVoid(block); |
| ... | ... | @@ -5293,7 +5312,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 5293 | 5312 | |
| 5294 | 5313 | const arg_mcv = try self.resolveInst(input); |
| 5295 | 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 | 5405 | } |
| 5387 | 5406 | |
| 5388 | 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 | 5410 | switch (mcv) { |
| 5391 | 5411 | .dead => unreachable, |
| 5392 | 5412 | .unreach, .none => return, // Nothing to do. |
| ... | ... | @@ -5441,11 +5461,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5441 | 5461 | const reg_lock = self.register_manager.lockReg(rwo.reg); |
| 5442 | 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 | 5465 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = rwo.reg }); |
| 5446 | 5466 | |
| 5447 | const overflow_bit_ty = ty.structFieldType(1); | |
| 5448 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*)); | |
| 5467 | const overflow_bit_ty = ty.structFieldType(1, mod); | |
| 5468 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, mod)); | |
| 5449 | 5469 | const raw_cond_reg = try self.register_manager.allocReg(null, gp); |
| 5450 | 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 | 5498 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5479 | 5499 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 5480 | 5500 | } else { |
| 5481 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 5482 | .base = .{ .tag = .single_mut_pointer }, | |
| 5483 | .data = ty, | |
| 5484 | }; | |
| 5485 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 5501 | const ptr_ty = try mod.singleMutPtrType(ty); | |
| 5486 | 5502 | |
| 5487 | 5503 | // TODO call extern memcpy |
| 5488 | 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 | 5575 | } |
| 5560 | 5576 | |
| 5561 | 5577 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 5578 | const mod = self.bin_file.options.module.?; | |
| 5562 | 5579 | switch (mcv) { |
| 5563 | 5580 | .dead => unreachable, |
| 5564 | 5581 | .unreach, .none => return, // Nothing to do. |
| ... | ... | @@ -5669,13 +5686,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5669 | 5686 | try self.genLdrRegister(reg, reg.toX(), ty); |
| 5670 | 5687 | }, |
| 5671 | 5688 | .stack_offset => |off| { |
| 5672 | const abi_size = ty.abiSize(self.target.*); | |
| 5689 | const abi_size = ty.abiSize(mod); | |
| 5673 | 5690 | |
| 5674 | 5691 | switch (abi_size) { |
| 5675 | 5692 | 1, 2, 4, 8 => { |
| 5676 | 5693 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5677 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack, | |
| 5678 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack, | |
| 5694 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack, | |
| 5695 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack, | |
| 5679 | 5696 | 4, 8 => .ldr_stack, |
| 5680 | 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 | 5710 | } |
| 5694 | 5711 | }, |
| 5695 | 5712 | .stack_argument_offset => |off| { |
| 5696 | const abi_size = ty.abiSize(self.target.*); | |
| 5713 | const abi_size = ty.abiSize(mod); | |
| 5697 | 5714 | |
| 5698 | 5715 | switch (abi_size) { |
| 5699 | 5716 | 1, 2, 4, 8 => { |
| 5700 | 5717 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5701 | 1 => if (ty.isSignedInt()) 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, | |
| 5718 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument, | |
| 5719 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument, | |
| 5703 | 5720 | 4, 8 => .ldr_stack_argument, |
| 5704 | 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 | 5737 | } |
| 5721 | 5738 | |
| 5722 | 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 | 5742 | switch (mcv) { |
| 5725 | 5743 | .dead => unreachable, |
| 5726 | 5744 | .none, .unreach => return, |
| ... | ... | @@ -5728,7 +5746,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5728 | 5746 | if (!self.wantSafety()) |
| 5729 | 5747 | return; // The already existing value will do just fine. |
| 5730 | 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 | 5750 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 5733 | 5751 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 5734 | 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 | 5816 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5799 | 5817 | return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg }); |
| 5800 | 5818 | } else { |
| 5801 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 5802 | .base = .{ .tag = .single_mut_pointer }, | |
| 5803 | .data = ty, | |
| 5804 | }; | |
| 5805 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 5819 | const ptr_ty = try mod.singleMutPtrType(ty); | |
| 5806 | 5820 | |
| 5807 | 5821 | // TODO call extern memcpy |
| 5808 | 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 | 5927 | }; |
| 5914 | 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 | 5931 | const dest = try self.allocRegOrMem(dest_ty, true, inst); |
| 5918 | 5932 | try self.setRegOrMem(dest_ty, dest, operand); |
| 5919 | 5933 | break :result dest; |
| ... | ... | @@ -5922,19 +5936,20 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 5922 | 5936 | } |
| 5923 | 5937 | |
| 5924 | 5938 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5939 | const mod = self.bin_file.options.module.?; | |
| 5925 | 5940 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5926 | 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 | 5943 | const ptr = try self.resolveInst(ty_op.operand); |
| 5929 | const array_ty = ptr_ty.childType(); | |
| 5930 | const array_len = @intCast(u32, array_ty.arrayLen()); | |
| 5944 | const array_ty = ptr_ty.childType(mod); | |
| 5945 | const array_len = @intCast(u32, array_ty.arrayLen(mod)); | |
| 5931 | 5946 | |
| 5932 | 5947 | const ptr_bits = self.target.ptrBitWidth(); |
| 5933 | 5948 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 5934 | 5949 | |
| 5935 | 5950 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); |
| 5936 | 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 | 5953 | break :result MCValue{ .stack_offset = stack_offset }; |
| 5939 | 5954 | }; |
| 5940 | 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 | 6059 | } |
| 6045 | 6060 | |
| 6046 | 6061 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 6047 | const vector_ty = self.air.typeOfIndex(inst); | |
| 6048 | const len = vector_ty.vectorLen(); | |
| 6062 | const mod = self.bin_file.options.module.?; | |
| 6063 | const vector_ty = self.typeOfIndex(inst); | |
| 6064 | const len = vector_ty.vectorLen(mod); | |
| 6049 | 6065 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6050 | 6066 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 6051 | 6067 | const result: MCValue = res: { |
| ... | ... | @@ -6087,14 +6103,15 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 6087 | 6103 | } |
| 6088 | 6104 | |
| 6089 | 6105 | fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 6106 | const mod = self.bin_file.options.module.?; | |
| 6090 | 6107 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 6091 | 6108 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 6092 | 6109 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 6093 | 6110 | const result: MCValue = result: { |
| 6094 | 6111 | const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; |
| 6095 | const error_union_ty = self.air.typeOf(pl_op.operand); | |
| 6096 | const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | |
| 6097 | const error_union_align = error_union_ty.abiAlignment(self.target.*); | |
| 6112 | const error_union_ty = self.typeOf(pl_op.operand); | |
| 6113 | const error_union_size = @intCast(u32, error_union_ty.abiSize(mod)); | |
| 6114 | const error_union_align = error_union_ty.abiAlignment(mod); | |
| 6098 | 6115 | |
| 6099 | 6116 | // The error union will die in the body. However, we need the |
| 6100 | 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 | 6140 | } |
| 6124 | 6141 | |
| 6125 | 6142 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 6126 | // First section of indexes correspond to a set number of constant values. | |
| 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 | } | |
| 6143 | const mod = self.bin_file.options.module.?; | |
| 6135 | 6144 | |
| 6136 | 6145 | // If the type has no codegen bits, no need to store it. |
| 6137 | const inst_ty = self.air.typeOf(inst); | |
| 6138 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) | |
| 6146 | const inst_ty = self.typeOf(inst); | |
| 6147 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod) and !inst_ty.isError(mod)) | |
| 6139 | 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 | 6155 | switch (self.air.instructions.items(.tag)[inst_index]) { |
| 6143 | .constant => { | |
| 6156 | .interned => { | |
| 6144 | 6157 | // Constants have static lifetimes, so they are always memoized in the outer most table. |
| 6145 | 6158 | const branch = &self.branch_stack.items[0]; |
| 6146 | 6159 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); |
| 6147 | 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 | 6162 | gop.value_ptr.* = try self.genTypedValue(.{ |
| 6150 | 6163 | .ty = inst_ty, |
| 6151 | .val = self.air.values[ty_pl.payload], | |
| 6164 | .val = interned.toValue(), | |
| 6152 | 6165 | }); |
| 6153 | 6166 | } |
| 6154 | 6167 | return gop.value_ptr.*; |
| 6155 | 6168 | }, |
| 6156 | .const_ty => unreachable, | |
| 6157 | 6169 | else => return self.getResolvedInstValue(inst_index), |
| 6158 | 6170 | } |
| 6159 | 6171 | } |
| ... | ... | @@ -6208,12 +6220,11 @@ const CallMCValues = struct { |
| 6208 | 6220 | |
| 6209 | 6221 | /// Caller must call `CallMCValues.deinit`. |
| 6210 | 6222 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6211 | const cc = fn_ty.fnCallingConvention(); | |
| 6212 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | |
| 6213 | defer self.gpa.free(param_types); | |
| 6214 | fn_ty.fnParamTypes(param_types); | |
| 6223 | const mod = self.bin_file.options.module.?; | |
| 6224 | const fn_info = mod.typeToFunc(fn_ty).?; | |
| 6225 | const cc = fn_info.cc; | |
| 6215 | 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 | 6228 | // These undefined values must be populated before returning from this function. |
| 6218 | 6229 | .return_value = undefined, |
| 6219 | 6230 | .stack_byte_count = undefined, |
| ... | ... | @@ -6221,7 +6232,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6221 | 6232 | }; |
| 6222 | 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 | 6237 | switch (cc) { |
| 6227 | 6238 | .Naked => { |
| ... | ... | @@ -6236,14 +6247,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6236 | 6247 | var ncrn: usize = 0; // Next Core Register Number |
| 6237 | 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 | 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 | 6253 | result.return_value = .{ .none = {} }; |
| 6243 | 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 | 6256 | if (ret_ty_size == 0) { |
| 6246 | assert(ret_ty.isError()); | |
| 6257 | assert(ret_ty.isError(mod)); | |
| 6247 | 6258 | result.return_value = .{ .immediate = 0 }; |
| 6248 | 6259 | } else if (ret_ty_size <= 8) { |
| 6249 | 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 | 6263 | } |
| 6253 | 6264 | } |
| 6254 | 6265 | |
| 6255 | for (param_types, 0..) |ty, i| { | |
| 6256 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | |
| 6266 | for (fn_info.param_types, 0..) |ty, i| { | |
| 6267 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); | |
| 6257 | 6268 | if (param_size == 0) { |
| 6258 | 6269 | result.args[i] = .{ .none = {} }; |
| 6259 | 6270 | continue; |
| ... | ... | @@ -6261,14 +6272,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6261 | 6272 | |
| 6262 | 6273 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned |
| 6263 | 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 | 6276 | // Round up NCRN to the next even number |
| 6266 | 6277 | ncrn += ncrn % 2; |
| 6267 | 6278 | } |
| 6268 | 6279 | |
| 6269 | 6280 | if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) { |
| 6270 | 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 | 6283 | ncrn += 1; |
| 6273 | 6284 | } else { |
| 6274 | 6285 | return self.fail("TODO MCValues with multiple registers", .{}); |
| ... | ... | @@ -6279,7 +6290,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6279 | 6290 | ncrn = 8; |
| 6280 | 6291 | // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided |
| 6281 | 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 | 6294 | if (nsaa % 8 != 0) { |
| 6284 | 6295 | nsaa += 8 - (nsaa % 8); |
| 6285 | 6296 | } |
| ... | ... | @@ -6294,14 +6305,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6294 | 6305 | result.stack_align = 16; |
| 6295 | 6306 | }, |
| 6296 | 6307 | .Unspecified => { |
| 6297 | if (ret_ty.zigTypeTag() == .NoReturn) { | |
| 6308 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { | |
| 6298 | 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 | 6311 | result.return_value = .{ .none = {} }; |
| 6301 | 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 | 6314 | if (ret_ty_size == 0) { |
| 6304 | assert(ret_ty.isError()); | |
| 6315 | assert(ret_ty.isError(mod)); | |
| 6305 | 6316 | result.return_value = .{ .immediate = 0 }; |
| 6306 | 6317 | } else if (ret_ty_size <= 8) { |
| 6307 | 6318 | result.return_value = .{ .register = self.registerAlias(.x0, ret_ty) }; |
| ... | ... | @@ -6317,10 +6328,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6317 | 6328 | |
| 6318 | 6329 | var stack_offset: u32 = 0; |
| 6319 | 6330 | |
| 6320 | for (param_types, 0..) |ty, i| { | |
| 6321 | if (ty.abiSize(self.target.*) > 0) { | |
| 6322 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | |
| 6323 | const param_alignment = ty.abiAlignment(self.target.*); | |
| 6331 | for (fn_info.param_types, 0..) |ty, i| { | |
| 6332 | if (ty.toType().abiSize(mod) > 0) { | |
| 6333 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); | |
| 6334 | const param_alignment = ty.toType().abiAlignment(mod); | |
| 6324 | 6335 | |
| 6325 | 6336 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); |
| 6326 | 6337 | result.args[i] = .{ .stack_argument_offset = stack_offset }; |
| ... | ... | @@ -6371,7 +6382,8 @@ fn parseRegName(name: []const u8) ?Register { |
| 6371 | 6382 | } |
| 6372 | 6383 | |
| 6373 | 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 | 6388 | switch (reg.class()) { |
| 6377 | 6389 | .general_purpose => { |
| ... | ... | @@ -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 | 4 | const Register = bits.Register; |
| 5 | 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 6 | 6 | const Type = @import("../../type.zig").Type; |
| 7 | const Module = @import("../../Module.zig"); | |
| 7 | 8 | |
| 8 | 9 | pub const Class = union(enum) { |
| 9 | 10 | memory, |
| ... | ... | @@ -14,44 +15,44 @@ pub const Class = union(enum) { |
| 14 | 15 | }; |
| 15 | 16 | |
| 16 | 17 | /// For `float_array` the second element will be the amount of floats. |
| 17 | pub fn classifyType(ty: Type, target: std.Target) Class { | |
| 18 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime()); | |
| 18 | pub fn classifyType(ty: Type, mod: *Module) Class { | |
| 19 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(mod)); | |
| 19 | 20 | |
| 20 | 21 | var maybe_float_bits: ?u16 = null; |
| 21 | switch (ty.zigTypeTag()) { | |
| 22 | switch (ty.zigTypeTag(mod)) { | |
| 22 | 23 | .Struct => { |
| 23 | if (ty.containerLayout() == .Packed) return .byval; | |
| 24 | const float_count = countFloats(ty, target, &maybe_float_bits); | |
| 24 | if (ty.containerLayout(mod) == .Packed) return .byval; | |
| 25 | const float_count = countFloats(ty, mod, &maybe_float_bits); | |
| 25 | 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 | 29 | if (bit_size > 128) return .memory; |
| 29 | 30 | if (bit_size > 64) return .double_integer; |
| 30 | 31 | return .integer; |
| 31 | 32 | }, |
| 32 | 33 | .Union => { |
| 33 | if (ty.containerLayout() == .Packed) return .byval; | |
| 34 | const float_count = countFloats(ty, target, &maybe_float_bits); | |
| 34 | if (ty.containerLayout(mod) == .Packed) return .byval; | |
| 35 | const float_count = countFloats(ty, mod, &maybe_float_bits); | |
| 35 | 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 | 39 | if (bit_size > 128) return .memory; |
| 39 | 40 | if (bit_size > 64) return .double_integer; |
| 40 | 41 | return .integer; |
| 41 | 42 | }, |
| 42 | 43 | .Int, .Enum, .ErrorSet, .Float, .Bool => return .byval, |
| 43 | 44 | .Vector => { |
| 44 | const bit_size = ty.bitSize(target); | |
| 45 | const bit_size = ty.bitSize(mod); | |
| 45 | 46 | // TODO is this controlled by a cpu feature? |
| 46 | 47 | if (bit_size > 128) return .memory; |
| 47 | 48 | return .byval; |
| 48 | 49 | }, |
| 49 | 50 | .Optional => { |
| 50 | std.debug.assert(ty.isPtrLikeOptional()); | |
| 51 | std.debug.assert(ty.isPtrLikeOptional(mod)); | |
| 51 | 52 | return .byval; |
| 52 | 53 | }, |
| 53 | 54 | .Pointer => { |
| 54 | std.debug.assert(!ty.isSlice()); | |
| 55 | std.debug.assert(!ty.isSlice(mod)); | |
| 55 | 56 | return .byval; |
| 56 | 57 | }, |
| 57 | 58 | .ErrorUnion, |
| ... | ... | @@ -73,14 +74,15 @@ pub fn classifyType(ty: Type, target: std.Target) Class { |
| 73 | 74 | } |
| 74 | 75 | |
| 75 | 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 | 79 | const invalid = std.math.maxInt(u8); |
| 78 | switch (ty.zigTypeTag()) { | |
| 80 | switch (ty.zigTypeTag(mod)) { | |
| 79 | 81 | .Union => { |
| 80 | const fields = ty.unionFields(); | |
| 82 | const fields = ty.unionFields(mod); | |
| 81 | 83 | var max_count: u8 = 0; |
| 82 | 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 | 86 | if (field_count == invalid) return invalid; |
| 85 | 87 | if (field_count > max_count) max_count = field_count; |
| 86 | 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 | 90 | return max_count; |
| 89 | 91 | }, |
| 90 | 92 | .Struct => { |
| 91 | const fields_len = ty.structFieldCount(); | |
| 93 | const fields_len = ty.structFieldCount(mod); | |
| 92 | 94 | var count: u8 = 0; |
| 93 | 95 | var i: u32 = 0; |
| 94 | 96 | while (i < fields_len) : (i += 1) { |
| 95 | const field_ty = ty.structFieldType(i); | |
| 96 | const field_count = countFloats(field_ty, target, maybe_float_bits); | |
| 97 | const field_ty = ty.structFieldType(i, mod); | |
| 98 | const field_count = countFloats(field_ty, mod, maybe_float_bits); | |
| 97 | 99 | if (field_count == invalid) return invalid; |
| 98 | 100 | count += field_count; |
| 99 | 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 | 115 | } |
| 114 | 116 | } |
| 115 | 117 | |
| 116 | pub fn getFloatArrayType(ty: Type) ?Type { | |
| 117 | switch (ty.zigTypeTag()) { | |
| 118 | pub fn getFloatArrayType(ty: Type, mod: *Module) ?Type { | |
| 119 | switch (ty.zigTypeTag(mod)) { | |
| 118 | 120 | .Union => { |
| 119 | const fields = ty.unionFields(); | |
| 121 | const fields = ty.unionFields(mod); | |
| 120 | 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 | 125 | return null; |
| 124 | 126 | }, |
| 125 | 127 | .Struct => { |
| 126 | const fields_len = ty.structFieldCount(); | |
| 128 | const fields_len = ty.structFieldCount(mod); | |
| 127 | 129 | var i: u32 = 0; |
| 128 | 130 | while (i < fields_len) : (i += 1) { |
| 129 | const field_ty = ty.structFieldType(i); | |
| 130 | if (getFloatArrayType(field_ty)) |some| return some; | |
| 131 | const field_ty = ty.structFieldType(i, mod); | |
| 132 | if (getFloatArrayType(field_ty, mod)) |some| return some; | |
| 131 | 133 | } |
| 132 | 134 | return null; |
| 133 | 135 | }, |
src/arch/arm/CodeGen.zig+365-342| ... | ... | @@ -334,7 +334,7 @@ const Self = @This(); |
| 334 | 334 | pub fn generate( |
| 335 | 335 | bin_file: *link.File, |
| 336 | 336 | src_loc: Module.SrcLoc, |
| 337 | module_fn: *Module.Fn, | |
| 337 | module_fn_index: Module.Fn.Index, | |
| 338 | 338 | air: Air, |
| 339 | 339 | liveness: Liveness, |
| 340 | 340 | code: *std.ArrayList(u8), |
| ... | ... | @@ -345,6 +345,7 @@ pub fn generate( |
| 345 | 345 | } |
| 346 | 346 | |
| 347 | 347 | const mod = bin_file.options.module.?; |
| 348 | const module_fn = mod.funcPtr(module_fn_index); | |
| 348 | 349 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 349 | 350 | assert(fn_owner_decl.has_tv); |
| 350 | 351 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -477,7 +478,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 477 | 478 | } |
| 478 | 479 | |
| 479 | 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 | 483 | if (cc != .Naked) { |
| 482 | 484 | // push {fp, lr} |
| 483 | 485 | const push_reloc = try self.addNop(); |
| ... | ... | @@ -518,10 +520,10 @@ fn gen(self: *Self) !void { |
| 518 | 520 | const inst = self.air.getMainBody()[arg_index]; |
| 519 | 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.*)); | |
| 524 | const abi_align = ty.abiAlignment(self.target.*); | |
| 525 | const abi_size = @intCast(u32, ty.abiSize(mod)); | |
| 526 | const abi_align = ty.abiAlignment(mod); | |
| 525 | 527 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 526 | 528 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 527 | 529 | |
| ... | ... | @@ -636,13 +638,14 @@ fn gen(self: *Self) !void { |
| 636 | 638 | } |
| 637 | 639 | |
| 638 | 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 | 643 | const air_tags = self.air.instructions.items(.tag); |
| 640 | 644 | |
| 641 | 645 | for (body) |inst| { |
| 642 | 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 | 648 | continue; |
| 645 | } | |
| 646 | 649 | |
| 647 | 650 | const old_air_bookkeeping = self.air_bookkeeping; |
| 648 | 651 | try self.ensureProcessDeathCapacity(Liveness.bpi); |
| ... | ... | @@ -826,8 +829,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 826 | 829 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 827 | 830 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 828 | 831 | |
| 829 | .constant => unreachable, // excluded from function bodies | |
| 830 | .const_ty => unreachable, // excluded from function bodies | |
| 832 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 831 | 833 | .unreach => self.finishAirBookkeeping(), |
| 832 | 834 | |
| 833 | 835 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | ... | @@ -900,8 +902,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 900 | 902 | |
| 901 | 903 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 902 | 904 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 903 | const air_tags = self.air.instructions.items(.tag); | |
| 904 | if (air_tags[inst] == .constant) return; // Constants are immortal. | |
| 905 | assert(self.air.instructions.items(.tag)[inst] != .interned); | |
| 905 | 906 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 906 | 907 | const prev_value = self.getResolvedInstValue(inst); |
| 907 | 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 | 938 | tomb_bits >>= 1; |
| 938 | 939 | if (!dies) continue; |
| 939 | 940 | const op_int = @enumToInt(op); |
| 940 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | |
| 941 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 941 | if (op_int < Air.ref_start_index) continue; | |
| 942 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); | |
| 942 | 943 | self.processDeath(op_index); |
| 943 | 944 | } |
| 944 | 945 | const is_used = @truncate(u1, tomb_bits) == 0; |
| ... | ... | @@ -1006,9 +1007,10 @@ fn allocMem( |
| 1006 | 1007 | |
| 1007 | 1008 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 1008 | 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 | 1014 | // As this stack item will never be dereferenced at runtime, |
| 1013 | 1015 | // return the stack offset 0. Stack offset 0 will be where all |
| 1014 | 1016 | // zero-sized stack allocations live as non-zero-sized |
| ... | ... | @@ -1016,22 +1018,21 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 1016 | 1018 | return @as(u32, 0); |
| 1017 | 1019 | } |
| 1018 | 1020 | |
| 1019 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | |
| 1020 | const mod = self.bin_file.options.module.?; | |
| 1021 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { | |
| 1021 | 1022 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 1022 | 1023 | }; |
| 1023 | 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 | 1027 | return self.allocMem(abi_size, abi_align, inst); |
| 1027 | 1028 | } |
| 1028 | 1029 | |
| 1029 | 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 | 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 | 1037 | if (reg_ok) { |
| 1037 | 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 | 1050 | } |
| 1050 | 1051 | |
| 1051 | 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 | 1054 | log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv }); |
| 1054 | 1055 | |
| 1055 | 1056 | const reg_mcv = self.getResolvedInstValue(inst); |
| ... | ... | @@ -1063,14 +1064,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 1063 | 1064 | |
| 1064 | 1065 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1065 | 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 | 1070 | /// Save the current instruction stored in the compare flags if |
| 1070 | 1071 | /// occupied |
| 1071 | 1072 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 1072 | 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 | 1075 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 1075 | 1076 | const new_mcv = switch (mcv) { |
| 1076 | 1077 | .cpsr_flags => try self.allocRegOrMem(ty, true, inst_to_save), |
| ... | ... | @@ -1080,7 +1081,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 1080 | 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 | 1085 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); |
| 1085 | 1086 | |
| 1086 | 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 | 1115 | } |
| 1115 | 1116 | |
| 1116 | 1117 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1118 | const mod = self.bin_file.options.module.?; | |
| 1117 | 1119 | const result: MCValue = switch (self.ret_mcv) { |
| 1118 | 1120 | .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, |
| 1119 | 1121 | .stack_offset => blk: { |
| 1120 | 1122 | // self.ret_mcv is an address to where this function |
| 1121 | 1123 | // should store its result into |
| 1122 | const ret_ty = self.fn_type.fnReturnType(); | |
| 1123 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 1124 | .base = .{ .tag = .single_mut_pointer }, | |
| 1125 | .data = ret_ty, | |
| 1126 | }; | |
| 1127 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 1124 | const ret_ty = self.fn_type.fnReturnType(mod); | |
| 1125 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | |
| 1128 | 1126 | |
| 1129 | 1127 | // addr_reg will contain the address of where to store the |
| 1130 | 1128 | // result into |
| ... | ... | @@ -1150,18 +1148,19 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 1150 | 1148 | } |
| 1151 | 1149 | |
| 1152 | 1150 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1151 | const mod = self.bin_file.options.module.?; | |
| 1153 | 1152 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1154 | 1153 | if (self.liveness.isUnused(inst)) |
| 1155 | 1154 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1156 | 1155 | |
| 1157 | 1156 | const operand = try self.resolveInst(ty_op.operand); |
| 1158 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 1159 | const dest_ty = self.air.typeOfIndex(inst); | |
| 1157 | const operand_ty = self.typeOf(ty_op.operand); | |
| 1158 | const dest_ty = self.typeOfIndex(inst); | |
| 1160 | 1159 | |
| 1161 | const operand_abi_size = operand_ty.abiSize(self.target.*); | |
| 1162 | const dest_abi_size = dest_ty.abiSize(self.target.*); | |
| 1163 | const info_a = operand_ty.intInfo(self.target.*); | |
| 1164 | const info_b = dest_ty.intInfo(self.target.*); | |
| 1160 | const operand_abi_size = operand_ty.abiSize(mod); | |
| 1161 | const dest_abi_size = dest_ty.abiSize(mod); | |
| 1162 | const info_a = operand_ty.intInfo(mod); | |
| 1163 | const info_b = dest_ty.intInfo(mod); | |
| 1165 | 1164 | |
| 1166 | 1165 | const dst_mcv: MCValue = blk: { |
| 1167 | 1166 | if (info_a.bits == info_b.bits) { |
| ... | ... | @@ -1215,8 +1214,9 @@ fn trunc( |
| 1215 | 1214 | operand_ty: Type, |
| 1216 | 1215 | dest_ty: Type, |
| 1217 | 1216 | ) !MCValue { |
| 1218 | const info_a = operand_ty.intInfo(self.target.*); | |
| 1219 | const info_b = dest_ty.intInfo(self.target.*); | |
| 1217 | const mod = self.bin_file.options.module.?; | |
| 1218 | const info_a = operand_ty.intInfo(mod); | |
| 1219 | const info_b = dest_ty.intInfo(mod); | |
| 1220 | 1220 | |
| 1221 | 1221 | if (info_b.bits <= 32) { |
| 1222 | 1222 | if (info_a.bits > 32) { |
| ... | ... | @@ -1259,8 +1259,8 @@ fn trunc( |
| 1259 | 1259 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1260 | 1260 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1261 | 1261 | const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 1262 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 1263 | const dest_ty = self.air.typeOfIndex(inst); | |
| 1262 | const operand_ty = self.typeOf(ty_op.operand); | |
| 1263 | const dest_ty = self.typeOfIndex(inst); | |
| 1264 | 1264 | |
| 1265 | 1265 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 1266 | 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 | 1278 | |
| 1279 | 1279 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1280 | 1280 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1281 | const mod = self.bin_file.options.module.?; | |
| 1281 | 1282 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1282 | 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 | 1285 | switch (try operand_bind.resolveToMcv(self)) { |
| 1285 | 1286 | .dead => unreachable, |
| 1286 | 1287 | .unreach => unreachable, |
| 1287 | 1288 | .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() }, |
| 1288 | 1289 | else => { |
| 1289 | switch (operand_ty.zigTypeTag()) { | |
| 1290 | switch (operand_ty.zigTypeTag(mod)) { | |
| 1290 | 1291 | .Bool => { |
| 1291 | 1292 | var op_reg: Register = undefined; |
| 1292 | 1293 | var dest_reg: Register = undefined; |
| ... | ... | @@ -1319,7 +1320,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1319 | 1320 | }, |
| 1320 | 1321 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), |
| 1321 | 1322 | .Int => { |
| 1322 | const int_info = operand_ty.intInfo(self.target.*); | |
| 1323 | const int_info = operand_ty.intInfo(mod); | |
| 1323 | 1324 | if (int_info.bits <= 32) { |
| 1324 | 1325 | var op_reg: Register = undefined; |
| 1325 | 1326 | var dest_reg: Register = undefined; |
| ... | ... | @@ -1373,13 +1374,13 @@ fn minMax( |
| 1373 | 1374 | rhs_ty: Type, |
| 1374 | 1375 | maybe_inst: ?Air.Inst.Index, |
| 1375 | 1376 | ) !MCValue { |
| 1376 | switch (lhs_ty.zigTypeTag()) { | |
| 1377 | const mod = self.bin_file.options.module.?; | |
| 1378 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 1377 | 1379 | .Float => return self.fail("TODO ARM min/max on floats", .{}), |
| 1378 | 1380 | .Vector => return self.fail("TODO ARM min/max on vectors", .{}), |
| 1379 | 1381 | .Int => { |
| 1380 | const mod = self.bin_file.options.module.?; | |
| 1381 | 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 | 1384 | if (int_info.bits <= 32) { |
| 1384 | 1385 | var lhs_reg: Register = undefined; |
| 1385 | 1386 | var rhs_reg: Register = undefined; |
| ... | ... | @@ -1463,8 +1464,8 @@ fn minMax( |
| 1463 | 1464 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1464 | 1465 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1465 | 1466 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1466 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1467 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1467 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1468 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1468 | 1469 | |
| 1469 | 1470 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1470 | 1471 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | ... | @@ -1483,9 +1484,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1483 | 1484 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1484 | 1485 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1485 | 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 | 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 | 1491 | const stack_offset = try self.allocMem(8, 4, inst); |
| 1491 | 1492 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| ... | ... | @@ -1497,8 +1498,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1497 | 1498 | |
| 1498 | 1499 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1499 | 1500 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1500 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1501 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1501 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1502 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1502 | 1503 | |
| 1503 | 1504 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1504 | 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 | 1549 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1549 | 1550 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1550 | 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 rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1552 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1553 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1553 | 1554 | |
| 1554 | 1555 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1555 | 1556 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | ... | @@ -1582,23 +1583,23 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1582 | 1583 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1583 | 1584 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1584 | 1585 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1586 | const mod = self.bin_file.options.module.?; | |
| 1585 | 1587 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1586 | 1588 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 1587 | 1589 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 1588 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 1589 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 1590 | const lhs_ty = self.typeOf(extra.lhs); | |
| 1591 | const rhs_ty = self.typeOf(extra.rhs); | |
| 1590 | 1592 | |
| 1591 | const tuple_ty = self.air.typeOfIndex(inst); | |
| 1592 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | |
| 1593 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | |
| 1594 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | |
| 1593 | const tuple_ty = self.typeOfIndex(inst); | |
| 1594 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); | |
| 1595 | const tuple_align = tuple_ty.abiAlignment(mod); | |
| 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 | 1599 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), |
| 1598 | 1600 | .Int => { |
| 1599 | const mod = self.bin_file.options.module.?; | |
| 1600 | 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 | 1603 | if (int_info.bits < 32) { |
| 1603 | 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 | 1632 | }); |
| 1632 | 1633 | |
| 1633 | 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 | 1637 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1637 | 1638 | } else if (int_info.bits == 32) { |
| ... | ... | @@ -1695,23 +1696,23 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1695 | 1696 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1696 | 1697 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1697 | 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 | 1700 | const result: MCValue = result: { |
| 1699 | 1701 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 1700 | 1702 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 1701 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 1702 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 1703 | const lhs_ty = self.typeOf(extra.lhs); | |
| 1704 | const rhs_ty = self.typeOf(extra.rhs); | |
| 1703 | 1705 | |
| 1704 | const tuple_ty = self.air.typeOfIndex(inst); | |
| 1705 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | |
| 1706 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | |
| 1707 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | |
| 1706 | const tuple_ty = self.typeOfIndex(inst); | |
| 1707 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); | |
| 1708 | const tuple_align = tuple_ty.abiAlignment(mod); | |
| 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 | 1712 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 1711 | 1713 | .Int => { |
| 1712 | const mod = self.bin_file.options.module.?; | |
| 1713 | 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 | 1716 | if (int_info.bits <= 16) { |
| 1716 | 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 | 1745 | }); |
| 1745 | 1746 | |
| 1746 | 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 | 1750 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1750 | 1751 | } else if (int_info.bits <= 32) { |
| ... | ... | @@ -1842,7 +1843,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1842 | 1843 | }); |
| 1843 | 1844 | |
| 1844 | 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 | 1848 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1848 | 1849 | } else { |
| ... | ... | @@ -1859,19 +1860,20 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1859 | 1860 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1860 | 1861 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1861 | 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 | 1864 | const result: MCValue = result: { |
| 1863 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 1864 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 1865 | const lhs_ty = self.typeOf(extra.lhs); | |
| 1866 | const rhs_ty = self.typeOf(extra.rhs); | |
| 1865 | 1867 | |
| 1866 | const tuple_ty = self.air.typeOfIndex(inst); | |
| 1867 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | |
| 1868 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | |
| 1869 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | |
| 1868 | const tuple_ty = self.typeOfIndex(inst); | |
| 1869 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); | |
| 1870 | const tuple_align = tuple_ty.abiAlignment(mod); | |
| 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 | 1874 | .Vector => return self.fail("TODO implement shl_with_overflow for vectors", .{}), |
| 1873 | 1875 | .Int => { |
| 1874 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 1876 | const int_info = lhs_ty.intInfo(mod); | |
| 1875 | 1877 | if (int_info.bits <= 32) { |
| 1876 | 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 | 1978 | }); |
| 1977 | 1979 | |
| 1978 | 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 | 1983 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1982 | 1984 | } else { |
| ... | ... | @@ -2014,10 +2016,11 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2014 | 2016 | } |
| 2015 | 2017 | |
| 2016 | 2018 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2019 | const mod = self.bin_file.options.module.?; | |
| 2017 | 2020 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2018 | 2021 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2019 | const optional_ty = self.air.typeOfIndex(inst); | |
| 2020 | const abi_size = @intCast(u32, optional_ty.abiSize(self.target.*)); | |
| 2022 | const optional_ty = self.typeOfIndex(inst); | |
| 2023 | const abi_size = @intCast(u32, optional_ty.abiSize(mod)); | |
| 2021 | 2024 | |
| 2022 | 2025 | // Optional with a zero-bit payload type is just a boolean true |
| 2023 | 2026 | if (abi_size == 1) { |
| ... | ... | @@ -2036,16 +2039,17 @@ fn errUnionErr( |
| 2036 | 2039 | error_union_ty: Type, |
| 2037 | 2040 | maybe_inst: ?Air.Inst.Index, |
| 2038 | 2041 | ) !MCValue { |
| 2039 | const err_ty = error_union_ty.errorUnionSet(); | |
| 2040 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 2041 | if (err_ty.errorSetIsEmpty()) { | |
| 2042 | const mod = self.bin_file.options.module.?; | |
| 2043 | const err_ty = error_union_ty.errorUnionSet(mod); | |
| 2044 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 2045 | if (err_ty.errorSetIsEmpty(mod)) { | |
| 2042 | 2046 | return MCValue{ .immediate = 0 }; |
| 2043 | 2047 | } |
| 2044 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2048 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2045 | 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 | 2053 | switch (try error_union_bind.resolveToMcv(self)) { |
| 2050 | 2054 | .register => { |
| 2051 | 2055 | var operand_reg: Register = undefined; |
| ... | ... | @@ -2067,7 +2071,7 @@ fn errUnionErr( |
| 2067 | 2071 | ); |
| 2068 | 2072 | |
| 2069 | 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 | 2076 | _ = try self.addInst(.{ |
| 2073 | 2077 | .tag = .ubfx, // errors are unsigned integers |
| ... | ... | @@ -2098,7 +2102,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2098 | 2102 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2099 | 2103 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2100 | 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 | 2107 | break :result try self.errUnionErr(error_union_bind, error_union_ty, inst); |
| 2104 | 2108 | }; |
| ... | ... | @@ -2112,16 +2116,17 @@ fn errUnionPayload( |
| 2112 | 2116 | error_union_ty: Type, |
| 2113 | 2117 | maybe_inst: ?Air.Inst.Index, |
| 2114 | 2118 | ) !MCValue { |
| 2115 | const err_ty = error_union_ty.errorUnionSet(); | |
| 2116 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 2117 | if (err_ty.errorSetIsEmpty()) { | |
| 2119 | const mod = self.bin_file.options.module.?; | |
| 2120 | const err_ty = error_union_ty.errorUnionSet(mod); | |
| 2121 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 2122 | if (err_ty.errorSetIsEmpty(mod)) { | |
| 2118 | 2123 | return try error_union_bind.resolveToMcv(self); |
| 2119 | 2124 | } |
| 2120 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2125 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2121 | 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 | 2130 | switch (try error_union_bind.resolveToMcv(self)) { |
| 2126 | 2131 | .register => { |
| 2127 | 2132 | var operand_reg: Register = undefined; |
| ... | ... | @@ -2143,10 +2148,10 @@ fn errUnionPayload( |
| 2143 | 2148 | ); |
| 2144 | 2149 | |
| 2145 | 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 | 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 | 2155 | .data = .{ .rr_lsb_width = .{ |
| 2151 | 2156 | .rd = dest_reg, |
| 2152 | 2157 | .rn = operand_reg, |
| ... | ... | @@ -2174,7 +2179,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2174 | 2179 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2175 | 2180 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2176 | 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 | 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 | 2226 | |
| 2222 | 2227 | /// T to E!T |
| 2223 | 2228 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2229 | const mod = self.bin_file.options.module.?; | |
| 2224 | 2230 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2225 | 2231 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2226 | 2232 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2227 | const error_ty = error_union_ty.errorUnionSet(); | |
| 2228 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 2233 | const error_ty = error_union_ty.errorUnionSet(mod); | |
| 2234 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 2229 | 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.*)); | |
| 2233 | const abi_align = error_union_ty.abiAlignment(self.target.*); | |
| 2238 | const abi_size = @intCast(u32, error_union_ty.abiSize(mod)); | |
| 2239 | const abi_align = error_union_ty.abiAlignment(mod); | |
| 2234 | 2240 | const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst)); |
| 2235 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | |
| 2236 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | |
| 2241 | const payload_off = errUnionPayloadOffset(payload_ty, mod); | |
| 2242 | const err_off = errUnionErrorOffset(payload_ty, mod); | |
| 2237 | 2243 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); |
| 2238 | 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 | 2250 | |
| 2245 | 2251 | /// E to E!T |
| 2246 | 2252 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2253 | const mod = self.bin_file.options.module.?; | |
| 2247 | 2254 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2248 | 2255 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2249 | 2256 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2250 | const error_ty = error_union_ty.errorUnionSet(); | |
| 2251 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 2257 | const error_ty = error_union_ty.errorUnionSet(mod); | |
| 2258 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 2252 | 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.*)); | |
| 2256 | const abi_align = error_union_ty.abiAlignment(self.target.*); | |
| 2262 | const abi_size = @intCast(u32, error_union_ty.abiSize(mod)); | |
| 2263 | const abi_align = error_union_ty.abiAlignment(mod); | |
| 2257 | 2264 | const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst)); |
| 2258 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | |
| 2259 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | |
| 2265 | const payload_off = errUnionPayloadOffset(payload_ty, mod); | |
| 2266 | const err_off = errUnionErrorOffset(payload_ty, mod); | |
| 2260 | 2267 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand); |
| 2261 | 2268 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); |
| 2262 | 2269 | |
| ... | ... | @@ -2360,8 +2367,9 @@ fn ptrElemVal( |
| 2360 | 2367 | ptr_ty: Type, |
| 2361 | 2368 | maybe_inst: ?Air.Inst.Index, |
| 2362 | 2369 | ) !MCValue { |
| 2363 | const elem_ty = ptr_ty.childType(); | |
| 2364 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | |
| 2370 | const mod = self.bin_file.options.module.?; | |
| 2371 | const elem_ty = ptr_ty.childType(mod); | |
| 2372 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | |
| 2365 | 2373 | |
| 2366 | 2374 | switch (elem_size) { |
| 2367 | 2375 | 1, 4 => { |
| ... | ... | @@ -2418,11 +2426,11 @@ fn ptrElemVal( |
| 2418 | 2426 | } |
| 2419 | 2427 | |
| 2420 | 2428 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2429 | const mod = self.bin_file.options.module.?; | |
| 2421 | 2430 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2422 | const slice_ty = self.air.typeOf(bin_op.lhs); | |
| 2423 | const result: MCValue = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: { | |
| 2424 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 2425 | const ptr_ty = slice_ty.slicePtrFieldType(&buf); | |
| 2431 | const slice_ty = self.typeOf(bin_op.lhs); | |
| 2432 | const result: MCValue = if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { | |
| 2433 | const ptr_ty = slice_ty.slicePtrFieldType(mod); | |
| 2426 | 2434 | |
| 2427 | 2435 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 2428 | 2436 | const base_mcv = slicePtr(slice_mcv); |
| ... | ... | @@ -2445,8 +2453,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2445 | 2453 | const base_bind: ReadArg.Bind = .{ .mcv = base_mcv }; |
| 2446 | 2454 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2447 | 2455 | |
| 2448 | const slice_ty = self.air.typeOf(extra.lhs); | |
| 2449 | const index_ty = self.air.typeOf(extra.rhs); | |
| 2456 | const slice_ty = self.typeOf(extra.lhs); | |
| 2457 | const index_ty = self.typeOf(extra.rhs); | |
| 2450 | 2458 | |
| 2451 | 2459 | const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null); |
| 2452 | 2460 | break :result addr; |
| ... | ... | @@ -2461,7 +2469,8 @@ fn arrayElemVal( |
| 2461 | 2469 | array_ty: Type, |
| 2462 | 2470 | maybe_inst: ?Air.Inst.Index, |
| 2463 | 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 | 2475 | const mcv = try array_bind.resolveToMcv(self); |
| 2467 | 2476 | switch (mcv) { |
| ... | ... | @@ -2495,11 +2504,7 @@ fn arrayElemVal( |
| 2495 | 2504 | |
| 2496 | 2505 | const base_bind: ReadArg.Bind = .{ .mcv = ptr_to_mcv }; |
| 2497 | 2506 | |
| 2498 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 2499 | .base = .{ .tag = .single_mut_pointer }, | |
| 2500 | .data = elem_ty, | |
| 2501 | }; | |
| 2502 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 2507 | const ptr_ty = try mod.singleMutPtrType(elem_ty); | |
| 2503 | 2508 | |
| 2504 | 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 | 2517 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2513 | 2518 | const array_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 2514 | 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 | 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 | 2525 | } |
| 2521 | 2526 | |
| 2522 | 2527 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2528 | const mod = self.bin_file.options.module.?; | |
| 2523 | 2529 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2524 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 2525 | const result: MCValue = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: { | |
| 2530 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 2531 | const result: MCValue = if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { | |
| 2526 | 2532 | const base_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 2527 | 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 | 2544 | const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2539 | 2545 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2540 | 2546 | |
| 2541 | const ptr_ty = self.air.typeOf(extra.lhs); | |
| 2542 | const index_ty = self.air.typeOf(extra.rhs); | |
| 2547 | const ptr_ty = self.typeOf(extra.lhs); | |
| 2548 | const index_ty = self.typeOf(extra.rhs); | |
| 2543 | 2549 | |
| 2544 | 2550 | const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null); |
| 2545 | 2551 | break :result addr; |
| ... | ... | @@ -2646,8 +2652,9 @@ fn reuseOperand( |
| 2646 | 2652 | } |
| 2647 | 2653 | |
| 2648 | 2654 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 2649 | const elem_ty = ptr_ty.elemType(); | |
| 2650 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | |
| 2655 | const mod = self.bin_file.options.module.?; | |
| 2656 | const elem_ty = ptr_ty.childType(mod); | |
| 2657 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | |
| 2651 | 2658 | |
| 2652 | 2659 | switch (ptr) { |
| 2653 | 2660 | .none => unreachable, |
| ... | ... | @@ -2722,19 +2729,20 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2722 | 2729 | } |
| 2723 | 2730 | |
| 2724 | 2731 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2732 | const mod = self.bin_file.options.module.?; | |
| 2725 | 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 | 2735 | const result: MCValue = result: { |
| 2728 | if (!elem_ty.hasRuntimeBits()) | |
| 2736 | if (!elem_ty.hasRuntimeBits(mod)) | |
| 2729 | 2737 | break :result MCValue.none; |
| 2730 | 2738 | |
| 2731 | 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 | 2741 | if (self.liveness.isUnused(inst) and !is_volatile) |
| 2734 | 2742 | break :result MCValue.dead; |
| 2735 | 2743 | |
| 2736 | 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 | 2746 | if (ptr_fits_dest and self.reuseOperand(inst, ty_op.operand, 0, ptr)) { |
| 2739 | 2747 | // The MCValue that holds the pointer can be re-used as the value. |
| 2740 | 2748 | break :blk ptr; |
| ... | ... | @@ -2742,7 +2750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2742 | 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 | 2755 | break :result dest_mcv; |
| 2748 | 2756 | }; |
| ... | ... | @@ -2750,7 +2758,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2750 | 2758 | } |
| 2751 | 2759 | |
| 2752 | 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 | 2764 | switch (ptr) { |
| 2756 | 2765 | .none => unreachable, |
| ... | ... | @@ -2846,8 +2855,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 2846 | 2855 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2847 | 2856 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2848 | 2857 | const value = try self.resolveInst(bin_op.rhs); |
| 2849 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 2850 | const value_ty = self.air.typeOf(bin_op.rhs); | |
| 2858 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 2859 | const value_ty = self.typeOf(bin_op.rhs); | |
| 2851 | 2860 | |
| 2852 | 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 | 2878 | |
| 2870 | 2879 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 2871 | 2880 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 2881 | const mod = self.bin_file.options.module.?; | |
| 2872 | 2882 | const mcv = try self.resolveInst(operand); |
| 2873 | const ptr_ty = self.air.typeOf(operand); | |
| 2874 | const struct_ty = ptr_ty.childType(); | |
| 2875 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | |
| 2883 | const ptr_ty = self.typeOf(operand); | |
| 2884 | const struct_ty = ptr_ty.childType(mod); | |
| 2885 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); | |
| 2876 | 2886 | switch (mcv) { |
| 2877 | 2887 | .ptr_stack_offset => |off| { |
| 2878 | 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 | 2902 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 2893 | 2903 | const operand = extra.struct_operand; |
| 2894 | 2904 | const index = extra.field_index; |
| 2905 | const mod = self.bin_file.options.module.?; | |
| 2895 | 2906 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2896 | 2907 | const mcv = try self.resolveInst(operand); |
| 2897 | const struct_ty = self.air.typeOf(operand); | |
| 2898 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | |
| 2899 | const struct_field_ty = struct_ty.structFieldType(index); | |
| 2908 | const struct_ty = self.typeOf(operand); | |
| 2909 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); | |
| 2910 | const struct_field_ty = struct_ty.structFieldType(index, mod); | |
| 2900 | 2911 | |
| 2901 | 2912 | switch (mcv) { |
| 2902 | 2913 | .dead, .unreach => unreachable, |
| ... | ... | @@ -2959,10 +2970,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2959 | 2970 | ); |
| 2960 | 2971 | |
| 2961 | 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 | 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 | 2977 | .data = .{ .rr_lsb_width = .{ |
| 2967 | 2978 | .rd = dest_reg, |
| 2968 | 2979 | .rn = operand_reg, |
| ... | ... | @@ -2981,17 +2992,18 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2981 | 2992 | } |
| 2982 | 2993 | |
| 2983 | 2994 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2995 | const mod = self.bin_file.options.module.?; | |
| 2984 | 2996 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2985 | 2997 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 2986 | 2998 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2987 | 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 | 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 | 3007 | switch (field_ptr) { |
| 2996 | 3008 | .ptr_stack_offset => |off| { |
| 2997 | 3009 | break :result MCValue{ .ptr_stack_offset = off + struct_field_offset }; |
| ... | ... | @@ -3375,12 +3387,12 @@ fn addSub( |
| 3375 | 3387 | maybe_inst: ?Air.Inst.Index, |
| 3376 | 3388 | ) InnerError!MCValue { |
| 3377 | 3389 | const mod = self.bin_file.options.module.?; |
| 3378 | switch (lhs_ty.zigTypeTag()) { | |
| 3390 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3379 | 3391 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3380 | 3392 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3381 | 3393 | .Int => { |
| 3382 | 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 | 3396 | if (int_info.bits <= 32) { |
| 3385 | 3397 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 3386 | 3398 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| ... | ... | @@ -3431,12 +3443,12 @@ fn mul( |
| 3431 | 3443 | maybe_inst: ?Air.Inst.Index, |
| 3432 | 3444 | ) InnerError!MCValue { |
| 3433 | 3445 | const mod = self.bin_file.options.module.?; |
| 3434 | switch (lhs_ty.zigTypeTag()) { | |
| 3446 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3435 | 3447 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3436 | 3448 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3437 | 3449 | .Int => { |
| 3438 | 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 | 3452 | if (int_info.bits <= 32) { |
| 3441 | 3453 | // TODO add optimisations for multiplication |
| 3442 | 3454 | // with immediates, for example a * 2 can be |
| ... | ... | @@ -3463,7 +3475,8 @@ fn divFloat( |
| 3463 | 3475 | _ = rhs_ty; |
| 3464 | 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 | 3480 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3468 | 3481 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3469 | 3482 | else => unreachable, |
| ... | ... | @@ -3479,12 +3492,12 @@ fn divTrunc( |
| 3479 | 3492 | maybe_inst: ?Air.Inst.Index, |
| 3480 | 3493 | ) InnerError!MCValue { |
| 3481 | 3494 | const mod = self.bin_file.options.module.?; |
| 3482 | switch (lhs_ty.zigTypeTag()) { | |
| 3495 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3483 | 3496 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3484 | 3497 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3485 | 3498 | .Int => { |
| 3486 | 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 | 3501 | if (int_info.bits <= 32) { |
| 3489 | 3502 | switch (int_info.signedness) { |
| 3490 | 3503 | .signed => { |
| ... | ... | @@ -3522,12 +3535,12 @@ fn divFloor( |
| 3522 | 3535 | maybe_inst: ?Air.Inst.Index, |
| 3523 | 3536 | ) InnerError!MCValue { |
| 3524 | 3537 | const mod = self.bin_file.options.module.?; |
| 3525 | switch (lhs_ty.zigTypeTag()) { | |
| 3538 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3526 | 3539 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3527 | 3540 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3528 | 3541 | .Int => { |
| 3529 | 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 | 3544 | if (int_info.bits <= 32) { |
| 3532 | 3545 | switch (int_info.signedness) { |
| 3533 | 3546 | .signed => { |
| ... | ... | @@ -3569,7 +3582,8 @@ fn divExact( |
| 3569 | 3582 | _ = rhs_ty; |
| 3570 | 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 | 3587 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3574 | 3588 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3575 | 3589 | .Int => return self.fail("TODO ARM div_exact", .{}), |
| ... | ... | @@ -3586,12 +3600,12 @@ fn rem( |
| 3586 | 3600 | maybe_inst: ?Air.Inst.Index, |
| 3587 | 3601 | ) InnerError!MCValue { |
| 3588 | 3602 | const mod = self.bin_file.options.module.?; |
| 3589 | switch (lhs_ty.zigTypeTag()) { | |
| 3603 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3590 | 3604 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3591 | 3605 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3592 | 3606 | .Int => { |
| 3593 | 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 | 3609 | if (int_info.bits <= 32) { |
| 3596 | 3610 | switch (int_info.signedness) { |
| 3597 | 3611 | .signed => { |
| ... | ... | @@ -3654,7 +3668,8 @@ fn modulo( |
| 3654 | 3668 | _ = rhs_ty; |
| 3655 | 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 | 3673 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3659 | 3674 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3660 | 3675 | .Int => return self.fail("TODO ARM mod", .{}), |
| ... | ... | @@ -3671,10 +3686,11 @@ fn wrappingArithmetic( |
| 3671 | 3686 | rhs_ty: Type, |
| 3672 | 3687 | maybe_inst: ?Air.Inst.Index, |
| 3673 | 3688 | ) InnerError!MCValue { |
| 3674 | switch (lhs_ty.zigTypeTag()) { | |
| 3689 | const mod = self.bin_file.options.module.?; | |
| 3690 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3675 | 3691 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3676 | 3692 | .Int => { |
| 3677 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 3693 | const int_info = lhs_ty.intInfo(mod); | |
| 3678 | 3694 | if (int_info.bits <= 32) { |
| 3679 | 3695 | // Generate an add/sub/mul |
| 3680 | 3696 | const result: MCValue = switch (tag) { |
| ... | ... | @@ -3708,12 +3724,12 @@ fn bitwise( |
| 3708 | 3724 | rhs_ty: Type, |
| 3709 | 3725 | maybe_inst: ?Air.Inst.Index, |
| 3710 | 3726 | ) InnerError!MCValue { |
| 3711 | switch (lhs_ty.zigTypeTag()) { | |
| 3727 | const mod = self.bin_file.options.module.?; | |
| 3728 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3712 | 3729 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3713 | 3730 | .Int => { |
| 3714 | const mod = self.bin_file.options.module.?; | |
| 3715 | 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 | 3733 | if (int_info.bits <= 32) { |
| 3718 | 3734 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 3719 | 3735 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| ... | ... | @@ -3753,16 +3769,17 @@ fn shiftExact( |
| 3753 | 3769 | rhs_ty: Type, |
| 3754 | 3770 | maybe_inst: ?Air.Inst.Index, |
| 3755 | 3771 | ) InnerError!MCValue { |
| 3756 | switch (lhs_ty.zigTypeTag()) { | |
| 3772 | const mod = self.bin_file.options.module.?; | |
| 3773 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3757 | 3774 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3758 | 3775 | .Int => { |
| 3759 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 3776 | const int_info = lhs_ty.intInfo(mod); | |
| 3760 | 3777 | if (int_info.bits <= 32) { |
| 3761 | 3778 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 3762 | 3779 | |
| 3763 | 3780 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 3764 | 3781 | .shl_exact => .lsl, |
| 3765 | .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) { | |
| 3782 | .shr_exact => switch (lhs_ty.intInfo(mod).signedness) { | |
| 3766 | 3783 | .signed => Mir.Inst.Tag.asr, |
| 3767 | 3784 | .unsigned => Mir.Inst.Tag.lsr, |
| 3768 | 3785 | }, |
| ... | ... | @@ -3791,10 +3808,11 @@ fn shiftNormal( |
| 3791 | 3808 | rhs_ty: Type, |
| 3792 | 3809 | maybe_inst: ?Air.Inst.Index, |
| 3793 | 3810 | ) InnerError!MCValue { |
| 3794 | switch (lhs_ty.zigTypeTag()) { | |
| 3811 | const mod = self.bin_file.options.module.?; | |
| 3812 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3795 | 3813 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3796 | 3814 | .Int => { |
| 3797 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 3815 | const int_info = lhs_ty.intInfo(mod); | |
| 3798 | 3816 | if (int_info.bits <= 32) { |
| 3799 | 3817 | // Generate a shl_exact/shr_exact |
| 3800 | 3818 | const result: MCValue = switch (tag) { |
| ... | ... | @@ -3833,7 +3851,8 @@ fn booleanOp( |
| 3833 | 3851 | rhs_ty: Type, |
| 3834 | 3852 | maybe_inst: ?Air.Inst.Index, |
| 3835 | 3853 | ) InnerError!MCValue { |
| 3836 | switch (lhs_ty.zigTypeTag()) { | |
| 3854 | const mod = self.bin_file.options.module.?; | |
| 3855 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3837 | 3856 | .Bool => { |
| 3838 | 3857 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 3839 | 3858 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| ... | ... | @@ -3866,17 +3885,17 @@ fn ptrArithmetic( |
| 3866 | 3885 | rhs_ty: Type, |
| 3867 | 3886 | maybe_inst: ?Air.Inst.Index, |
| 3868 | 3887 | ) InnerError!MCValue { |
| 3869 | switch (lhs_ty.zigTypeTag()) { | |
| 3888 | const mod = self.bin_file.options.module.?; | |
| 3889 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3870 | 3890 | .Pointer => { |
| 3871 | const mod = self.bin_file.options.module.?; | |
| 3872 | 3891 | assert(rhs_ty.eql(Type.usize, mod)); |
| 3873 | 3892 | |
| 3874 | 3893 | const ptr_ty = lhs_ty; |
| 3875 | const elem_ty = switch (ptr_ty.ptrSize()) { | |
| 3876 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | |
| 3877 | else => ptr_ty.childType(), | |
| 3894 | const elem_ty = switch (ptr_ty.ptrSize(mod)) { | |
| 3895 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type | |
| 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 | 3900 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 3882 | 3901 | .ptr_add => .add, |
| ... | ... | @@ -3903,11 +3922,12 @@ fn ptrArithmetic( |
| 3903 | 3922 | } |
| 3904 | 3923 | |
| 3905 | 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 | 3928 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3909 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb, | |
| 3910 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh, | |
| 3929 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb else .ldrb, | |
| 3930 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh else .ldrh, | |
| 3911 | 3931 | 3, 4 => .ldr, |
| 3912 | 3932 | else => unreachable, |
| 3913 | 3933 | }; |
| ... | ... | @@ -3924,7 +3944,7 @@ fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) |
| 3924 | 3944 | } }; |
| 3925 | 3945 | |
| 3926 | 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 | 3948 | 2 => rr_extra_offset, |
| 3929 | 3949 | 3, 4 => rr_offset, |
| 3930 | 3950 | else => unreachable, |
| ... | ... | @@ -3937,7 +3957,8 @@ fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) |
| 3937 | 3957 | } |
| 3938 | 3958 | |
| 3939 | 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 | 3963 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3943 | 3964 | 1 => .strb, |
| ... | ... | @@ -4051,14 +4072,14 @@ fn genInlineMemset( |
| 4051 | 4072 | ) !void { |
| 4052 | 4073 | const dst_reg = switch (dst) { |
| 4053 | 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 | 4077 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 4057 | 4078 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 4058 | 4079 | |
| 4059 | 4080 | const val_reg = switch (val) { |
| 4060 | 4081 | .register => |r| r, |
| 4061 | else => try self.copyToTmpRegister(Type.initTag(.u8), val), | |
| 4082 | else => try self.copyToTmpRegister(Type.u8, val), | |
| 4062 | 4083 | }; |
| 4063 | 4084 | const val_reg_lock = self.register_manager.lockReg(val_reg); |
| 4064 | 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 | 4164 | while (self.args[arg_index] == .none) arg_index += 1; |
| 4144 | 4165 | self.arg_index = arg_index + 1; |
| 4145 | 4166 | |
| 4146 | const ty = self.air.typeOfIndex(inst); | |
| 4167 | const ty = self.typeOfIndex(inst); | |
| 4147 | 4168 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4148 | 4169 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 4149 | 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 | 4217 | const callee = pl_op.operand; |
| 4197 | 4218 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 4198 | 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 | 4224 | .Fn => ty, |
| 4203 | .Pointer => ty.childType(), | |
| 4225 | .Pointer => ty.childType(mod), | |
| 4204 | 4226 | else => unreachable, |
| 4205 | 4227 | }; |
| 4206 | 4228 | |
| ... | ... | @@ -4225,16 +4247,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4225 | 4247 | // untouched by the parameter passing code |
| 4226 | 4248 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { |
| 4227 | 4249 | log.debug("airCall: return by reference", .{}); |
| 4228 | const ret_ty = fn_ty.fnReturnType(); | |
| 4229 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | |
| 4230 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); | |
| 4250 | const ret_ty = fn_ty.fnReturnType(mod); | |
| 4251 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(mod)); | |
| 4252 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(mod)); | |
| 4231 | 4253 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4232 | 4254 | |
| 4233 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 4234 | .base = .{ .tag = .single_mut_pointer }, | |
| 4235 | .data = ret_ty, | |
| 4236 | }; | |
| 4237 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 4255 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | |
| 4238 | 4256 | try self.register_manager.getReg(.r0, null); |
| 4239 | 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 | 4267 | |
| 4250 | 4268 | for (info.args, 0..) |mc_arg, arg_i| { |
| 4251 | 4269 | const arg = args[arg_i]; |
| 4252 | const arg_ty = self.air.typeOf(arg); | |
| 4270 | const arg_ty = self.typeOf(arg); | |
| 4253 | 4271 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 4254 | 4272 | |
| 4255 | 4273 | switch (mc_arg) { |
| ... | ... | @@ -4270,16 +4288,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4270 | 4288 | |
| 4271 | 4289 | // Due to incremental compilation, how function calls are generated depends |
| 4272 | 4290 | // on linking. |
| 4273 | if (self.air.value(callee)) |func_value| { | |
| 4274 | if (func_value.castTag(.function)) |func_payload| { | |
| 4275 | const func = func_payload.data; | |
| 4276 | ||
| 4291 | if (try self.air.value(callee, mod)) |func_value| { | |
| 4292 | if (func_value.getFunction(mod)) |func| { | |
| 4277 | 4293 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4278 | 4294 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4279 | 4295 | const atom = elf_file.getAtom(atom_index); |
| 4280 | 4296 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 4281 | 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 | 4299 | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 4284 | 4300 | unreachable; // unsupported architecture for MachO |
| 4285 | 4301 | } else { |
| ... | ... | @@ -4288,16 +4304,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4288 | 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 | 4308 | return self.fail("TODO implement calling extern functions", .{}); |
| 4293 | 4309 | } else { |
| 4294 | 4310 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 4295 | 4311 | } |
| 4296 | 4312 | } else { |
| 4297 | assert(ty.zigTypeTag() == .Pointer); | |
| 4313 | assert(ty.zigTypeTag(mod) == .Pointer); | |
| 4298 | 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 | 4319 | // TODO: add Instruction.supportedOn |
| ... | ... | @@ -4329,7 +4345,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4329 | 4345 | if (RegisterManager.indexOfRegIntoTracked(reg) == null) { |
| 4330 | 4346 | // Save function return value into a tracked register |
| 4331 | 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 | 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 | 4369 | } |
| 4354 | 4370 | |
| 4355 | 4371 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4372 | const mod = self.bin_file.options.module.?; | |
| 4356 | 4373 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4357 | 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 | 4377 | switch (self.ret_mcv) { |
| 4361 | 4378 | .none => {}, |
| 4362 | 4379 | .immediate => { |
| 4363 | assert(ret_ty.isError()); | |
| 4380 | assert(ret_ty.isError(mod)); | |
| 4364 | 4381 | }, |
| 4365 | 4382 | .register => |reg| { |
| 4366 | 4383 | // Return result by value |
| ... | ... | @@ -4371,11 +4388,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4371 | 4388 | // |
| 4372 | 4389 | // self.ret_mcv is an address to where this function |
| 4373 | 4390 | // should store its result into |
| 4374 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 4375 | .base = .{ .tag = .single_mut_pointer }, | |
| 4376 | .data = ret_ty, | |
| 4377 | }; | |
| 4378 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 4391 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | |
| 4379 | 4392 | try self.store(self.ret_mcv, operand, ptr_ty, ret_ty); |
| 4380 | 4393 | }, |
| 4381 | 4394 | else => unreachable, // invalid return result |
| ... | ... | @@ -4388,10 +4401,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4388 | 4401 | } |
| 4389 | 4402 | |
| 4390 | 4403 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4404 | const mod = self.bin_file.options.module.?; | |
| 4391 | 4405 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4392 | 4406 | const ptr = try self.resolveInst(un_op); |
| 4393 | const ptr_ty = self.air.typeOf(un_op); | |
| 4394 | const ret_ty = self.fn_type.fnReturnType(); | |
| 4407 | const ptr_ty = self.typeOf(un_op); | |
| 4408 | const ret_ty = self.fn_type.fnReturnType(mod); | |
| 4395 | 4409 | |
| 4396 | 4410 | switch (self.ret_mcv) { |
| 4397 | 4411 | .none => {}, |
| ... | ... | @@ -4411,8 +4425,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4411 | 4425 | // location. |
| 4412 | 4426 | const op_inst = Air.refToIndex(un_op).?; |
| 4413 | 4427 | if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) { |
| 4414 | const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | |
| 4415 | const abi_align = ret_ty.abiAlignment(self.target.*); | |
| 4428 | const abi_size = @intCast(u32, ret_ty.abiSize(mod)); | |
| 4429 | const abi_align = ret_ty.abiAlignment(mod); | |
| 4416 | 4430 | |
| 4417 | 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 | 4446 | |
| 4433 | 4447 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4434 | 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 | 4451 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 4438 | 4452 | break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op); |
| ... | ... | @@ -4448,29 +4462,28 @@ fn cmp( |
| 4448 | 4462 | lhs_ty: Type, |
| 4449 | 4463 | op: math.CompareOperator, |
| 4450 | 4464 | ) !MCValue { |
| 4451 | var int_buffer: Type.Payload.Bits = undefined; | |
| 4452 | const int_ty = switch (lhs_ty.zigTypeTag()) { | |
| 4465 | const mod = self.bin_file.options.module.?; | |
| 4466 | const int_ty = switch (lhs_ty.zigTypeTag(mod)) { | |
| 4453 | 4467 | .Optional => blk: { |
| 4454 | var opt_buffer: Type.Payload.ElemType = undefined; | |
| 4455 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); | |
| 4456 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4457 | break :blk Type.initTag(.u1); | |
| 4458 | } else if (lhs_ty.isPtrLikeOptional()) { | |
| 4468 | const payload_ty = lhs_ty.optionalChild(mod); | |
| 4469 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4470 | break :blk Type.u1; | |
| 4471 | } else if (lhs_ty.isPtrLikeOptional(mod)) { | |
| 4459 | 4472 | break :blk Type.usize; |
| 4460 | 4473 | } else { |
| 4461 | 4474 | return self.fail("TODO ARM cmp non-pointer optionals", .{}); |
| 4462 | 4475 | } |
| 4463 | 4476 | }, |
| 4464 | 4477 | .Float => return self.fail("TODO ARM cmp floats", .{}), |
| 4465 | .Enum => lhs_ty.intTagType(&int_buffer), | |
| 4478 | .Enum => lhs_ty.intTagType(mod), | |
| 4466 | 4479 | .Int => lhs_ty, |
| 4467 | .Bool => Type.initTag(.u1), | |
| 4480 | .Bool => Type.u1, | |
| 4468 | 4481 | .Pointer => Type.usize, |
| 4469 | .ErrorSet => Type.initTag(.u16), | |
| 4482 | .ErrorSet => Type.u16, | |
| 4470 | 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 | 4487 | if (int_info.bits <= 32) { |
| 4475 | 4488 | try self.spillCompareFlagsIfOccupied(); |
| 4476 | 4489 | |
| ... | ... | @@ -4555,8 +4568,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 4555 | 4568 | } |
| 4556 | 4569 | |
| 4557 | 4570 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 4558 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 4559 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 4571 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; | |
| 4572 | const mod = self.bin_file.options.module.?; | |
| 4573 | const function = mod.funcPtr(ty_fn.func); | |
| 4560 | 4574 | // TODO emit debug info for function change |
| 4561 | 4575 | _ = function; |
| 4562 | 4576 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | ... | @@ -4571,7 +4585,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4571 | 4585 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4572 | 4586 | const operand = pl_op.operand; |
| 4573 | 4587 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4574 | const ty = self.air.typeOf(operand); | |
| 4588 | const ty = self.typeOf(operand); | |
| 4575 | 4589 | const mcv = try self.resolveInst(operand); |
| 4576 | 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 | 4650 | // whether it needs to be spilled in the branches |
| 4637 | 4651 | if (self.liveness.operandDies(inst, 0)) { |
| 4638 | 4652 | const op_int = @enumToInt(pl_op.operand); |
| 4639 | if (op_int >= Air.Inst.Ref.typed_value_map.len) { | |
| 4640 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 4653 | if (op_int >= Air.ref_start_index) { | |
| 4654 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); | |
| 4641 | 4655 | self.processDeath(op_index); |
| 4642 | 4656 | } |
| 4643 | 4657 | } |
| ... | ... | @@ -4726,7 +4740,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4726 | 4740 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); |
| 4727 | 4741 | // TODO make sure the destination stack offset / register does not already have something |
| 4728 | 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 | 4744 | // TODO track the new register / stack allocation |
| 4731 | 4745 | } |
| 4732 | 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 | 4767 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); |
| 4754 | 4768 | // TODO make sure the destination stack offset / register does not already have something |
| 4755 | 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 | 4771 | // TODO track the new register / stack allocation |
| 4758 | 4772 | } |
| 4759 | 4773 | |
| ... | ... | @@ -4772,8 +4786,9 @@ fn isNull( |
| 4772 | 4786 | operand_bind: ReadArg.Bind, |
| 4773 | 4787 | operand_ty: Type, |
| 4774 | 4788 | ) !MCValue { |
| 4775 | if (operand_ty.isPtrLikeOptional()) { | |
| 4776 | assert(operand_ty.abiSize(self.target.*) == 4); | |
| 4789 | const mod = self.bin_file.options.module.?; | |
| 4790 | if (operand_ty.isPtrLikeOptional(mod)) { | |
| 4791 | assert(operand_ty.abiSize(mod) == 4); | |
| 4777 | 4792 | |
| 4778 | 4793 | const imm_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 0 } }; |
| 4779 | 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 | 4812 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4798 | 4813 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4799 | 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 | 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 | 4820 | } |
| 4806 | 4821 | |
| 4807 | 4822 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4823 | const mod = self.bin_file.options.module.?; | |
| 4808 | 4824 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4809 | 4825 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4810 | 4826 | const operand_ptr = try self.resolveInst(un_op); |
| 4811 | const ptr_ty = self.air.typeOf(un_op); | |
| 4812 | const elem_ty = ptr_ty.elemType(); | |
| 4827 | const ptr_ty = self.typeOf(un_op); | |
| 4828 | const elem_ty = ptr_ty.childType(mod); | |
| 4813 | 4829 | |
| 4814 | 4830 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4815 | 4831 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | ... | @@ -4823,7 +4839,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4823 | 4839 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4824 | 4840 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4825 | 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 | 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 | 4847 | } |
| 4832 | 4848 | |
| 4833 | 4849 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4850 | const mod = self.bin_file.options.module.?; | |
| 4834 | 4851 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4835 | 4852 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4836 | 4853 | const operand_ptr = try self.resolveInst(un_op); |
| 4837 | const ptr_ty = self.air.typeOf(un_op); | |
| 4838 | const elem_ty = ptr_ty.elemType(); | |
| 4854 | const ptr_ty = self.typeOf(un_op); | |
| 4855 | const elem_ty = ptr_ty.childType(mod); | |
| 4839 | 4856 | |
| 4840 | 4857 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4841 | 4858 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | ... | @@ -4850,9 +4867,10 @@ fn isErr( |
| 4850 | 4867 | error_union_bind: ReadArg.Bind, |
| 4851 | 4868 | error_union_ty: Type, |
| 4852 | 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 | 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 | 4901 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4884 | 4902 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4885 | 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 | 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 | 4909 | } |
| 4892 | 4910 | |
| 4893 | 4911 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4912 | const mod = self.bin_file.options.module.?; | |
| 4894 | 4913 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4895 | 4914 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4896 | 4915 | const operand_ptr = try self.resolveInst(un_op); |
| 4897 | const ptr_ty = self.air.typeOf(un_op); | |
| 4898 | const elem_ty = ptr_ty.elemType(); | |
| 4916 | const ptr_ty = self.typeOf(un_op); | |
| 4917 | const elem_ty = ptr_ty.childType(mod); | |
| 4899 | 4918 | |
| 4900 | 4919 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4901 | 4920 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | ... | @@ -4909,7 +4928,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4909 | 4928 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4910 | 4929 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4911 | 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 | 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 | 4936 | } |
| 4918 | 4937 | |
| 4919 | 4938 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4939 | const mod = self.bin_file.options.module.?; | |
| 4920 | 4940 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4921 | 4941 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4922 | 4942 | const operand_ptr = try self.resolveInst(un_op); |
| 4923 | const ptr_ty = self.air.typeOf(un_op); | |
| 4924 | const elem_ty = ptr_ty.elemType(); | |
| 4943 | const ptr_ty = self.typeOf(un_op); | |
| 4944 | const elem_ty = ptr_ty.childType(mod); | |
| 4925 | 4945 | |
| 4926 | 4946 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4927 | 4947 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | ... | @@ -4988,7 +5008,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 4988 | 5008 | |
| 4989 | 5009 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4990 | 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 | 5012 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 4993 | 5013 | const liveness = try self.liveness.getSwitchBr( |
| 4994 | 5014 | self.gpa, |
| ... | ... | @@ -5131,9 +5151,10 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 5131 | 5151 | } |
| 5132 | 5152 | |
| 5133 | 5153 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5154 | const mod = self.bin_file.options.module.?; | |
| 5134 | 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 | 5158 | const operand_mcv = try self.resolveInst(operand); |
| 5138 | 5159 | const block_mcv = block_data.mcv; |
| 5139 | 5160 | if (block_mcv == .none) { |
| ... | ... | @@ -5141,14 +5162,14 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5141 | 5162 | .none, .dead, .unreach => unreachable, |
| 5142 | 5163 | .register, .stack_offset, .memory => operand_mcv, |
| 5143 | 5164 | .immediate, .stack_argument_offset, .cpsr_flags => blk: { |
| 5144 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); | |
| 5145 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | |
| 5165 | const new_mcv = try self.allocRegOrMem(self.typeOfIndex(block), true, block); | |
| 5166 | try self.setRegOrMem(self.typeOfIndex(block), new_mcv, operand_mcv); | |
| 5146 | 5167 | break :blk new_mcv; |
| 5147 | 5168 | }, |
| 5148 | 5169 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), |
| 5149 | 5170 | }; |
| 5150 | 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 | 5175 | return self.brVoid(block); |
| ... | ... | @@ -5212,7 +5233,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 5212 | 5233 | |
| 5213 | 5234 | const arg_mcv = try self.resolveInst(input); |
| 5214 | 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 | 5322 | } |
| 5302 | 5323 | |
| 5303 | 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 | 5327 | switch (mcv) { |
| 5306 | 5328 | .dead => unreachable, |
| 5307 | 5329 | .unreach, .none => return, // Nothing to do. |
| ... | ... | @@ -5332,7 +5354,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5332 | 5354 | 1, 4 => { |
| 5333 | 5355 | const offset = if (math.cast(u12, stack_offset)) |imm| blk: { |
| 5334 | 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 | 5359 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5338 | 5360 | 1 => .strb, |
| ... | ... | @@ -5355,7 +5377,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5355 | 5377 | 2 => { |
| 5356 | 5378 | const offset = if (stack_offset <= math.maxInt(u8)) blk: { |
| 5357 | 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 | 5382 | _ = try self.addInst(.{ |
| 5361 | 5383 | .tag = .strh, |
| ... | ... | @@ -5378,11 +5400,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5378 | 5400 | const reg_lock = self.register_manager.lockReg(reg); |
| 5379 | 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 | 5404 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }); |
| 5383 | 5405 | |
| 5384 | const overflow_bit_ty = ty.structFieldType(1); | |
| 5385 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*)); | |
| 5406 | const overflow_bit_ty = ty.structFieldType(1, mod); | |
| 5407 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, mod)); | |
| 5386 | 5408 | const cond_reg = try self.register_manager.allocReg(null, gp); |
| 5387 | 5409 | |
| 5388 | 5410 | // C flag: movcs reg, #1 |
| ... | ... | @@ -5420,11 +5442,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5420 | 5442 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5421 | 5443 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 5422 | 5444 | } else { |
| 5423 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 5424 | .base = .{ .tag = .single_mut_pointer }, | |
| 5425 | .data = ty, | |
| 5426 | }; | |
| 5427 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 5445 | const ptr_ty = try mod.singleMutPtrType(ty); | |
| 5428 | 5446 | |
| 5429 | 5447 | // TODO call extern memcpy |
| 5430 | 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 | 5484 | } |
| 5467 | 5485 | |
| 5468 | 5486 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 5487 | const mod = self.bin_file.options.module.?; | |
| 5469 | 5488 | switch (mcv) { |
| 5470 | 5489 | .dead => unreachable, |
| 5471 | 5490 | .unreach, .none => return, // Nothing to do. |
| ... | ... | @@ -5640,17 +5659,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5640 | 5659 | }, |
| 5641 | 5660 | .stack_offset => |off| { |
| 5642 | 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 | 5664 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5646 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb, | |
| 5647 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh, | |
| 5665 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb else .ldrb, | |
| 5666 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh else .ldrh, | |
| 5648 | 5667 | 3, 4 => .ldr, |
| 5649 | 5668 | else => unreachable, |
| 5650 | 5669 | }; |
| 5651 | 5670 | |
| 5652 | 5671 | const extra_offset = switch (abi_size) { |
| 5653 | 1 => ty.isSignedInt(), | |
| 5672 | 1 => ty.isSignedInt(mod), | |
| 5654 | 5673 | 2 => true, |
| 5655 | 5674 | 3, 4 => false, |
| 5656 | 5675 | else => unreachable, |
| ... | ... | @@ -5659,7 +5678,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5659 | 5678 | if (extra_offset) { |
| 5660 | 5679 | const offset = if (off <= math.maxInt(u8)) blk: { |
| 5661 | 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 | 5683 | _ = try self.addInst(.{ |
| 5665 | 5684 | .tag = tag, |
| ... | ... | @@ -5675,7 +5694,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5675 | 5694 | } else { |
| 5676 | 5695 | const offset = if (off <= math.maxInt(u12)) blk: { |
| 5677 | 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 | 5699 | _ = try self.addInst(.{ |
| 5681 | 5700 | .tag = tag, |
| ... | ... | @@ -5691,11 +5710,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5691 | 5710 | } |
| 5692 | 5711 | }, |
| 5693 | 5712 | .stack_argument_offset => |off| { |
| 5694 | const abi_size = ty.abiSize(self.target.*); | |
| 5713 | const abi_size = ty.abiSize(mod); | |
| 5695 | 5714 | |
| 5696 | 5715 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5697 | 1 => if (ty.isSignedInt()) 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, | |
| 5716 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument, | |
| 5717 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument, | |
| 5699 | 5718 | 3, 4 => .ldr_stack_argument, |
| 5700 | 5719 | else => unreachable, |
| 5701 | 5720 | }; |
| ... | ... | @@ -5712,7 +5731,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5712 | 5731 | } |
| 5713 | 5732 | |
| 5714 | 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 | 5736 | switch (mcv) { |
| 5717 | 5737 | .dead => unreachable, |
| 5718 | 5738 | .none, .unreach => return, |
| ... | ... | @@ -5732,7 +5752,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5732 | 5752 | 1, 4 => { |
| 5733 | 5753 | const offset = if (math.cast(u12, stack_offset)) |imm| blk: { |
| 5734 | 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 | 5757 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5738 | 5758 | 1 => .strb, |
| ... | ... | @@ -5752,7 +5772,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5752 | 5772 | 2 => { |
| 5753 | 5773 | const offset = if (stack_offset <= math.maxInt(u8)) blk: { |
| 5754 | 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 | 5777 | _ = try self.addInst(.{ |
| 5758 | 5778 | .tag = .strh, |
| ... | ... | @@ -5779,11 +5799,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5779 | 5799 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5780 | 5800 | return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg }); |
| 5781 | 5801 | } else { |
| 5782 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 5783 | .base = .{ .tag = .single_mut_pointer }, | |
| 5784 | .data = ty, | |
| 5785 | }; | |
| 5786 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 5802 | const ptr_ty = try mod.singleMutPtrType(ty); | |
| 5787 | 5803 | |
| 5788 | 5804 | // TODO call extern memcpy |
| 5789 | 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 | 5878 | }; |
| 5863 | 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 | 5882 | const dest = try self.allocRegOrMem(dest_ty, true, inst); |
| 5867 | 5883 | try self.setRegOrMem(dest_ty, dest, operand); |
| 5868 | 5884 | break :result dest; |
| ... | ... | @@ -5871,16 +5887,17 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 5871 | 5887 | } |
| 5872 | 5888 | |
| 5873 | 5889 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5890 | const mod = self.bin_file.options.module.?; | |
| 5874 | 5891 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5875 | 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 | 5894 | const ptr = try self.resolveInst(ty_op.operand); |
| 5878 | const array_ty = ptr_ty.childType(); | |
| 5879 | const array_len = @intCast(u32, array_ty.arrayLen()); | |
| 5895 | const array_ty = ptr_ty.childType(mod); | |
| 5896 | const array_len = @intCast(u32, array_ty.arrayLen(mod)); | |
| 5880 | 5897 | |
| 5881 | 5898 | const stack_offset = try self.allocMem(8, 8, inst); |
| 5882 | 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 | 5901 | break :result MCValue{ .stack_offset = stack_offset }; |
| 5885 | 5902 | }; |
| 5886 | 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 | 6006 | } |
| 5990 | 6007 | |
| 5991 | 6008 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 5992 | const vector_ty = self.air.typeOfIndex(inst); | |
| 5993 | const len = vector_ty.vectorLen(); | |
| 6009 | const mod = self.bin_file.options.module.?; | |
| 6010 | const vector_ty = self.typeOfIndex(inst); | |
| 6011 | const len = vector_ty.vectorLen(mod); | |
| 5994 | 6012 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5995 | 6013 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 5996 | 6014 | const result: MCValue = res: { |
| ... | ... | @@ -6038,9 +6056,10 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 6038 | 6056 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 6039 | 6057 | const result: MCValue = result: { |
| 6040 | 6058 | const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; |
| 6041 | const error_union_ty = self.air.typeOf(pl_op.operand); | |
| 6042 | const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | |
| 6043 | const error_union_align = error_union_ty.abiAlignment(self.target.*); | |
| 6059 | const error_union_ty = self.typeOf(pl_op.operand); | |
| 6060 | const mod = self.bin_file.options.module.?; | |
| 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 | 6064 | // The error union will die in the body. However, we need the |
| 6046 | 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 | 6088 | } |
| 6070 | 6089 | |
| 6071 | 6090 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 6072 | // First section of indexes correspond to a set number of constant values. | |
| 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 | } | |
| 6091 | const mod = self.bin_file.options.module.?; | |
| 6081 | 6092 | |
| 6082 | 6093 | // If the type has no codegen bits, no need to store it. |
| 6083 | const inst_ty = self.air.typeOf(inst); | |
| 6084 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) | |
| 6094 | const inst_ty = self.typeOf(inst); | |
| 6095 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod) and !inst_ty.isError(mod)) | |
| 6085 | 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 | 6103 | switch (self.air.instructions.items(.tag)[inst_index]) { |
| 6089 | .constant => { | |
| 6104 | .interned => { | |
| 6090 | 6105 | // Constants have static lifetimes, so they are always memoized in the outer most table. |
| 6091 | 6106 | const branch = &self.branch_stack.items[0]; |
| 6092 | 6107 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); |
| 6093 | 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 | 6110 | gop.value_ptr.* = try self.genTypedValue(.{ |
| 6096 | 6111 | .ty = inst_ty, |
| 6097 | .val = self.air.values[ty_pl.payload], | |
| 6112 | .val = interned.toValue(), | |
| 6098 | 6113 | }); |
| 6099 | 6114 | } |
| 6100 | 6115 | return gop.value_ptr.*; |
| 6101 | 6116 | }, |
| 6102 | .const_ty => unreachable, | |
| 6103 | 6117 | else => return self.getResolvedInstValue(inst_index), |
| 6104 | 6118 | } |
| 6105 | 6119 | } |
| ... | ... | @@ -6152,12 +6166,11 @@ const CallMCValues = struct { |
| 6152 | 6166 | |
| 6153 | 6167 | /// Caller must call `CallMCValues.deinit`. |
| 6154 | 6168 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6155 | const cc = fn_ty.fnCallingConvention(); | |
| 6156 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | |
| 6157 | defer self.gpa.free(param_types); | |
| 6158 | fn_ty.fnParamTypes(param_types); | |
| 6169 | const mod = self.bin_file.options.module.?; | |
| 6170 | const fn_info = mod.typeToFunc(fn_ty).?; | |
| 6171 | const cc = fn_info.cc; | |
| 6159 | 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 | 6174 | // These undefined values must be populated before returning from this function. |
| 6162 | 6175 | .return_value = undefined, |
| 6163 | 6176 | .stack_byte_count = undefined, |
| ... | ... | @@ -6165,7 +6178,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6165 | 6178 | }; |
| 6166 | 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 | 6183 | switch (cc) { |
| 6171 | 6184 | .Naked => { |
| ... | ... | @@ -6180,12 +6193,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6180 | 6193 | var ncrn: usize = 0; // Next Core Register Number |
| 6181 | 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 | 6197 | result.return_value = .{ .unreach = {} }; |
| 6185 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6198 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6186 | 6199 | result.return_value = .{ .none = {} }; |
| 6187 | 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 | 6202 | // TODO handle cases where multiple registers are used |
| 6190 | 6203 | if (ret_ty_size <= 4) { |
| 6191 | 6204 | result.return_value = .{ .register = c_abi_int_return_regs[0] }; |
| ... | ... | @@ -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| { | |
| 6203 | if (ty.abiAlignment(self.target.*) == 8) | |
| 6215 | for (fn_info.param_types, 0..) |ty, i| { | |
| 6216 | if (ty.toType().abiAlignment(mod) == 8) | |
| 6204 | 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 | 6220 | if (std.math.divCeil(u32, param_size, 4) catch unreachable <= 4 - ncrn) { |
| 6208 | 6221 | if (param_size <= 4) { |
| 6209 | 6222 | result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] }; |
| ... | ... | @@ -6215,7 +6228,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6215 | 6228 | return self.fail("TODO MCValues split between registers and stack", .{}); |
| 6216 | 6229 | } else { |
| 6217 | 6230 | ncrn = 4; |
| 6218 | if (ty.abiAlignment(self.target.*) == 8) | |
| 6231 | if (ty.toType().abiAlignment(mod) == 8) | |
| 6219 | 6232 | nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8); |
| 6220 | 6233 | |
| 6221 | 6234 | result.args[i] = .{ .stack_argument_offset = nsaa }; |
| ... | ... | @@ -6227,14 +6240,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6227 | 6240 | result.stack_align = 8; |
| 6228 | 6241 | }, |
| 6229 | 6242 | .Unspecified => { |
| 6230 | if (ret_ty.zigTypeTag() == .NoReturn) { | |
| 6243 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { | |
| 6231 | 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 | 6246 | result.return_value = .{ .none = {} }; |
| 6234 | 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 | 6249 | if (ret_ty_size == 0) { |
| 6237 | assert(ret_ty.isError()); | |
| 6250 | assert(ret_ty.isError(mod)); | |
| 6238 | 6251 | result.return_value = .{ .immediate = 0 }; |
| 6239 | 6252 | } else if (ret_ty_size <= 4) { |
| 6240 | 6253 | result.return_value = .{ .register = .r0 }; |
| ... | ... | @@ -6249,10 +6262,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6249 | 6262 | |
| 6250 | 6263 | var stack_offset: u32 = 0; |
| 6251 | 6264 | |
| 6252 | for (param_types, 0..) |ty, i| { | |
| 6253 | if (ty.abiSize(self.target.*) > 0) { | |
| 6254 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | |
| 6255 | const param_alignment = ty.abiAlignment(self.target.*); | |
| 6265 | for (fn_info.param_types, 0..) |ty, i| { | |
| 6266 | if (ty.toType().abiSize(mod) > 0) { | |
| 6267 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); | |
| 6268 | const param_alignment = ty.toType().abiAlignment(mod); | |
| 6256 | 6269 | |
| 6257 | 6270 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); |
| 6258 | 6271 | result.args[i] = .{ .stack_argument_offset = stack_offset }; |
| ... | ... | @@ -6301,3 +6314,13 @@ fn parseRegName(name: []const u8) ?Register { |
| 6301 | 6314 | } |
| 6302 | 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 | 1 | const std = @import("std"); |
| 2 | const assert = std.debug.assert; | |
| 2 | 3 | const bits = @import("bits.zig"); |
| 3 | 4 | const Register = bits.Register; |
| 4 | 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 5 | 6 | const Type = @import("../../type.zig").Type; |
| 7 | const Module = @import("../../Module.zig"); | |
| 6 | 8 | |
| 7 | 9 | pub const Class = union(enum) { |
| 8 | 10 | memory, |
| ... | ... | @@ -22,28 +24,28 @@ pub const Class = union(enum) { |
| 22 | 24 | |
| 23 | 25 | pub const Context = enum { ret, arg }; |
| 24 | 26 | |
| 25 | pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { | |
| 26 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime()); | |
| 27 | pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { | |
| 28 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); | |
| 27 | 29 | |
| 28 | 30 | var maybe_float_bits: ?u16 = null; |
| 29 | 31 | const max_byval_size = 512; |
| 30 | switch (ty.zigTypeTag()) { | |
| 32 | switch (ty.zigTypeTag(mod)) { | |
| 31 | 33 | .Struct => { |
| 32 | const bit_size = ty.bitSize(target); | |
| 33 | if (ty.containerLayout() == .Packed) { | |
| 34 | const bit_size = ty.bitSize(mod); | |
| 35 | if (ty.containerLayout(mod) == .Packed) { | |
| 34 | 36 | if (bit_size > 64) return .memory; |
| 35 | 37 | return .byval; |
| 36 | 38 | } |
| 37 | 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 | 41 | if (float_count <= byval_float_count) return .byval; |
| 40 | 42 | |
| 41 | const fields = ty.structFieldCount(); | |
| 43 | const fields = ty.structFieldCount(mod); | |
| 42 | 44 | var i: u32 = 0; |
| 43 | 45 | while (i < fields) : (i += 1) { |
| 44 | const field_ty = ty.structFieldType(i); | |
| 45 | const field_alignment = ty.structFieldAlign(i, target); | |
| 46 | const field_size = field_ty.bitSize(target); | |
| 46 | const field_ty = ty.structFieldType(i, mod); | |
| 47 | const field_alignment = ty.structFieldAlign(i, mod); | |
| 48 | const field_size = field_ty.bitSize(mod); | |
| 47 | 49 | if (field_size > 32 or field_alignment > 32) { |
| 48 | 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 | 53 | return Class.arrSize(bit_size, 32); |
| 52 | 54 | }, |
| 53 | 55 | .Union => { |
| 54 | const bit_size = ty.bitSize(target); | |
| 55 | if (ty.containerLayout() == .Packed) { | |
| 56 | const bit_size = ty.bitSize(mod); | |
| 57 | if (ty.containerLayout(mod) == .Packed) { | |
| 56 | 58 | if (bit_size > 64) return .memory; |
| 57 | 59 | return .byval; |
| 58 | 60 | } |
| 59 | 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 | 63 | if (float_count <= byval_float_count) return .byval; |
| 62 | 64 | |
| 63 | for (ty.unionFields().values()) |field| { | |
| 64 | if (field.ty.bitSize(target) > 32 or field.normalAlignment(target) > 32) { | |
| 65 | for (ty.unionFields(mod).values()) |field| { | |
| 66 | if (field.ty.bitSize(mod) > 32 or field.normalAlignment(mod) > 32) { | |
| 65 | 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 | 73 | .Int => { |
| 72 | 74 | // TODO this is incorrect for _BitInt(128) but implementing |
| 73 | 75 | // this correctly makes implementing compiler-rt impossible. |
| 74 | // const bit_size = ty.bitSize(target); | |
| 76 | // const bit_size = ty.bitSize(mod); | |
| 75 | 77 | // if (bit_size > 64) return .memory; |
| 76 | 78 | return .byval; |
| 77 | 79 | }, |
| 78 | 80 | .Enum, .ErrorSet => { |
| 79 | const bit_size = ty.bitSize(target); | |
| 81 | const bit_size = ty.bitSize(mod); | |
| 80 | 82 | if (bit_size > 64) return .memory; |
| 81 | 83 | return .byval; |
| 82 | 84 | }, |
| 83 | 85 | .Vector => { |
| 84 | const bit_size = ty.bitSize(target); | |
| 86 | const bit_size = ty.bitSize(mod); | |
| 85 | 87 | // TODO is this controlled by a cpu feature? |
| 86 | 88 | if (ctx == .ret and bit_size > 128) return .memory; |
| 87 | 89 | if (bit_size > 512) return .memory; |
| 88 | 90 | return .byval; |
| 89 | 91 | }, |
| 90 | 92 | .Optional => { |
| 91 | std.debug.assert(ty.isPtrLikeOptional()); | |
| 93 | assert(ty.isPtrLikeOptional(mod)); | |
| 92 | 94 | return .byval; |
| 93 | 95 | }, |
| 94 | 96 | .Pointer => { |
| 95 | std.debug.assert(!ty.isSlice()); | |
| 97 | assert(!ty.isSlice(mod)); | |
| 96 | 98 | return .byval; |
| 97 | 99 | }, |
| 98 | 100 | .ErrorUnion, |
| ... | ... | @@ -114,14 +116,15 @@ pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { |
| 114 | 116 | } |
| 115 | 117 | |
| 116 | 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 | 121 | const invalid = std.math.maxInt(u32); |
| 119 | switch (ty.zigTypeTag()) { | |
| 122 | switch (ty.zigTypeTag(mod)) { | |
| 120 | 123 | .Union => { |
| 121 | const fields = ty.unionFields(); | |
| 124 | const fields = ty.unionFields(mod); | |
| 122 | 125 | var max_count: u32 = 0; |
| 123 | 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 | 128 | if (field_count == invalid) return invalid; |
| 126 | 129 | if (field_count > max_count) max_count = field_count; |
| 127 | 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 | 132 | return max_count; |
| 130 | 133 | }, |
| 131 | 134 | .Struct => { |
| 132 | const fields_len = ty.structFieldCount(); | |
| 135 | const fields_len = ty.structFieldCount(mod); | |
| 133 | 136 | var count: u32 = 0; |
| 134 | 137 | var i: u32 = 0; |
| 135 | 138 | while (i < fields_len) : (i += 1) { |
| 136 | const field_ty = ty.structFieldType(i); | |
| 137 | const field_count = countFloats(field_ty, target, maybe_float_bits); | |
| 139 | const field_ty = ty.structFieldType(i, mod); | |
| 140 | const field_count = countFloats(field_ty, mod, maybe_float_bits); | |
| 138 | 141 | if (field_count == invalid) return invalid; |
| 139 | 142 | count += field_count; |
| 140 | 143 | if (count > byval_float_count) return invalid; |
src/arch/riscv64/CodeGen.zig+108-95| ... | ... | @@ -217,7 +217,7 @@ const Self = @This(); |
| 217 | 217 | pub fn generate( |
| 218 | 218 | bin_file: *link.File, |
| 219 | 219 | src_loc: Module.SrcLoc, |
| 220 | module_fn: *Module.Fn, | |
| 220 | module_fn_index: Module.Fn.Index, | |
| 221 | 221 | air: Air, |
| 222 | 222 | liveness: Liveness, |
| 223 | 223 | code: *std.ArrayList(u8), |
| ... | ... | @@ -228,6 +228,7 @@ pub fn generate( |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | 230 | const mod = bin_file.options.module.?; |
| 231 | const module_fn = mod.funcPtr(module_fn_index); | |
| 231 | 232 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 232 | 233 | assert(fn_owner_decl.has_tv); |
| 233 | 234 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -347,7 +348,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 347 | 348 | } |
| 348 | 349 | |
| 349 | 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 | 353 | if (cc != .Naked) { |
| 352 | 354 | // TODO Finish function prologue and epilogue for riscv64. |
| 353 | 355 | |
| ... | ... | @@ -470,13 +472,14 @@ fn gen(self: *Self) !void { |
| 470 | 472 | } |
| 471 | 473 | |
| 472 | 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 | 477 | const air_tags = self.air.instructions.items(.tag); |
| 474 | 478 | |
| 475 | 479 | for (body) |inst| { |
| 476 | 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 | 482 | continue; |
| 479 | } | |
| 480 | 483 | |
| 481 | 484 | const old_air_bookkeeping = self.air_bookkeeping; |
| 482 | 485 | try self.ensureProcessDeathCapacity(Liveness.bpi); |
| ... | ... | @@ -656,8 +659,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 656 | 659 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 657 | 660 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 658 | 661 | |
| 659 | .constant => unreachable, // excluded from function bodies | |
| 660 | .const_ty => unreachable, // excluded from function bodies | |
| 662 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 661 | 663 | .unreach => self.finishAirBookkeeping(), |
| 662 | 664 | |
| 663 | 665 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | ... | @@ -727,8 +729,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 727 | 729 | |
| 728 | 730 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 729 | 731 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 730 | const air_tags = self.air.instructions.items(.tag); | |
| 731 | if (air_tags[inst] == .constant) return; // Constants are immortal. | |
| 732 | assert(self.air.instructions.items(.tag)[inst] != .interned); | |
| 732 | 733 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 733 | 734 | const prev_value = self.getResolvedInstValue(inst); |
| 734 | 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 | 756 | tomb_bits >>= 1; |
| 756 | 757 | if (!dies) continue; |
| 757 | 758 | const op_int = @enumToInt(op); |
| 758 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | |
| 759 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 759 | if (op_int < Air.ref_start_index) continue; | |
| 760 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); | |
| 760 | 761 | self.processDeath(op_index); |
| 761 | 762 | } |
| 762 | 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 | 805 | |
| 805 | 806 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 806 | 807 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 807 | const elem_ty = self.air.typeOfIndex(inst).elemType(); | |
| 808 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | |
| 809 | const mod = self.bin_file.options.module.?; | |
| 808 | const mod = self.bin_file.options.module.?; | |
| 809 | const elem_ty = self.typeOfIndex(inst).childType(mod); | |
| 810 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { | |
| 810 | 811 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 811 | 812 | }; |
| 812 | 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 | 815 | return self.allocMem(inst, abi_size, abi_align); |
| 815 | 816 | } |
| 816 | 817 | |
| 817 | 818 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 818 | const elem_ty = self.air.typeOfIndex(inst); | |
| 819 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | |
| 820 | const mod = self.bin_file.options.module.?; | |
| 819 | const mod = self.bin_file.options.module.?; | |
| 820 | const elem_ty = self.typeOfIndex(inst); | |
| 821 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { | |
| 821 | 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 | 825 | if (abi_align > self.stack_align) |
| 825 | 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 | 846 | assert(reg == reg_mcv.register); |
| 846 | 847 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 847 | 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 | 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 | 863 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 863 | 864 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 864 | 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 | 867 | return MCValue{ .register = reg }; |
| 867 | 868 | } |
| 868 | 869 | |
| ... | ... | @@ -893,10 +894,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 893 | 894 | if (self.liveness.isUnused(inst)) |
| 894 | 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 | 899 | const operand = try self.resolveInst(ty_op.operand); |
| 898 | const info_a = operand_ty.intInfo(self.target.*); | |
| 899 | const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); | |
| 900 | const info_a = operand_ty.intInfo(mod); | |
| 901 | const info_b = self.typeOfIndex(inst).intInfo(mod); | |
| 900 | 902 | if (info_a.signedness != info_b.signedness) |
| 901 | 903 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); |
| 902 | 904 | |
| ... | ... | @@ -1068,18 +1070,18 @@ fn binOp( |
| 1068 | 1070 | lhs_ty: Type, |
| 1069 | 1071 | rhs_ty: Type, |
| 1070 | 1072 | ) InnerError!MCValue { |
| 1073 | const mod = self.bin_file.options.module.?; | |
| 1071 | 1074 | switch (tag) { |
| 1072 | 1075 | // Arithmetic operations on integers and floats |
| 1073 | 1076 | .add, |
| 1074 | 1077 | .sub, |
| 1075 | 1078 | => { |
| 1076 | switch (lhs_ty.zigTypeTag()) { | |
| 1079 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 1077 | 1080 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 1078 | 1081 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 1079 | 1082 | .Int => { |
| 1080 | const mod = self.bin_file.options.module.?; | |
| 1081 | 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 | 1085 | if (int_info.bits <= 64) { |
| 1084 | 1086 | // TODO immediate operands |
| 1085 | 1087 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| ... | ... | @@ -1093,14 +1095,14 @@ fn binOp( |
| 1093 | 1095 | .ptr_add, |
| 1094 | 1096 | .ptr_sub, |
| 1095 | 1097 | => { |
| 1096 | switch (lhs_ty.zigTypeTag()) { | |
| 1098 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 1097 | 1099 | .Pointer => { |
| 1098 | 1100 | const ptr_ty = lhs_ty; |
| 1099 | const elem_ty = switch (ptr_ty.ptrSize()) { | |
| 1100 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | |
| 1101 | else => ptr_ty.childType(), | |
| 1101 | const elem_ty = switch (ptr_ty.ptrSize(mod)) { | |
| 1102 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type | |
| 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 | 1107 | if (elem_size == 1) { |
| 1106 | 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 | 1127 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1126 | 1128 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1127 | 1129 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1128 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1129 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1130 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1131 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1130 | 1132 | |
| 1131 | 1133 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1132 | 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 | 1139 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1138 | 1140 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1139 | 1141 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1140 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1141 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1142 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1143 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1142 | 1144 | |
| 1143 | 1145 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1144 | 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 | 1333 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1332 | 1334 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1333 | 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 | 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 | 1341 | break :result MCValue{ .immediate = 1 }; |
| 1339 | 1342 | |
| 1340 | 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 | 1501 | } |
| 1499 | 1502 | |
| 1500 | 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 | 1506 | switch (ptr) { |
| 1503 | 1507 | .none => unreachable, |
| 1504 | 1508 | .undef => unreachable, |
| ... | ... | @@ -1523,14 +1527,15 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1523 | 1527 | } |
| 1524 | 1528 | |
| 1525 | 1529 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1530 | const mod = self.bin_file.options.module.?; | |
| 1526 | 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 | 1533 | const result: MCValue = result: { |
| 1529 | if (!elem_ty.hasRuntimeBits()) | |
| 1534 | if (!elem_ty.hasRuntimeBits(mod)) | |
| 1530 | 1535 | break :result MCValue.none; |
| 1531 | 1536 | |
| 1532 | 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 | 1539 | if (self.liveness.isUnused(inst) and !is_volatile) |
| 1535 | 1540 | break :result MCValue.dead; |
| 1536 | 1541 | |
| ... | ... | @@ -1542,7 +1547,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1542 | 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 | 1551 | break :result dst_mcv; |
| 1547 | 1552 | }; |
| 1548 | 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 | 1588 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1584 | 1589 | const ptr = try self.resolveInst(bin_op.lhs); |
| 1585 | 1590 | const value = try self.resolveInst(bin_op.rhs); |
| 1586 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 1587 | const value_ty = self.air.typeOf(bin_op.rhs); | |
| 1591 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 1592 | const value_ty = self.typeOf(bin_op.rhs); | |
| 1588 | 1593 | |
| 1589 | 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 | 1649 | const arg_index = self.arg_index; |
| 1645 | 1650 | self.arg_index += 1; |
| 1646 | 1651 | |
| 1647 | const ty = self.air.typeOfIndex(inst); | |
| 1652 | const ty = self.typeOfIndex(inst); | |
| 1648 | 1653 | _ = ty; |
| 1649 | 1654 | |
| 1650 | 1655 | const result = self.args[arg_index]; |
| ... | ... | @@ -1698,9 +1703,10 @@ fn airFence(self: *Self) !void { |
| 1698 | 1703 | } |
| 1699 | 1704 | |
| 1700 | 1705 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 1706 | const mod = self.bin_file.options.module.?; | |
| 1701 | 1707 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{}); |
| 1702 | 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 | 1710 | const callee = pl_op.operand; |
| 1705 | 1711 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 1706 | 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 | 1719 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 1714 | 1720 | for (info.args, 0..) |mc_arg, arg_i| { |
| 1715 | 1721 | const arg = args[arg_i]; |
| 1716 | const arg_ty = self.air.typeOf(arg); | |
| 1722 | const arg_ty = self.typeOf(arg); | |
| 1717 | 1723 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 1718 | 1724 | |
| 1719 | 1725 | switch (mc_arg) { |
| ... | ... | @@ -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| { | |
| 1740 | if (func_value.castTag(.function)) |func_payload| { | |
| 1741 | const func = func_payload.data; | |
| 1745 | if (try self.air.value(callee, mod)) |func_value| { | |
| 1746 | if (mod.funcPtrUnwrap(mod.intern_pool.indexToFunc(func_value.ip_index))) |func| { | |
| 1742 | 1747 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 1743 | 1748 | const atom = elf_file.getAtom(atom_index); |
| 1744 | 1749 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 1745 | 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 | 1752 | _ = try self.addInst(.{ |
| 1748 | 1753 | .tag = .jalr, |
| 1749 | 1754 | .data = .{ .i_type = .{ |
| ... | ... | @@ -1752,7 +1757,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1752 | 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 | 1761 | return self.fail("TODO implement calling extern functions", .{}); |
| 1757 | 1762 | } else { |
| 1758 | 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 | 1801 | } |
| 1797 | 1802 | |
| 1798 | 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 | 1806 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 1801 | 1807 | // Just add space for an instruction, patch this later |
| 1802 | 1808 | const index = try self.addInst(.{ |
| ... | ... | @@ -1825,10 +1831,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1825 | 1831 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1826 | 1832 | if (self.liveness.isUnused(inst)) |
| 1827 | 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 | 1835 | const mod = self.bin_file.options.module.?; |
| 1830 | assert(ty.eql(self.air.typeOf(bin_op.rhs), mod)); | |
| 1831 | if (ty.zigTypeTag() == .ErrorSet) | |
| 1836 | assert(ty.eql(self.typeOf(bin_op.rhs), mod)); | |
| 1837 | if (ty.zigTypeTag(mod) == .ErrorSet) | |
| 1832 | 1838 | return self.fail("TODO implement cmp for errors", .{}); |
| 1833 | 1839 | |
| 1834 | 1840 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -1869,8 +1875,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1869 | 1875 | } |
| 1870 | 1876 | |
| 1871 | 1877 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 1872 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 1873 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 1878 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; | |
| 1879 | const mod = self.bin_file.options.module.?; | |
| 1880 | const function = mod.funcPtr(ty_fn.func); | |
| 1874 | 1881 | // TODO emit debug info for function change |
| 1875 | 1882 | _ = function; |
| 1876 | 1883 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | ... | @@ -1946,7 +1953,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1946 | 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 | 1957 | break :result try self.isNull(operand); |
| 1951 | 1958 | }; |
| 1952 | 1959 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | ... | @@ -1973,7 +1980,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1973 | 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 | 1984 | break :result try self.isNonNull(operand); |
| 1978 | 1985 | }; |
| 1979 | 1986 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | ... | @@ -2000,7 +2007,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2000 | 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 | 2011 | break :result try self.isErr(operand); |
| 2005 | 2012 | }; |
| 2006 | 2013 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | ... | @@ -2027,7 +2034,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2027 | 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 | 2038 | break :result try self.isNonErr(operand); |
| 2032 | 2039 | }; |
| 2033 | 2040 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | ... | @@ -2107,13 +2114,14 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2107 | 2114 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 2108 | 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 | 2119 | const operand_mcv = try self.resolveInst(operand); |
| 2112 | 2120 | const block_mcv = block_data.mcv; |
| 2113 | 2121 | if (block_mcv == .none) { |
| 2114 | 2122 | block_data.mcv = operand_mcv; |
| 2115 | 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 | 2127 | return self.brVoid(block); |
| ... | ... | @@ -2176,7 +2184,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 2176 | 2184 | |
| 2177 | 2185 | const arg_mcv = try self.resolveInst(input); |
| 2178 | 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 | 2380 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2373 | 2381 | |
| 2374 | 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 | 2384 | break :result dest; |
| 2377 | 2385 | }; |
| 2378 | 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 | 2497 | } |
| 2490 | 2498 | |
| 2491 | 2499 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 2492 | const vector_ty = self.air.typeOfIndex(inst); | |
| 2493 | const len = vector_ty.vectorLen(); | |
| 2500 | const mod = self.bin_file.options.module.?; | |
| 2501 | const vector_ty = self.typeOfIndex(inst); | |
| 2502 | const len = vector_ty.vectorLen(mod); | |
| 2494 | 2503 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2495 | 2504 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 2496 | 2505 | const result: MCValue = res: { |
| ... | ... | @@ -2533,37 +2542,32 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 2533 | 2542 | } |
| 2534 | 2543 | |
| 2535 | 2544 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 2536 | // First section of indexes correspond to a set number of constant values. | |
| 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 | const mod = self.bin_file.options.module.?; | |
| 2545 | 2546 | |
| 2546 | 2547 | // If the type has no codegen bits, no need to store it. |
| 2547 | const inst_ty = self.air.typeOf(inst); | |
| 2548 | if (!inst_ty.hasRuntimeBits()) | |
| 2548 | const inst_ty = self.typeOf(inst); | |
| 2549 | if (!inst_ty.hasRuntimeBits(mod)) | |
| 2549 | 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 | 2557 | switch (self.air.instructions.items(.tag)[inst_index]) { |
| 2553 | .constant => { | |
| 2558 | .interned => { | |
| 2554 | 2559 | // Constants have static lifetimes, so they are always memoized in the outer most table. |
| 2555 | 2560 | const branch = &self.branch_stack.items[0]; |
| 2556 | 2561 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); |
| 2557 | 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 | 2564 | gop.value_ptr.* = try self.genTypedValue(.{ |
| 2560 | 2565 | .ty = inst_ty, |
| 2561 | .val = self.air.values[ty_pl.payload], | |
| 2566 | .val = interned.toValue(), | |
| 2562 | 2567 | }); |
| 2563 | 2568 | } |
| 2564 | 2569 | return gop.value_ptr.*; |
| 2565 | 2570 | }, |
| 2566 | .const_ty => unreachable, | |
| 2567 | 2571 | else => return self.getResolvedInstValue(inst_index), |
| 2568 | 2572 | } |
| 2569 | 2573 | } |
| ... | ... | @@ -2616,12 +2620,11 @@ const CallMCValues = struct { |
| 2616 | 2620 | |
| 2617 | 2621 | /// Caller must call `CallMCValues.deinit`. |
| 2618 | 2622 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2619 | const cc = fn_ty.fnCallingConvention(); | |
| 2620 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | |
| 2621 | defer self.gpa.free(param_types); | |
| 2622 | fn_ty.fnParamTypes(param_types); | |
| 2623 | const mod = self.bin_file.options.module.?; | |
| 2624 | const fn_info = mod.typeToFunc(fn_ty).?; | |
| 2625 | const cc = fn_info.cc; | |
| 2623 | 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 | 2628 | // These undefined values must be populated before returning from this function. |
| 2626 | 2629 | .return_value = undefined, |
| 2627 | 2630 | .stack_byte_count = undefined, |
| ... | ... | @@ -2629,7 +2632,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2629 | 2632 | }; |
| 2630 | 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 | 2637 | switch (cc) { |
| 2635 | 2638 | .Naked => { |
| ... | ... | @@ -2649,8 +2652,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2649 | 2652 | var next_stack_offset: u32 = 0; |
| 2650 | 2653 | const argument_registers = [_]Register{ .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7 }; |
| 2651 | 2654 | |
| 2652 | for (param_types, 0..) |ty, i| { | |
| 2653 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | |
| 2655 | for (fn_info.param_types, 0..) |ty, i| { | |
| 2656 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); | |
| 2654 | 2657 | if (param_size <= 8) { |
| 2655 | 2658 | if (next_register < argument_registers.len) { |
| 2656 | 2659 | result.args[i] = .{ .register = argument_registers[next_register] }; |
| ... | ... | @@ -2680,14 +2683,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2680 | 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 | 2687 | result.return_value = .{ .unreach = {} }; |
| 2685 | } else if (!ret_ty.hasRuntimeBits()) { | |
| 2688 | } else if (!ret_ty.hasRuntimeBits(mod)) { | |
| 2686 | 2689 | result.return_value = .{ .none = {} }; |
| 2687 | 2690 | } else switch (cc) { |
| 2688 | 2691 | .Naked => unreachable, |
| 2689 | 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 | 2694 | if (ret_ty_size <= 8) { |
| 2692 | 2695 | result.return_value = .{ .register = .a0 }; |
| 2693 | 2696 | } else if (ret_ty_size <= 16) { |
| ... | ... | @@ -2731,3 +2734,13 @@ fn parseRegName(name: []const u8) ?Register { |
| 2731 | 2734 | } |
| 2732 | 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 | 3 | const Register = bits.Register; |
| 4 | 4 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 5 | 5 | const Type = @import("../../type.zig").Type; |
| 6 | const Module = @import("../../Module.zig"); | |
| 6 | 7 | |
| 7 | 8 | pub const Class = enum { memory, byval, integer, double_integer }; |
| 8 | 9 | |
| 9 | pub fn classifyType(ty: Type, target: std.Target) Class { | |
| 10 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime()); | |
| 10 | pub fn classifyType(ty: Type, mod: *Module) Class { | |
| 11 | const target = mod.getTarget(); | |
| 12 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(mod)); | |
| 11 | 13 | |
| 12 | 14 | const max_byval_size = target.ptrBitWidth() * 2; |
| 13 | switch (ty.zigTypeTag()) { | |
| 15 | switch (ty.zigTypeTag(mod)) { | |
| 14 | 16 | .Struct => { |
| 15 | const bit_size = ty.bitSize(target); | |
| 16 | if (ty.containerLayout() == .Packed) { | |
| 17 | const bit_size = ty.bitSize(mod); | |
| 18 | if (ty.containerLayout(mod) == .Packed) { | |
| 17 | 19 | if (bit_size > max_byval_size) return .memory; |
| 18 | 20 | return .byval; |
| 19 | 21 | } |
| ... | ... | @@ -23,8 +25,8 @@ pub fn classifyType(ty: Type, target: std.Target) Class { |
| 23 | 25 | return .integer; |
| 24 | 26 | }, |
| 25 | 27 | .Union => { |
| 26 | const bit_size = ty.bitSize(target); | |
| 27 | if (ty.containerLayout() == .Packed) { | |
| 28 | const bit_size = ty.bitSize(mod); | |
| 29 | if (ty.containerLayout(mod) == .Packed) { | |
| 28 | 30 | if (bit_size > max_byval_size) return .memory; |
| 29 | 31 | return .byval; |
| 30 | 32 | } |
| ... | ... | @@ -36,21 +38,21 @@ pub fn classifyType(ty: Type, target: std.Target) Class { |
| 36 | 38 | .Bool => return .integer, |
| 37 | 39 | .Float => return .byval, |
| 38 | 40 | .Int, .Enum, .ErrorSet => { |
| 39 | const bit_size = ty.bitSize(target); | |
| 41 | const bit_size = ty.bitSize(mod); | |
| 40 | 42 | if (bit_size > max_byval_size) return .memory; |
| 41 | 43 | return .byval; |
| 42 | 44 | }, |
| 43 | 45 | .Vector => { |
| 44 | const bit_size = ty.bitSize(target); | |
| 46 | const bit_size = ty.bitSize(mod); | |
| 45 | 47 | if (bit_size > max_byval_size) return .memory; |
| 46 | 48 | return .integer; |
| 47 | 49 | }, |
| 48 | 50 | .Optional => { |
| 49 | std.debug.assert(ty.isPtrLikeOptional()); | |
| 51 | std.debug.assert(ty.isPtrLikeOptional(mod)); | |
| 50 | 52 | return .byval; |
| 51 | 53 | }, |
| 52 | 54 | .Pointer => { |
| 53 | std.debug.assert(!ty.isSlice()); | |
| 55 | std.debug.assert(!ty.isSlice(mod)); | |
| 54 | 56 | return .byval; |
| 55 | 57 | }, |
| 56 | 58 | .ErrorUnion, |
src/arch/sparc64/CodeGen.zig+244-222| ... | ... | @@ -260,7 +260,7 @@ const BigTomb = struct { |
| 260 | 260 | pub fn generate( |
| 261 | 261 | bin_file: *link.File, |
| 262 | 262 | src_loc: Module.SrcLoc, |
| 263 | module_fn: *Module.Fn, | |
| 263 | module_fn_index: Module.Fn.Index, | |
| 264 | 264 | air: Air, |
| 265 | 265 | liveness: Liveness, |
| 266 | 266 | code: *std.ArrayList(u8), |
| ... | ... | @@ -271,12 +271,11 @@ pub fn generate( |
| 271 | 271 | } |
| 272 | 272 | |
| 273 | 273 | const mod = bin_file.options.module.?; |
| 274 | const module_fn = mod.funcPtr(module_fn_index); | |
| 274 | 275 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 275 | 276 | assert(fn_owner_decl.has_tv); |
| 276 | 277 | const fn_type = fn_owner_decl.ty; |
| 277 | 278 | |
| 278 | log.debug("fn {s}", .{fn_owner_decl.name}); | |
| 279 | ||
| 280 | 279 | var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); |
| 281 | 280 | defer { |
| 282 | 281 | assert(branch_stack.items.len == 1); |
| ... | ... | @@ -363,7 +362,8 @@ pub fn generate( |
| 363 | 362 | } |
| 364 | 363 | |
| 365 | 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 | 367 | if (cc != .Naked) { |
| 368 | 368 | // TODO Finish function prologue and epilogue for sparc64. |
| 369 | 369 | |
| ... | ... | @@ -490,13 +490,14 @@ fn gen(self: *Self) !void { |
| 490 | 490 | } |
| 491 | 491 | |
| 492 | 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 | 495 | const air_tags = self.air.instructions.items(.tag); |
| 494 | 496 | |
| 495 | 497 | for (body) |inst| { |
| 496 | 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 | 500 | continue; |
| 499 | } | |
| 500 | 501 | |
| 501 | 502 | const old_air_bookkeeping = self.air_bookkeeping; |
| 502 | 503 | try self.ensureProcessDeathCapacity(Liveness.bpi); |
| ... | ... | @@ -676,8 +677,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 676 | 677 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 677 | 678 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 678 | 679 | |
| 679 | .constant => unreachable, // excluded from function bodies | |
| 680 | .const_ty => unreachable, // excluded from function bodies | |
| 680 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 681 | 681 | .unreach => self.finishAirBookkeeping(), |
| 682 | 682 | |
| 683 | 683 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | ... | @@ -758,18 +758,18 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 758 | 758 | const tag = self.air.instructions.items(.tag)[inst]; |
| 759 | 759 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 760 | 760 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 761 | const mod = self.bin_file.options.module.?; | |
| 761 | 762 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 762 | 763 | const lhs = try self.resolveInst(extra.lhs); |
| 763 | 764 | const rhs = try self.resolveInst(extra.rhs); |
| 764 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 765 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 765 | const lhs_ty = self.typeOf(extra.lhs); | |
| 766 | const rhs_ty = self.typeOf(extra.rhs); | |
| 766 | 767 | |
| 767 | switch (lhs_ty.zigTypeTag()) { | |
| 768 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 768 | 769 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), |
| 769 | 770 | .Int => { |
| 770 | const mod = self.bin_file.options.module.?; | |
| 771 | 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 | 773 | switch (int_info.bits) { |
| 774 | 774 | 32, 64 => { |
| 775 | 775 | // Only say yes if the operation is |
| ... | ... | @@ -836,8 +836,9 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 836 | 836 | } |
| 837 | 837 | |
| 838 | 838 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 839 | const vector_ty = self.air.typeOfIndex(inst); | |
| 840 | const len = vector_ty.vectorLen(); | |
| 839 | const mod = self.bin_file.options.module.?; | |
| 840 | const vector_ty = self.typeOfIndex(inst); | |
| 841 | const len = vector_ty.vectorLen(mod); | |
| 841 | 842 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 842 | 843 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 843 | 844 | const result: MCValue = res: { |
| ... | ... | @@ -869,19 +870,20 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 869 | 870 | } |
| 870 | 871 | |
| 871 | 872 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 873 | const mod = self.bin_file.options.module.?; | |
| 872 | 874 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 873 | 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 | 877 | const ptr = try self.resolveInst(ty_op.operand); |
| 876 | const array_ty = ptr_ty.childType(); | |
| 877 | const array_len = @intCast(u32, array_ty.arrayLen()); | |
| 878 | const array_ty = ptr_ty.childType(mod); | |
| 879 | const array_len = @intCast(u32, array_ty.arrayLen(mod)); | |
| 878 | 880 | |
| 879 | 881 | const ptr_bits = self.target.ptrBitWidth(); |
| 880 | 882 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 881 | 883 | |
| 882 | 884 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); |
| 883 | 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 | 887 | break :result MCValue{ .stack_offset = stack_offset }; |
| 886 | 888 | }; |
| 887 | 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 | 937 | |
| 936 | 938 | const arg_mcv = try self.resolveInst(input); |
| 937 | 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 | 1010 | } |
| 1009 | 1011 | |
| 1010 | 1012 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1013 | const mod = self.bin_file.options.module.?; | |
| 1011 | 1014 | const arg_index = self.arg_index; |
| 1012 | 1015 | self.arg_index += 1; |
| 1013 | 1016 | |
| 1014 | const ty = self.air.typeOfIndex(inst); | |
| 1017 | const ty = self.typeOfIndex(inst); | |
| 1015 | 1018 | |
| 1016 | 1019 | const arg = self.args[arg_index]; |
| 1017 | 1020 | const mcv = blk: { |
| 1018 | 1021 | switch (arg) { |
| 1019 | 1022 | .stack_offset => |off| { |
| 1020 | const mod = self.bin_file.options.module.?; | |
| 1021 | const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse { | |
| 1023 | const abi_size = math.cast(u32, ty.abiSize(mod)) orelse { | |
| 1022 | 1024 | return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); |
| 1023 | 1025 | }; |
| 1024 | 1026 | const offset = off + abi_size; |
| ... | ... | @@ -1063,8 +1065,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1063 | 1065 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1064 | 1066 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1065 | 1067 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1066 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1067 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1068 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1069 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1068 | 1070 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1069 | 1071 | .dead |
| 1070 | 1072 | else |
| ... | ... | @@ -1088,8 +1090,8 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 1088 | 1090 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1089 | 1091 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1090 | 1092 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1091 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1092 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1093 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1094 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1093 | 1095 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1094 | 1096 | .dead |
| 1095 | 1097 | else |
| ... | ... | @@ -1115,7 +1117,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1115 | 1117 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 1116 | 1118 | |
| 1117 | 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 | 1121 | break :result dest; |
| 1120 | 1122 | }; |
| 1121 | 1123 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | ... | @@ -1203,6 +1205,7 @@ fn airBreakpoint(self: *Self) !void { |
| 1203 | 1205 | } |
| 1204 | 1206 | |
| 1205 | 1207 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 1208 | const mod = self.bin_file.options.module.?; | |
| 1206 | 1209 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1207 | 1210 | |
| 1208 | 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 | 1220 | // TODO: Fold byteswap+store into a single ST*A and load+byteswap into a single LD*A. |
| 1218 | 1221 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1219 | 1222 | const operand = try self.resolveInst(ty_op.operand); |
| 1220 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 1221 | switch (operand_ty.zigTypeTag()) { | |
| 1223 | const operand_ty = self.typeOf(ty_op.operand); | |
| 1224 | switch (operand_ty.zigTypeTag(mod)) { | |
| 1222 | 1225 | .Vector => return self.fail("TODO byteswap for vectors", .{}), |
| 1223 | 1226 | .Int => { |
| 1224 | const int_info = operand_ty.intInfo(self.target.*); | |
| 1227 | const int_info = operand_ty.intInfo(mod); | |
| 1225 | 1228 | if (int_info.bits == 8) break :result operand; |
| 1226 | 1229 | |
| 1227 | 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 | 1232 | const opposite_endian_asi = switch (self.target.cpu.arch.endian()) { |
| 1230 | 1233 | Endian.Big => ASI.asi_primary_little, |
| 1231 | 1234 | Endian.Little => ASI.asi_primary, |
| ... | ... | @@ -1293,10 +1296,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1293 | 1296 | const callee = pl_op.operand; |
| 1294 | 1297 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 1295 | 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); | |
| 1297 | const fn_ty = switch (ty.zigTypeTag()) { | |
| 1299 | const ty = self.typeOf(callee); | |
| 1300 | const mod = self.bin_file.options.module.?; | |
| 1301 | const fn_ty = switch (ty.zigTypeTag(mod)) { | |
| 1298 | 1302 | .Fn => ty, |
| 1299 | .Pointer => ty.childType(), | |
| 1303 | .Pointer => ty.childType(mod), | |
| 1300 | 1304 | else => unreachable, |
| 1301 | 1305 | }; |
| 1302 | 1306 | |
| ... | ... | @@ -1316,7 +1320,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1316 | 1320 | |
| 1317 | 1321 | for (info.args, 0..) |mc_arg, arg_i| { |
| 1318 | 1322 | const arg = args[arg_i]; |
| 1319 | const arg_ty = self.air.typeOf(arg); | |
| 1323 | const arg_ty = self.typeOf(arg); | |
| 1320 | 1324 | const arg_mcv = try self.resolveInst(arg); |
| 1321 | 1325 | |
| 1322 | 1326 | switch (mc_arg) { |
| ... | ... | @@ -1337,10 +1341,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1337 | 1341 | |
| 1338 | 1342 | // Due to incremental compilation, how function calls are generated depends |
| 1339 | 1343 | // on linking. |
| 1340 | if (self.air.value(callee)) |func_value| { | |
| 1344 | if (try self.air.value(callee, mod)) |func_value| { | |
| 1341 | 1345 | if (self.bin_file.tag == link.File.Elf.base_tag) { |
| 1342 | if (func_value.castTag(.function)) |func_payload| { | |
| 1343 | const func = func_payload.data; | |
| 1346 | if (mod.funcPtrUnwrap(mod.intern_pool.indexToFunc(func_value.ip_index))) |func| { | |
| 1344 | 1347 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| 1345 | 1348 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 1346 | 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 | 1351 | break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file)); |
| 1349 | 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 | 1356 | _ = try self.addInst(.{ |
| 1354 | 1357 | .tag = .jmpl, |
| ... | ... | @@ -1367,14 +1370,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1367 | 1370 | .tag = .nop, |
| 1368 | 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 | 1374 | return self.fail("TODO implement calling extern functions", .{}); |
| 1372 | 1375 | } else { |
| 1373 | 1376 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 1374 | 1377 | } |
| 1375 | 1378 | } else @panic("TODO SPARCv9 currently does not support non-ELF binaries"); |
| 1376 | 1379 | } else { |
| 1377 | assert(ty.zigTypeTag() == .Pointer); | |
| 1380 | assert(ty.zigTypeTag(mod) == .Pointer); | |
| 1378 | 1381 | const mcv = try self.resolveInst(callee); |
| 1379 | 1382 | try self.genSetReg(ty, .o7, mcv); |
| 1380 | 1383 | |
| ... | ... | @@ -1422,25 +1425,24 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 1422 | 1425 | |
| 1423 | 1426 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1424 | 1427 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1428 | const mod = self.bin_file.options.module.?; | |
| 1425 | 1429 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1426 | 1430 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1427 | 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; | |
| 1431 | const int_ty = switch (lhs_ty.zigTypeTag()) { | |
| 1434 | const int_ty = switch (lhs_ty.zigTypeTag(mod)) { | |
| 1432 | 1435 | .Vector => unreachable, // Handled by cmp_vector. |
| 1433 | .Enum => lhs_ty.intTagType(&int_buffer), | |
| 1436 | .Enum => lhs_ty.intTagType(mod), | |
| 1434 | 1437 | .Int => lhs_ty, |
| 1435 | .Bool => Type.initTag(.u1), | |
| 1438 | .Bool => Type.u1, | |
| 1436 | 1439 | .Pointer => Type.usize, |
| 1437 | .ErrorSet => Type.initTag(.u16), | |
| 1440 | .ErrorSet => Type.u16, | |
| 1438 | 1441 | .Optional => blk: { |
| 1439 | var opt_buffer: Type.Payload.ElemType = undefined; | |
| 1440 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); | |
| 1441 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1442 | break :blk Type.initTag(.u1); | |
| 1443 | } else if (lhs_ty.isPtrLikeOptional()) { | |
| 1442 | const payload_ty = lhs_ty.optionalChild(mod); | |
| 1443 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1444 | break :blk Type.u1; | |
| 1445 | } else if (lhs_ty.isPtrLikeOptional(mod)) { | |
| 1444 | 1446 | break :blk Type.usize; |
| 1445 | 1447 | } else { |
| 1446 | 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 | 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 | 1456 | if (int_info.bits <= 64) { |
| 1455 | 1457 | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{ |
| 1456 | 1458 | .lhs = bin_op.lhs, |
| ... | ... | @@ -1512,8 +1514,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1512 | 1514 | // whether it needs to be spilled in the branches |
| 1513 | 1515 | if (self.liveness.operandDies(inst, 0)) { |
| 1514 | 1516 | const op_int = @enumToInt(pl_op.operand); |
| 1515 | if (op_int >= Air.Inst.Ref.typed_value_map.len) { | |
| 1516 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 1517 | if (op_int >= Air.ref_start_index) { | |
| 1518 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); | |
| 1517 | 1519 | self.processDeath(op_index); |
| 1518 | 1520 | } |
| 1519 | 1521 | } |
| ... | ... | @@ -1603,7 +1605,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1603 | 1605 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); |
| 1604 | 1606 | // TODO make sure the destination stack offset / register does not already have something |
| 1605 | 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 | 1609 | // TODO track the new register / stack allocation |
| 1608 | 1610 | } |
| 1609 | 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 | 1632 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); |
| 1631 | 1633 | // TODO make sure the destination stack offset / register does not already have something |
| 1632 | 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 | 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 | 1658 | } |
| 1657 | 1659 | |
| 1658 | 1660 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 1659 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 1660 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 1661 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; | |
| 1662 | const mod = self.bin_file.options.module.?; | |
| 1663 | const function = mod.funcPtr(ty_fn.func); | |
| 1661 | 1664 | // TODO emit debug info for function change |
| 1662 | 1665 | _ = function; |
| 1663 | 1666 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | ... | @@ -1752,10 +1755,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1752 | 1755 | if (self.liveness.isUnused(inst)) |
| 1753 | 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 | 1760 | const operand = try self.resolveInst(ty_op.operand); |
| 1757 | const info_a = operand_ty.intInfo(self.target.*); | |
| 1758 | const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); | |
| 1761 | const info_a = operand_ty.intInfo(mod); | |
| 1762 | const info_b = self.typeOfIndex(inst).intInfo(mod); | |
| 1759 | 1763 | if (info_a.signedness != info_b.signedness) |
| 1760 | 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 | 1781 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1778 | 1782 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1779 | 1783 | const operand = try self.resolveInst(un_op); |
| 1780 | const ty = self.air.typeOf(un_op); | |
| 1784 | const ty = self.typeOf(un_op); | |
| 1781 | 1785 | break :result try self.isErr(ty, operand); |
| 1782 | 1786 | }; |
| 1783 | 1787 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | ... | @@ -1787,7 +1791,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1787 | 1791 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1788 | 1792 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1789 | 1793 | const operand = try self.resolveInst(un_op); |
| 1790 | const ty = self.air.typeOf(un_op); | |
| 1794 | const ty = self.typeOf(un_op); | |
| 1791 | 1795 | break :result try self.isNonErr(ty, operand); |
| 1792 | 1796 | }; |
| 1793 | 1797 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | ... | @@ -1812,15 +1816,16 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 1812 | 1816 | } |
| 1813 | 1817 | |
| 1814 | 1818 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1819 | const mod = self.bin_file.options.module.?; | |
| 1815 | 1820 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1816 | const elem_ty = self.air.typeOfIndex(inst); | |
| 1817 | const elem_size = elem_ty.abiSize(self.target.*); | |
| 1821 | const elem_ty = self.typeOfIndex(inst); | |
| 1822 | const elem_size = elem_ty.abiSize(mod); | |
| 1818 | 1823 | const result: MCValue = result: { |
| 1819 | if (!elem_ty.hasRuntimeBits()) | |
| 1824 | if (!elem_ty.hasRuntimeBits(mod)) | |
| 1820 | 1825 | break :result MCValue.none; |
| 1821 | 1826 | |
| 1822 | 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 | 1829 | if (self.liveness.isUnused(inst) and !is_volatile) |
| 1825 | 1830 | break :result MCValue.dead; |
| 1826 | 1831 | |
| ... | ... | @@ -1835,7 +1840,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1835 | 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 | 1844 | break :result dst_mcv; |
| 1840 | 1845 | }; |
| 1841 | 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 | 1883 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1879 | 1884 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1880 | 1885 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1881 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1882 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1886 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1887 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1883 | 1888 | |
| 1884 | 1889 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1885 | 1890 | .dead |
| ... | ... | @@ -1893,8 +1898,8 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1893 | 1898 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1894 | 1899 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1895 | 1900 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1896 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1897 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1901 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 1902 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 1898 | 1903 | assert(lhs_ty.eql(rhs_ty, self.bin_file.options.module.?)); |
| 1899 | 1904 | |
| 1900 | 1905 | if (self.liveness.isUnused(inst)) |
| ... | ... | @@ -2037,18 +2042,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2037 | 2042 | //const tag = self.air.instructions.items(.tag)[inst]; |
| 2038 | 2043 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2039 | 2044 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2045 | const mod = self.bin_file.options.module.?; | |
| 2040 | 2046 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2041 | 2047 | const lhs = try self.resolveInst(extra.lhs); |
| 2042 | 2048 | const rhs = try self.resolveInst(extra.rhs); |
| 2043 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 2044 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 2049 | const lhs_ty = self.typeOf(extra.lhs); | |
| 2050 | const rhs_ty = self.typeOf(extra.rhs); | |
| 2045 | 2051 | |
| 2046 | switch (lhs_ty.zigTypeTag()) { | |
| 2052 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2047 | 2053 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 2048 | 2054 | .Int => { |
| 2049 | const mod = self.bin_file.options.module.?; | |
| 2050 | 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 | 2057 | switch (int_info.bits) { |
| 2053 | 2058 | 1...32 => { |
| 2054 | 2059 | try self.spillConditionFlagsIfOccupied(); |
| ... | ... | @@ -2101,9 +2106,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2101 | 2106 | |
| 2102 | 2107 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 2103 | 2108 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2109 | const mod = self.bin_file.options.module.?; | |
| 2104 | 2110 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2105 | 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 | 2113 | switch (operand) { |
| 2108 | 2114 | .dead => unreachable, |
| 2109 | 2115 | .unreach => unreachable, |
| ... | ... | @@ -2116,7 +2122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 2116 | 2122 | }; |
| 2117 | 2123 | }, |
| 2118 | 2124 | else => { |
| 2119 | switch (operand_ty.zigTypeTag()) { | |
| 2125 | switch (operand_ty.zigTypeTag(mod)) { | |
| 2120 | 2126 | .Bool => { |
| 2121 | 2127 | const op_reg = switch (operand) { |
| 2122 | 2128 | .register => |r| r, |
| ... | ... | @@ -2150,7 +2156,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 2150 | 2156 | }, |
| 2151 | 2157 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), |
| 2152 | 2158 | .Int => { |
| 2153 | const int_info = operand_ty.intInfo(self.target.*); | |
| 2159 | const int_info = operand_ty.intInfo(mod); | |
| 2154 | 2160 | if (int_info.bits <= 64) { |
| 2155 | 2161 | const op_reg = switch (operand) { |
| 2156 | 2162 | .register => |r| r, |
| ... | ... | @@ -2280,8 +2286,8 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 2280 | 2286 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2281 | 2287 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2282 | 2288 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2283 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 2284 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 2289 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 2290 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 2285 | 2291 | |
| 2286 | 2292 | // TODO add safety check |
| 2287 | 2293 | |
| ... | ... | @@ -2332,16 +2338,17 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2332 | 2338 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2333 | 2339 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2334 | 2340 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2341 | const mod = self.bin_file.options.module.?; | |
| 2335 | 2342 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2336 | 2343 | const lhs = try self.resolveInst(extra.lhs); |
| 2337 | 2344 | const rhs = try self.resolveInst(extra.rhs); |
| 2338 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 2339 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 2345 | const lhs_ty = self.typeOf(extra.lhs); | |
| 2346 | const rhs_ty = self.typeOf(extra.rhs); | |
| 2340 | 2347 | |
| 2341 | switch (lhs_ty.zigTypeTag()) { | |
| 2348 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2342 | 2349 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 2343 | 2350 | .Int => { |
| 2344 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 2351 | const int_info = lhs_ty.intInfo(mod); | |
| 2345 | 2352 | if (int_info.bits <= 64) { |
| 2346 | 2353 | try self.spillConditionFlagsIfOccupied(); |
| 2347 | 2354 | |
| ... | ... | @@ -2423,9 +2430,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2423 | 2430 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2424 | 2431 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2425 | 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 | 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 | 2437 | const ptr_bits = self.target.ptrBitWidth(); |
| 2431 | 2438 | const ptr_bytes = @divExact(ptr_bits, 8); |
| ... | ... | @@ -2439,6 +2446,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2439 | 2446 | } |
| 2440 | 2447 | |
| 2441 | 2448 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2449 | const mod = self.bin_file.options.module.?; | |
| 2442 | 2450 | const is_volatile = false; // TODO |
| 2443 | 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 | 2455 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 2448 | 2456 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 2449 | 2457 | |
| 2450 | const slice_ty = self.air.typeOf(bin_op.lhs); | |
| 2451 | const elem_ty = slice_ty.childType(); | |
| 2452 | const elem_size = elem_ty.abiSize(self.target.*); | |
| 2458 | const slice_ty = self.typeOf(bin_op.lhs); | |
| 2459 | const elem_ty = slice_ty.childType(mod); | |
| 2460 | const elem_size = elem_ty.abiSize(mod); | |
| 2453 | 2461 | |
| 2454 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 2455 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | |
| 2462 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod); | |
| 2456 | 2463 | |
| 2457 | 2464 | const index_lock: ?RegisterLock = if (index_mcv == .register) |
| 2458 | 2465 | self.register_manager.lockRegAssumeUnused(index_mcv.register) |
| ... | ... | @@ -2537,8 +2544,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 2537 | 2544 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2538 | 2545 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2539 | 2546 | const value = try self.resolveInst(bin_op.rhs); |
| 2540 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 2541 | const value_ty = self.air.typeOf(bin_op.rhs); | |
| 2547 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 2548 | const value_ty = self.typeOf(bin_op.rhs); | |
| 2542 | 2549 | |
| 2543 | 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 | 2571 | const operand = extra.struct_operand; |
| 2565 | 2572 | const index = extra.field_index; |
| 2566 | 2573 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2574 | const mod = self.bin_file.options.module.?; | |
| 2567 | 2575 | const mcv = try self.resolveInst(operand); |
| 2568 | const struct_ty = self.air.typeOf(operand); | |
| 2569 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | |
| 2576 | const struct_ty = self.typeOf(operand); | |
| 2577 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); | |
| 2570 | 2578 | |
| 2571 | 2579 | switch (mcv) { |
| 2572 | 2580 | .dead, .unreach => unreachable, |
| ... | ... | @@ -2651,8 +2659,8 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 2651 | 2659 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2652 | 2660 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2653 | 2661 | const operand = try self.resolveInst(ty_op.operand); |
| 2654 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 2655 | const dest_ty = self.air.typeOfIndex(inst); | |
| 2662 | const operand_ty = self.typeOf(ty_op.operand); | |
| 2663 | const dest_ty = self.typeOfIndex(inst); | |
| 2656 | 2664 | |
| 2657 | 2665 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 2658 | 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 | 2674 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 2667 | 2675 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 2668 | 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 | 2678 | const error_union = try self.resolveInst(pl_op.operand); |
| 2671 | 2679 | const is_err_result = try self.isErr(error_union_ty, error_union); |
| 2672 | 2680 | const reloc = try self.condBr(is_err_result); |
| ... | ... | @@ -2696,12 +2704,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 2696 | 2704 | } |
| 2697 | 2705 | |
| 2698 | 2706 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2707 | const mod = self.bin_file.options.module.?; | |
| 2699 | 2708 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2700 | 2709 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2701 | const error_union_ty = self.air.typeOf(ty_op.operand); | |
| 2702 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 2710 | const error_union_ty = self.typeOf(ty_op.operand); | |
| 2711 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 2703 | 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 | 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 | 2718 | } |
| 2710 | 2719 | |
| 2711 | 2720 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2721 | const mod = self.bin_file.options.module.?; | |
| 2712 | 2722 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2713 | 2723 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2714 | const error_union_ty = self.air.typeOf(ty_op.operand); | |
| 2715 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 2716 | if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; | |
| 2724 | const error_union_ty = self.typeOf(ty_op.operand); | |
| 2725 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 2726 | if (!payload_ty.hasRuntimeBits(mod)) break :result MCValue.none; | |
| 2717 | 2727 | |
| 2718 | 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 | 2732 | |
| 2723 | 2733 | /// E to E!T |
| 2724 | 2734 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2735 | const mod = self.bin_file.options.module.?; | |
| 2725 | 2736 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2726 | 2737 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2727 | 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 | 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 | 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 | 2753 | } |
| 2743 | 2754 | |
| 2744 | 2755 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2756 | const mod = self.bin_file.options.module.?; | |
| 2745 | 2757 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2746 | 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 | 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 | 2763 | break :result MCValue{ .immediate = 1 }; |
| 2752 | 2764 | |
| 2753 | 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 | 2794 | |
| 2783 | 2795 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 2784 | 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 | 2801 | // As this stack item will never be dereferenced at runtime, |
| 2789 | 2802 | // return the stack offset 0. Stack offset 0 will be where all |
| 2790 | 2803 | // zero-sized stack allocations live as non-zero-sized |
| ... | ... | @@ -2792,22 +2805,21 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 2792 | 2805 | return @as(u32, 0); |
| 2793 | 2806 | } |
| 2794 | 2807 | |
| 2795 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | |
| 2796 | const mod = self.bin_file.options.module.?; | |
| 2808 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { | |
| 2797 | 2809 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 2798 | 2810 | }; |
| 2799 | 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 | 2813 | return self.allocMem(inst, abi_size, abi_align); |
| 2802 | 2814 | } |
| 2803 | 2815 | |
| 2804 | 2816 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2805 | const elem_ty = self.air.typeOfIndex(inst); | |
| 2806 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | |
| 2807 | const mod = self.bin_file.options.module.?; | |
| 2817 | const mod = self.bin_file.options.module.?; | |
| 2818 | const elem_ty = self.typeOfIndex(inst); | |
| 2819 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { | |
| 2808 | 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 | 2823 | if (abi_align > self.stack_align) |
| 2812 | 2824 | self.stack_align = abi_align; |
| 2813 | 2825 | |
| ... | ... | @@ -2860,12 +2872,12 @@ fn binOp( |
| 2860 | 2872 | .xor, |
| 2861 | 2873 | .cmp_eq, |
| 2862 | 2874 | => { |
| 2863 | switch (lhs_ty.zigTypeTag()) { | |
| 2875 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2864 | 2876 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 2865 | 2877 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2866 | 2878 | .Int => { |
| 2867 | 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 | 2881 | if (int_info.bits <= 64) { |
| 2870 | 2882 | // Only say yes if the operation is |
| 2871 | 2883 | // commutative, i.e. we can swap both of the |
| ... | ... | @@ -2934,10 +2946,10 @@ fn binOp( |
| 2934 | 2946 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2935 | 2947 | |
| 2936 | 2948 | // Truncate if necessary |
| 2937 | switch (lhs_ty.zigTypeTag()) { | |
| 2949 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2938 | 2950 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2939 | 2951 | .Int => { |
| 2940 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 2952 | const int_info = lhs_ty.intInfo(mod); | |
| 2941 | 2953 | if (int_info.bits <= 64) { |
| 2942 | 2954 | const result_reg = result.register; |
| 2943 | 2955 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| ... | ... | @@ -2951,11 +2963,11 @@ fn binOp( |
| 2951 | 2963 | }, |
| 2952 | 2964 | |
| 2953 | 2965 | .div_trunc => { |
| 2954 | switch (lhs_ty.zigTypeTag()) { | |
| 2966 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2955 | 2967 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2956 | 2968 | .Int => { |
| 2957 | 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 | 2971 | if (int_info.bits <= 64) { |
| 2960 | 2972 | const rhs_immediate_ok = switch (tag) { |
| 2961 | 2973 | .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| ... | ... | @@ -2984,14 +2996,14 @@ fn binOp( |
| 2984 | 2996 | }, |
| 2985 | 2997 | |
| 2986 | 2998 | .ptr_add => { |
| 2987 | switch (lhs_ty.zigTypeTag()) { | |
| 2999 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 2988 | 3000 | .Pointer => { |
| 2989 | 3001 | const ptr_ty = lhs_ty; |
| 2990 | const elem_ty = switch (ptr_ty.ptrSize()) { | |
| 2991 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | |
| 2992 | else => ptr_ty.childType(), | |
| 3002 | const elem_ty = switch (ptr_ty.ptrSize(mod)) { | |
| 3003 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type | |
| 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 | 3008 | if (elem_size == 1) { |
| 2997 | 3009 | const base_tag: Mir.Inst.Tag = switch (tag) { |
| ... | ... | @@ -3005,7 +3017,7 @@ fn binOp( |
| 3005 | 3017 | // multiplying it with elem_size |
| 3006 | 3018 | |
| 3007 | 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 | 3021 | return addr; |
| 3010 | 3022 | } |
| 3011 | 3023 | }, |
| ... | ... | @@ -3016,7 +3028,7 @@ fn binOp( |
| 3016 | 3028 | .bool_and, |
| 3017 | 3029 | .bool_or, |
| 3018 | 3030 | => { |
| 3019 | switch (lhs_ty.zigTypeTag()) { | |
| 3031 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3020 | 3032 | .Bool => { |
| 3021 | 3033 | assert(lhs != .immediate); // should have been handled by Sema |
| 3022 | 3034 | assert(rhs != .immediate); // should have been handled by Sema |
| ... | ... | @@ -3046,10 +3058,10 @@ fn binOp( |
| 3046 | 3058 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 3047 | 3059 | |
| 3048 | 3060 | // Truncate if necessary |
| 3049 | switch (lhs_ty.zigTypeTag()) { | |
| 3061 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3050 | 3062 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 3051 | 3063 | .Int => { |
| 3052 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 3064 | const int_info = lhs_ty.intInfo(mod); | |
| 3053 | 3065 | if (int_info.bits <= 64) { |
| 3054 | 3066 | // 32 and 64 bit operands doesn't need truncating |
| 3055 | 3067 | if (int_info.bits == 32 or int_info.bits == 64) return result; |
| ... | ... | @@ -3068,10 +3080,10 @@ fn binOp( |
| 3068 | 3080 | .shl_exact, |
| 3069 | 3081 | .shr_exact, |
| 3070 | 3082 | => { |
| 3071 | switch (lhs_ty.zigTypeTag()) { | |
| 3083 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3072 | 3084 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 3073 | 3085 | .Int => { |
| 3074 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 3086 | const int_info = lhs_ty.intInfo(mod); | |
| 3075 | 3087 | if (int_info.bits <= 64) { |
| 3076 | 3088 | const rhs_immediate_ok = rhs == .immediate; |
| 3077 | 3089 | |
| ... | ... | @@ -3393,7 +3405,8 @@ fn binOpRegister( |
| 3393 | 3405 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 3394 | 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 | 3410 | const operand_mcv = try self.resolveInst(operand); |
| 3398 | 3411 | const block_mcv = block_data.mcv; |
| 3399 | 3412 | if (block_mcv == .none) { |
| ... | ... | @@ -3402,13 +3415,13 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 3402 | 3415 | .register, .stack_offset, .memory => operand_mcv, |
| 3403 | 3416 | .immediate => blk: { |
| 3404 | 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 | 3419 | break :blk new_mcv; |
| 3407 | 3420 | }, |
| 3408 | 3421 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), |
| 3409 | 3422 | }; |
| 3410 | 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 | 3427 | return self.brVoid(block); |
| ... | ... | @@ -3512,16 +3525,17 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 3512 | 3525 | |
| 3513 | 3526 | /// Given an error union, returns the payload |
| 3514 | 3527 | fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { |
| 3515 | const err_ty = error_union_ty.errorUnionSet(); | |
| 3516 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 3517 | if (err_ty.errorSetIsEmpty()) { | |
| 3528 | const mod = self.bin_file.options.module.?; | |
| 3529 | const err_ty = error_union_ty.errorUnionSet(mod); | |
| 3530 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 3531 | if (err_ty.errorSetIsEmpty(mod)) { | |
| 3518 | 3532 | return error_union_mcv; |
| 3519 | 3533 | } |
| 3520 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3534 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3521 | 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 | 3539 | switch (error_union_mcv) { |
| 3526 | 3540 | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| 3527 | 3541 | .stack_offset => |off| { |
| ... | ... | @@ -3555,8 +3569,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 3555 | 3569 | tomb_bits >>= 1; |
| 3556 | 3570 | if (!dies) continue; |
| 3557 | 3571 | const op_int = @enumToInt(op); |
| 3558 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | |
| 3559 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 3572 | if (op_int < Air.ref_start_index) continue; | |
| 3573 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); | |
| 3560 | 3574 | self.processDeath(op_index); |
| 3561 | 3575 | } |
| 3562 | 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 | 3744 | } |
| 3731 | 3745 | |
| 3732 | 3746 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3747 | const mod = self.bin_file.options.module.?; | |
| 3733 | 3748 | switch (mcv) { |
| 3734 | 3749 | .dead => unreachable, |
| 3735 | 3750 | .unreach, .none => return, // Nothing to do. |
| ... | ... | @@ -3928,19 +3943,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3928 | 3943 | // The value is in memory at a hard-coded address. |
| 3929 | 3944 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3930 | 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 | 3948 | .stack_offset => |off| { |
| 3934 | 3949 | const real_offset = realStackOffset(off); |
| 3935 | 3950 | const simm13 = math.cast(i13, real_offset) orelse |
| 3936 | 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 | 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 | 3960 | switch (mcv) { |
| 3945 | 3961 | .dead => unreachable, |
| 3946 | 3962 | .unreach, .none => return, // Nothing to do. |
| ... | ... | @@ -3948,7 +3964,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3948 | 3964 | if (!self.wantSafety()) |
| 3949 | 3965 | return; // The already existing value will do just fine. |
| 3950 | 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 | 3968 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 3953 | 3969 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 3954 | 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 | 3990 | const reg_lock = self.register_manager.lockReg(rwo.reg); |
| 3975 | 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 | 3994 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = rwo.reg }); |
| 3979 | 3995 | |
| 3980 | const overflow_bit_ty = ty.structFieldType(1); | |
| 3981 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*)); | |
| 3996 | const overflow_bit_ty = ty.structFieldType(1, mod); | |
| 3997 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, mod)); | |
| 3982 | 3998 | const cond_reg = try self.register_manager.allocReg(null, gp); |
| 3983 | 3999 | |
| 3984 | 4000 | // TODO handle floating point CCRs |
| ... | ... | @@ -4024,11 +4040,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4024 | 4040 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4025 | 4041 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 4026 | 4042 | } else { |
| 4027 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 4028 | .base = .{ .tag = .single_mut_pointer }, | |
| 4029 | .data = ty, | |
| 4030 | }; | |
| 4031 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 4043 | const ptr_ty = try mod.singleMutPtrType(ty); | |
| 4032 | 4044 | |
| 4033 | 4045 | const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp); |
| 4034 | 4046 | const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs); |
| ... | ... | @@ -4152,13 +4164,14 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 4152 | 4164 | } |
| 4153 | 4165 | |
| 4154 | 4166 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4155 | const error_type = ty.errorUnionSet(); | |
| 4156 | const payload_type = ty.errorUnionPayload(); | |
| 4167 | const mod = self.bin_file.options.module.?; | |
| 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 | 4172 | return MCValue{ .immediate = 0 }; // always false |
| 4160 | } else if (!payload_type.hasRuntimeBits()) { | |
| 4161 | if (error_type.abiSize(self.target.*) <= 8) { | |
| 4173 | } else if (!payload_type.hasRuntimeBits(mod)) { | |
| 4174 | if (error_type.abiSize(mod) <= 8) { | |
| 4162 | 4175 | const reg_mcv: MCValue = switch (operand) { |
| 4163 | 4176 | .register => operand, |
| 4164 | 4177 | else => .{ .register = try self.copyToTmpRegister(error_type, operand) }, |
| ... | ... | @@ -4249,8 +4262,9 @@ fn jump(self: *Self, inst: Mir.Inst.Index) !void { |
| 4249 | 4262 | } |
| 4250 | 4263 | |
| 4251 | 4264 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 4252 | const elem_ty = ptr_ty.elemType(); | |
| 4253 | const elem_size = elem_ty.abiSize(self.target.*); | |
| 4265 | const mod = self.bin_file.options.module.?; | |
| 4266 | const elem_ty = ptr_ty.childType(mod); | |
| 4267 | const elem_size = elem_ty.abiSize(mod); | |
| 4254 | 4268 | |
| 4255 | 4269 | switch (ptr) { |
| 4256 | 4270 | .none => unreachable, |
| ... | ... | @@ -4321,11 +4335,11 @@ fn minMax( |
| 4321 | 4335 | ) InnerError!MCValue { |
| 4322 | 4336 | const mod = self.bin_file.options.module.?; |
| 4323 | 4337 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 4324 | switch (lhs_ty.zigTypeTag()) { | |
| 4338 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 4325 | 4339 | .Float => return self.fail("TODO min/max on floats", .{}), |
| 4326 | 4340 | .Vector => return self.fail("TODO min/max on vectors", .{}), |
| 4327 | 4341 | .Int => { |
| 4328 | const int_info = lhs_ty.intInfo(self.target.*); | |
| 4342 | const int_info = lhs_ty.intInfo(mod); | |
| 4329 | 4343 | if (int_info.bits <= 64) { |
| 4330 | 4344 | // TODO skip register setting when one of the operands |
| 4331 | 4345 | // is a small (fits in i13) immediate. |
| ... | ... | @@ -4406,8 +4420,7 @@ fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| 4406 | 4420 | |
| 4407 | 4421 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 4408 | 4422 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 4409 | const air_tags = self.air.instructions.items(.tag); | |
| 4410 | if (air_tags[inst] == .constant) return; // Constants are immortal. | |
| 4423 | assert(self.air.instructions.items(.tag)[inst] != .interned); | |
| 4411 | 4424 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 4412 | 4425 | const prev_value = self.getResolvedInstValue(inst); |
| 4413 | 4426 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | ... | @@ -4441,12 +4454,11 @@ fn realStackOffset(off: u32) u32 { |
| 4441 | 4454 | |
| 4442 | 4455 | /// Caller must call `CallMCValues.deinit`. |
| 4443 | 4456 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) !CallMCValues { |
| 4444 | const cc = fn_ty.fnCallingConvention(); | |
| 4445 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | |
| 4446 | defer self.gpa.free(param_types); | |
| 4447 | fn_ty.fnParamTypes(param_types); | |
| 4457 | const mod = self.bin_file.options.module.?; | |
| 4458 | const fn_info = mod.typeToFunc(fn_ty).?; | |
| 4459 | const cc = fn_info.cc; | |
| 4448 | 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 | 4462 | // These undefined values must be populated before returning from this function. |
| 4451 | 4463 | .return_value = undefined, |
| 4452 | 4464 | .stack_byte_count = undefined, |
| ... | ... | @@ -4454,7 +4466,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4454 | 4466 | }; |
| 4455 | 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 | 4471 | switch (cc) { |
| 4460 | 4472 | .Naked => { |
| ... | ... | @@ -4477,8 +4489,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4477 | 4489 | .callee => abi.c_abi_int_param_regs_callee_view, |
| 4478 | 4490 | }; |
| 4479 | 4491 | |
| 4480 | for (param_types, 0..) |ty, i| { | |
| 4481 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | |
| 4492 | for (fn_info.param_types, 0..) |ty, i| { | |
| 4493 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); | |
| 4482 | 4494 | if (param_size <= 8) { |
| 4483 | 4495 | if (next_register < argument_registers.len) { |
| 4484 | 4496 | result.args[i] = .{ .register = argument_registers[next_register] }; |
| ... | ... | @@ -4505,12 +4517,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4505 | 4517 | result.stack_byte_count = next_stack_offset; |
| 4506 | 4518 | result.stack_align = 16; |
| 4507 | 4519 | |
| 4508 | if (ret_ty.zigTypeTag() == .NoReturn) { | |
| 4520 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { | |
| 4509 | 4521 | result.return_value = .{ .unreach = {} }; |
| 4510 | } else if (!ret_ty.hasRuntimeBits()) { | |
| 4522 | } else if (!ret_ty.hasRuntimeBits(mod)) { | |
| 4511 | 4523 | result.return_value = .{ .none = {} }; |
| 4512 | 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 | 4526 | // The callee puts the return values in %i0-%i3, which becomes %o0-%o3 inside the caller. |
| 4515 | 4527 | if (ret_ty_size <= 8) { |
| 4516 | 4528 | result.return_value = switch (role) { |
| ... | ... | @@ -4528,44 +4540,41 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4528 | 4540 | return result; |
| 4529 | 4541 | } |
| 4530 | 4542 | |
| 4531 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | |
| 4532 | // First section of indexes correspond to a set number of constant values. | |
| 4533 | const ref_int = @enumToInt(inst); | |
| 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 | } | |
| 4543 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { | |
| 4544 | const mod = self.bin_file.options.module.?; | |
| 4545 | const ty = self.typeOf(ref); | |
| 4541 | 4546 | |
| 4542 | 4547 | // If the type has no codegen bits, no need to store it. |
| 4543 | const inst_ty = self.air.typeOf(inst); | |
| 4544 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) | |
| 4545 | return MCValue{ .none = {} }; | |
| 4546 | ||
| 4547 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); | |
| 4548 | switch (self.air.instructions.items(.tag)[inst_index]) { | |
| 4549 | .constant => { | |
| 4550 | // Constants have static lifetimes, so they are always memoized in the outer most table. | |
| 4551 | const branch = &self.branch_stack.items[0]; | |
| 4552 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); | |
| 4553 | if (!gop.found_existing) { | |
| 4554 | const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl; | |
| 4555 | gop.value_ptr.* = try self.genTypedValue(.{ | |
| 4556 | .ty = inst_ty, | |
| 4557 | .val = self.air.values[ty_pl.payload], | |
| 4558 | }); | |
| 4559 | } | |
| 4560 | return gop.value_ptr.*; | |
| 4561 | }, | |
| 4562 | .const_ty => unreachable, | |
| 4563 | else => return self.getResolvedInstValue(inst_index), | |
| 4548 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; | |
| 4549 | ||
| 4550 | if (Air.refToIndex(ref)) |inst| { | |
| 4551 | switch (self.air.instructions.items(.tag)[inst]) { | |
| 4552 | .interned => { | |
| 4553 | // Constants have static lifetimes, so they are always memoized in the outer most table. | |
| 4554 | const branch = &self.branch_stack.items[0]; | |
| 4555 | const gop = try branch.inst_table.getOrPut(self.gpa, inst); | |
| 4556 | if (!gop.found_existing) { | |
| 4557 | const interned = self.air.instructions.items(.data)[inst].interned; | |
| 4558 | gop.value_ptr.* = try self.genTypedValue(.{ | |
| 4559 | .ty = ty, | |
| 4560 | .val = interned.toValue(), | |
| 4561 | }); | |
| 4562 | } | |
| 4563 | return gop.value_ptr.*; | |
| 4564 | }, | |
| 4565 | else => return self.getResolvedInstValue(inst), | |
| 4566 | } | |
| 4564 | 4567 | } |
| 4568 | ||
| 4569 | return self.genTypedValue(.{ | |
| 4570 | .ty = ty, | |
| 4571 | .val = (try self.air.value(ref, mod)).?, | |
| 4572 | }); | |
| 4565 | 4573 | } |
| 4566 | 4574 | |
| 4567 | 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 | 4578 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 4570 | 4579 | |
| 4571 | 4580 | // Just add space for a branch instruction, patch this later |
| ... | ... | @@ -4638,7 +4647,7 @@ fn spillConditionFlagsIfOccupied(self: *Self) !void { |
| 4638 | 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 | 4651 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); |
| 4643 | 4652 | |
| 4644 | 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 | 4671 | assert(reg == reg_mcv.register); |
| 4663 | 4672 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 4664 | 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 | 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 | 4681 | switch (ptr) { |
| 4672 | 4682 | .none => unreachable, |
| ... | ... | @@ -4707,10 +4717,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 4707 | 4717 | |
| 4708 | 4718 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 4709 | 4719 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 4720 | const mod = self.bin_file.options.module.?; | |
| 4710 | 4721 | const mcv = try self.resolveInst(operand); |
| 4711 | const ptr_ty = self.air.typeOf(operand); | |
| 4712 | const struct_ty = ptr_ty.childType(); | |
| 4713 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | |
| 4722 | const ptr_ty = self.typeOf(operand); | |
| 4723 | const struct_ty = ptr_ty.childType(mod); | |
| 4724 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); | |
| 4714 | 4725 | switch (mcv) { |
| 4715 | 4726 | .ptr_stack_offset => |off| { |
| 4716 | 4727 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| ... | ... | @@ -4748,8 +4759,9 @@ fn trunc( |
| 4748 | 4759 | operand_ty: Type, |
| 4749 | 4760 | dest_ty: Type, |
| 4750 | 4761 | ) !MCValue { |
| 4751 | const info_a = operand_ty.intInfo(self.target.*); | |
| 4752 | const info_b = dest_ty.intInfo(self.target.*); | |
| 4762 | const mod = self.bin_file.options.module.?; | |
| 4763 | const info_a = operand_ty.intInfo(mod); | |
| 4764 | const info_b = dest_ty.intInfo(mod); | |
| 4753 | 4765 | |
| 4754 | 4766 | if (info_b.bits <= 64) { |
| 4755 | 4767 | const operand_reg = switch (operand) { |
| ... | ... | @@ -4866,3 +4878,13 @@ fn wantSafety(self: *Self) bool { |
| 4866 | 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 | 11 | |
| 12 | 12 | const codegen = @import("../../codegen.zig"); |
| 13 | 13 | const Module = @import("../../Module.zig"); |
| 14 | const InternPool = @import("../../InternPool.zig"); | |
| 14 | 15 | const Decl = Module.Decl; |
| 15 | 16 | const Type = @import("../../type.zig").Type; |
| 16 | 17 | const Value = @import("../../value.zig").Value; |
| ... | ... | @@ -764,8 +765,9 @@ pub fn deinit(func: *CodeGen) void { |
| 764 | 765 | |
| 765 | 766 | /// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig |
| 766 | 767 | fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError { |
| 768 | const mod = func.bin_file.base.options.module.?; | |
| 767 | 769 | const src = LazySrcLoc.nodeOffset(0); |
| 768 | const src_loc = src.toSrcLoc(func.decl); | |
| 770 | const src_loc = src.toSrcLoc(func.decl, mod); | |
| 769 | 771 | func.err_msg = try Module.ErrorMsg.create(func.gpa, src_loc, fmt, args); |
| 770 | 772 | return error.CodegenFail; |
| 771 | 773 | } |
| ... | ... | @@ -788,9 +790,10 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { |
| 788 | 790 | const gop = try func.branches.items[0].values.getOrPut(func.gpa, ref); |
| 789 | 791 | assert(!gop.found_existing); |
| 790 | 792 | |
| 791 | const val = func.air.value(ref).?; | |
| 792 | const ty = func.air.typeOf(ref); | |
| 793 | if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt() and !ty.isError()) { | |
| 793 | const mod = func.bin_file.base.options.module.?; | |
| 794 | const val = (try func.air.value(ref, mod)).?; | |
| 795 | const ty = func.typeOf(ref); | |
| 796 | if (!ty.hasRuntimeBitsIgnoreComptime(mod) and !ty.isInt(mod) and !ty.isError(mod)) { | |
| 794 | 797 | gop.value_ptr.* = WValue{ .none = {} }; |
| 795 | 798 | return gop.value_ptr.*; |
| 796 | 799 | } |
| ... | ... | @@ -801,7 +804,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { |
| 801 | 804 | // |
| 802 | 805 | // In the other cases, we will simply lower the constant to a value that fits |
| 803 | 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 | 808 | const sym_index = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, func.decl_index); |
| 806 | 809 | break :blk WValue{ .memory = sym_index }; |
| 807 | 810 | } else try func.lowerConstant(val, ty); |
| ... | ... | @@ -880,7 +883,7 @@ fn iterateBigTomb(func: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !B |
| 880 | 883 | |
| 881 | 884 | fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void { |
| 882 | 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 | 887 | // Branches are currently only allowed to free locals allocated |
| 885 | 888 | // within their own branch. |
| 886 | 889 | // TODO: Upon branch consolidation free any locals if needed. |
| ... | ... | @@ -987,8 +990,9 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 |
| 987 | 990 | } |
| 988 | 991 | |
| 989 | 992 | /// Using a given `Type`, returns the corresponding type |
| 990 | fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { | |
| 991 | return switch (ty.zigTypeTag()) { | |
| 993 | fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { | |
| 994 | const target = mod.getTarget(); | |
| 995 | return switch (ty.zigTypeTag(mod)) { | |
| 992 | 996 | .Float => blk: { |
| 993 | 997 | const bits = ty.floatBits(target); |
| 994 | 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 | 1002 | return wasm.Valtype.i32; // represented as pointer to stack |
| 999 | 1003 | }, |
| 1000 | 1004 | .Int, .Enum => blk: { |
| 1001 | const info = ty.intInfo(target); | |
| 1005 | const info = ty.intInfo(mod); | |
| 1002 | 1006 | if (info.bits <= 32) break :blk wasm.Valtype.i32; |
| 1003 | 1007 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; |
| 1004 | 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 | 1011 | .Packed => { |
| 1008 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 1009 | return typeToValtype(struct_obj.backing_int_ty, target); | |
| 1012 | const struct_obj = mod.typeToStruct(ty).?; | |
| 1013 | return typeToValtype(struct_obj.backing_int_ty, mod); | |
| 1010 | 1014 | }, |
| 1011 | 1015 | else => wasm.Valtype.i32, |
| 1012 | 1016 | }, |
| 1013 | .Vector => switch (determineSimdStoreStrategy(ty, target)) { | |
| 1017 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { | |
| 1014 | 1018 | .direct => wasm.Valtype.v128, |
| 1015 | 1019 | .unrolled => wasm.Valtype.i32, |
| 1016 | 1020 | }, |
| 1017 | .Union => switch (ty.containerLayout()) { | |
| 1021 | .Union => switch (ty.containerLayout(mod)) { | |
| 1018 | 1022 | .Packed => { |
| 1019 | var int_ty_payload: Type.Payload.Bits = .{ | |
| 1020 | .base = .{ .tag = .int_unsigned }, | |
| 1021 | .data = @intCast(u16, ty.bitSize(target)), | |
| 1022 | }; | |
| 1023 | const int_ty = Type.initPayload(&int_ty_payload.base); | |
| 1024 | return typeToValtype(int_ty, target); | |
| 1023 | const int_ty = mod.intType(.unsigned, @intCast(u16, ty.bitSize(mod))) catch @panic("out of memory"); | |
| 1024 | return typeToValtype(int_ty, mod); | |
| 1025 | 1025 | }, |
| 1026 | 1026 | else => wasm.Valtype.i32, |
| 1027 | 1027 | }, |
| ... | ... | @@ -1030,17 +1030,17 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { |
| 1030 | 1030 | } |
| 1031 | 1031 | |
| 1032 | 1032 | /// Using a given `Type`, returns the byte representation of its wasm value type |
| 1033 | fn genValtype(ty: Type, target: std.Target) u8 { | |
| 1034 | return wasm.valtype(typeToValtype(ty, target)); | |
| 1033 | fn genValtype(ty: Type, mod: *Module) u8 { | |
| 1034 | return wasm.valtype(typeToValtype(ty, mod)); | |
| 1035 | 1035 | } |
| 1036 | 1036 | |
| 1037 | 1037 | /// Using a given `Type`, returns the corresponding wasm value type |
| 1038 | 1038 | /// Differently from `genValtype` this also allows `void` to create a block |
| 1039 | 1039 | /// with no return type |
| 1040 | fn genBlockType(ty: Type, target: std.Target) u8 { | |
| 1041 | return switch (ty.tag()) { | |
| 1042 | .void, .noreturn => wasm.block_empty, | |
| 1043 | else => genValtype(ty, target), | |
| 1040 | fn genBlockType(ty: Type, mod: *Module) u8 { | |
| 1041 | return switch (ty.ip_index) { | |
| 1042 | .void_type, .noreturn_type => wasm.block_empty, | |
| 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 | 1101 | /// Creates one locals for a given `Type`. |
| 1102 | 1102 | /// Returns a corresponding `Wvalue` with `local` as active tag |
| 1103 | 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 | 1106 | switch (valtype) { |
| 1106 | 1107 | .i32 => if (func.free_locals_i32.popOrNull()) |index| { |
| 1107 | 1108 | log.debug("reusing local ({d}) of type {}", .{ index, valtype }); |
| ... | ... | @@ -1132,7 +1133,8 @@ fn allocLocal(func: *CodeGen, ty: Type) InnerError!WValue { |
| 1132 | 1133 | /// Ensures a new local will be created. This is useful when it's useful |
| 1133 | 1134 | /// to use a zero-initialized local. |
| 1134 | 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 | 1138 | const initial_index = func.local_index; |
| 1137 | 1139 | func.local_index += 1; |
| 1138 | 1140 | return WValue{ .local = .{ .value = initial_index, .references = 1 } }; |
| ... | ... | @@ -1140,48 +1142,55 @@ fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue { |
| 1140 | 1142 | |
| 1141 | 1143 | /// Generates a `wasm.Type` from a given function type. |
| 1142 | 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 | 1152 | var temp_params = std.ArrayList(wasm.Valtype).init(gpa); |
| 1145 | 1153 | defer temp_params.deinit(); |
| 1146 | 1154 | var returns = std.ArrayList(wasm.Valtype).init(gpa); |
| 1147 | 1155 | defer returns.deinit(); |
| 1148 | 1156 | |
| 1149 | if (firstParamSRet(cc, return_type, target)) { | |
| 1157 | if (firstParamSRet(cc, return_type, mod)) { | |
| 1150 | 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 | 1160 | if (cc == .C) { |
| 1153 | const res_classes = abi.classifyType(return_type, target); | |
| 1161 | const res_classes = abi.classifyType(return_type, mod); | |
| 1154 | 1162 | assert(res_classes[0] == .direct and res_classes[1] == .none); |
| 1155 | const scalar_type = abi.scalarType(return_type, target); | |
| 1156 | try returns.append(typeToValtype(scalar_type, target)); | |
| 1163 | const scalar_type = abi.scalarType(return_type, mod); | |
| 1164 | try returns.append(typeToValtype(scalar_type, mod)); | |
| 1157 | 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 | 1169 | try returns.append(.i32); |
| 1162 | 1170 | } |
| 1163 | 1171 | |
| 1164 | 1172 | // param types |
| 1165 | for (params) |param_type| { | |
| 1166 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1173 | for (params) |param_type_ip| { | |
| 1174 | const param_type = param_type_ip.toType(); | |
| 1175 | if (!param_type.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1167 | 1176 | |
| 1168 | 1177 | switch (cc) { |
| 1169 | 1178 | .C => { |
| 1170 | const param_classes = abi.classifyType(param_type, target); | |
| 1179 | const param_classes = abi.classifyType(param_type, mod); | |
| 1171 | 1180 | for (param_classes) |class| { |
| 1172 | 1181 | if (class == .none) continue; |
| 1173 | 1182 | if (class == .direct) { |
| 1174 | const scalar_type = abi.scalarType(param_type, target); | |
| 1175 | try temp_params.append(typeToValtype(scalar_type, target)); | |
| 1183 | const scalar_type = abi.scalarType(param_type, mod); | |
| 1184 | try temp_params.append(typeToValtype(scalar_type, mod)); | |
| 1176 | 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 | 1191 | try temp_params.append(.i32) |
| 1183 | 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 | 1203 | pub fn generate( |
| 1195 | 1204 | bin_file: *link.File, |
| 1196 | 1205 | src_loc: Module.SrcLoc, |
| 1197 | func: *Module.Fn, | |
| 1206 | func_index: Module.Fn.Index, | |
| 1198 | 1207 | air: Air, |
| 1199 | 1208 | liveness: Liveness, |
| 1200 | 1209 | code: *std.ArrayList(u8), |
| 1201 | 1210 | debug_output: codegen.DebugInfoOutput, |
| 1202 | 1211 | ) codegen.CodeGenError!codegen.Result { |
| 1203 | 1212 | _ = src_loc; |
| 1213 | const mod = bin_file.options.module.?; | |
| 1214 | const func = mod.funcPtr(func_index); | |
| 1204 | 1215 | var code_gen: CodeGen = .{ |
| 1205 | 1216 | .gpa = bin_file.allocator, |
| 1206 | 1217 | .air = air, |
| 1207 | 1218 | .liveness = liveness, |
| 1208 | 1219 | .code = code, |
| 1209 | 1220 | .decl_index = func.owner_decl, |
| 1210 | .decl = bin_file.options.module.?.declPtr(func.owner_decl), | |
| 1221 | .decl = mod.declPtr(func.owner_decl), | |
| 1211 | 1222 | .err_msg = undefined, |
| 1212 | 1223 | .locals = .{}, |
| 1213 | 1224 | .target = bin_file.options.target, |
| ... | ... | @@ -1226,8 +1237,9 @@ pub fn generate( |
| 1226 | 1237 | } |
| 1227 | 1238 | |
| 1228 | 1239 | fn genFunc(func: *CodeGen) InnerError!void { |
| 1229 | const fn_info = func.decl.ty.fnInfo(); | |
| 1230 | var func_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type, func.target); | |
| 1240 | const mod = func.bin_file.base.options.module.?; | |
| 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 | 1243 | defer func_type.deinit(func.gpa); |
| 1232 | 1244 | _ = try func.bin_file.storeDeclType(func.decl_index, func_type); |
| 1233 | 1245 | |
| ... | ... | @@ -1253,8 +1265,8 @@ fn genFunc(func: *CodeGen) InnerError!void { |
| 1253 | 1265 | // we emit an unreachable instruction to tell the stack validator that part will never be reached. |
| 1254 | 1266 | if (func_type.returns.len != 0 and func.air.instructions.len > 0) { |
| 1255 | 1267 | const inst = @intCast(u32, func.air.instructions.len - 1); |
| 1256 | const last_inst_ty = func.air.typeOfIndex(inst); | |
| 1257 | if (!last_inst_ty.hasRuntimeBitsIgnoreComptime() or last_inst_ty.isNoReturn()) { | |
| 1268 | const last_inst_ty = func.typeOfIndex(inst); | |
| 1269 | if (!last_inst_ty.hasRuntimeBitsIgnoreComptime(mod) or last_inst_ty.isNoReturn(mod)) { | |
| 1258 | 1270 | try func.addTag(.@"unreachable"); |
| 1259 | 1271 | } |
| 1260 | 1272 | } |
| ... | ... | @@ -1335,10 +1347,9 @@ const CallWValues = struct { |
| 1335 | 1347 | }; |
| 1336 | 1348 | |
| 1337 | 1349 | fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWValues { |
| 1338 | const cc = fn_ty.fnCallingConvention(); | |
| 1339 | const param_types = try func.gpa.alloc(Type, fn_ty.fnParamLen()); | |
| 1340 | defer func.gpa.free(param_types); | |
| 1341 | fn_ty.fnParamTypes(param_types); | |
| 1350 | const mod = func.bin_file.base.options.module.?; | |
| 1351 | const fn_info = mod.typeToFunc(fn_ty).?; | |
| 1352 | const cc = fn_info.cc; | |
| 1342 | 1353 | var result: CallWValues = .{ |
| 1343 | 1354 | .args = &.{}, |
| 1344 | 1355 | .return_value = .none, |
| ... | ... | @@ -1350,8 +1361,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV |
| 1350 | 1361 | |
| 1351 | 1362 | // Check if we store the result as a pointer to the stack rather than |
| 1352 | 1363 | // by value |
| 1353 | const fn_info = fn_ty.fnInfo(); | |
| 1354 | if (firstParamSRet(fn_info.cc, fn_info.return_type, func.target)) { | |
| 1364 | if (firstParamSRet(fn_info.cc, fn_info.return_type.toType(), mod)) { | |
| 1355 | 1365 | // the sret arg will be passed as first argument, therefore we |
| 1356 | 1366 | // set the `return_value` before allocating locals for regular args. |
| 1357 | 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 | 1370 | |
| 1361 | 1371 | switch (cc) { |
| 1362 | 1372 | .Unspecified => { |
| 1363 | for (param_types) |ty| { | |
| 1364 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1373 | for (fn_info.param_types) |ty| { | |
| 1374 | if (!ty.toType().hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1365 | 1375 | continue; |
| 1366 | 1376 | } |
| 1367 | 1377 | |
| ... | ... | @@ -1370,8 +1380,8 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV |
| 1370 | 1380 | } |
| 1371 | 1381 | }, |
| 1372 | 1382 | .C => { |
| 1373 | for (param_types) |ty| { | |
| 1374 | const ty_classes = abi.classifyType(ty, func.target); | |
| 1383 | for (fn_info.param_types) |ty| { | |
| 1384 | const ty_classes = abi.classifyType(ty.toType(), mod); | |
| 1375 | 1385 | for (ty_classes) |class| { |
| 1376 | 1386 | if (class == .none) continue; |
| 1377 | 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 | 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 | 1399 | switch (cc) { |
| 1390 | .Unspecified, .Inline => return isByRef(return_type, target), | |
| 1400 | .Unspecified, .Inline => return isByRef(return_type, mod), | |
| 1391 | 1401 | .C => { |
| 1392 | const ty_classes = abi.classifyType(return_type, target); | |
| 1402 | const ty_classes = abi.classifyType(return_type, mod); | |
| 1393 | 1403 | if (ty_classes[0] == .indirect) return true; |
| 1394 | 1404 | if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true; |
| 1395 | 1405 | return false; |
| ... | ... | @@ -1405,16 +1415,17 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: |
| 1405 | 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 | 1420 | assert(ty_classes[0] != .none); |
| 1410 | switch (ty.zigTypeTag()) { | |
| 1421 | switch (ty.zigTypeTag(mod)) { | |
| 1411 | 1422 | .Struct, .Union => { |
| 1412 | 1423 | if (ty_classes[0] == .indirect) { |
| 1413 | 1424 | return func.lowerToStack(value); |
| 1414 | 1425 | } |
| 1415 | 1426 | assert(ty_classes[0] == .direct); |
| 1416 | const scalar_type = abi.scalarType(ty, func.target); | |
| 1417 | const abi_size = scalar_type.abiSize(func.target); | |
| 1427 | const scalar_type = abi.scalarType(ty, mod); | |
| 1428 | const abi_size = scalar_type.abiSize(mod); | |
| 1418 | 1429 | try func.emitWValue(value); |
| 1419 | 1430 | |
| 1420 | 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 | 1433 | const opcode = buildOpcode(.{ |
| 1423 | 1434 | .op = .load, |
| 1424 | 1435 | .width = @intCast(u8, abi_size), |
| 1425 | .signedness = if (scalar_type.isSignedInt()) .signed else .unsigned, | |
| 1426 | .valtype1 = typeToValtype(scalar_type, func.target), | |
| 1436 | .signedness = if (scalar_type.isSignedInt(mod)) .signed else .unsigned, | |
| 1437 | .valtype1 = typeToValtype(scalar_type, mod), | |
| 1427 | 1438 | }); |
| 1428 | 1439 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 1429 | 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 | 1447 | return func.lowerToStack(value); |
| 1437 | 1448 | } |
| 1438 | 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 | 1451 | // in this case we have an integer or float that must be lowered as 2 i64's. |
| 1441 | 1452 | try func.emitWValue(value); |
| 1442 | 1453 | try func.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 8 }); |
| ... | ... | @@ -1503,18 +1514,18 @@ fn restoreStackPointer(func: *CodeGen) !void { |
| 1503 | 1514 | /// |
| 1504 | 1515 | /// Asserts Type has codegenbits |
| 1505 | 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 | 1519 | if (func.initial_stack_value == .none) { |
| 1508 | 1520 | try func.initializeStack(); |
| 1509 | 1521 | } |
| 1510 | 1522 | |
| 1511 | const abi_size = std.math.cast(u32, ty.abiSize(func.target)) orelse { | |
| 1512 | const module = func.bin_file.base.options.module.?; | |
| 1523 | const abi_size = std.math.cast(u32, ty.abiSize(mod)) orelse { | |
| 1513 | 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 | 1530 | if (abi_align > func.stack_alignment) { |
| 1520 | 1531 | func.stack_alignment = abi_align; |
| ... | ... | @@ -1531,22 +1542,22 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue { |
| 1531 | 1542 | /// This is different from allocStack where this will use the pointer's alignment |
| 1532 | 1543 | /// if it is set, to ensure the stack alignment will be set correctly. |
| 1533 | 1544 | fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue { |
| 1534 | const ptr_ty = func.air.typeOfIndex(inst); | |
| 1535 | const pointee_ty = ptr_ty.childType(); | |
| 1545 | const mod = func.bin_file.base.options.module.?; | |
| 1546 | const ptr_ty = func.typeOfIndex(inst); | |
| 1547 | const pointee_ty = ptr_ty.childType(mod); | |
| 1536 | 1548 | |
| 1537 | 1549 | if (func.initial_stack_value == .none) { |
| 1538 | 1550 | try func.initializeStack(); |
| 1539 | 1551 | } |
| 1540 | 1552 | |
| 1541 | if (!pointee_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1553 | if (!pointee_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1542 | 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); | |
| 1546 | const abi_size = std.math.cast(u32, pointee_ty.abiSize(func.target)) orelse { | |
| 1547 | const module = func.bin_file.base.options.module.?; | |
| 1557 | const abi_alignment = ptr_ty.ptrAlignment(mod); | |
| 1558 | const abi_size = std.math.cast(u32, pointee_ty.abiSize(mod)) orelse { | |
| 1548 | 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 | 1563 | if (abi_alignment > func.stack_alignment) { |
| ... | ... | @@ -1704,8 +1715,9 @@ fn arch(func: *const CodeGen) std.Target.Cpu.Arch { |
| 1704 | 1715 | |
| 1705 | 1716 | /// For a given `Type`, will return true when the type will be passed |
| 1706 | 1717 | /// by reference, rather than by value |
| 1707 | fn isByRef(ty: Type, target: std.Target) bool { | |
| 1708 | switch (ty.zigTypeTag()) { | |
| 1718 | fn isByRef(ty: Type, mod: *Module) bool { | |
| 1719 | const target = mod.getTarget(); | |
| 1720 | switch (ty.zigTypeTag(mod)) { | |
| 1709 | 1721 | .Type, |
| 1710 | 1722 | .ComptimeInt, |
| 1711 | 1723 | .ComptimeFloat, |
| ... | ... | @@ -1726,44 +1738,42 @@ fn isByRef(ty: Type, target: std.Target) bool { |
| 1726 | 1738 | |
| 1727 | 1739 | .Array, |
| 1728 | 1740 | .Frame, |
| 1729 | => return ty.hasRuntimeBitsIgnoreComptime(), | |
| 1741 | => return ty.hasRuntimeBitsIgnoreComptime(mod), | |
| 1730 | 1742 | .Union => { |
| 1731 | if (ty.castTag(.@"union")) |union_ty| { | |
| 1732 | if (union_ty.data.layout == .Packed) { | |
| 1733 | return ty.abiSize(target) > 8; | |
| 1743 | if (mod.typeToUnion(ty)) |union_obj| { | |
| 1744 | if (union_obj.layout == .Packed) { | |
| 1745 | return ty.abiSize(mod) > 8; | |
| 1734 | 1746 | } |
| 1735 | 1747 | } |
| 1736 | return ty.hasRuntimeBitsIgnoreComptime(); | |
| 1748 | return ty.hasRuntimeBitsIgnoreComptime(mod); | |
| 1737 | 1749 | }, |
| 1738 | 1750 | .Struct => { |
| 1739 | if (ty.castTag(.@"struct")) |struct_ty| { | |
| 1740 | const struct_obj = struct_ty.data; | |
| 1751 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 1741 | 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, | |
| 1748 | .Int => return ty.intInfo(target).bits > 64, | |
| 1758 | .Vector => return determineSimdStoreStrategy(ty, mod) == .unrolled, | |
| 1759 | .Int => return ty.intInfo(mod).bits > 64, | |
| 1749 | 1760 | .Float => return ty.floatBits(target) > 64, |
| 1750 | 1761 | .ErrorUnion => { |
| 1751 | const pl_ty = ty.errorUnionPayload(); | |
| 1752 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1762 | const pl_ty = ty.errorUnionPayload(mod); | |
| 1763 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1753 | 1764 | return false; |
| 1754 | 1765 | } |
| 1755 | 1766 | return true; |
| 1756 | 1767 | }, |
| 1757 | 1768 | .Optional => { |
| 1758 | if (ty.isPtrLikeOptional()) return false; | |
| 1759 | var buf: Type.Payload.ElemType = undefined; | |
| 1760 | const pl_type = ty.optionalChild(&buf); | |
| 1761 | if (pl_type.zigTypeTag() == .ErrorSet) return false; | |
| 1762 | return pl_type.hasRuntimeBitsIgnoreComptime(); | |
| 1769 | if (ty.isPtrLikeOptional(mod)) return false; | |
| 1770 | const pl_type = ty.optionalChild(mod); | |
| 1771 | if (pl_type.zigTypeTag(mod) == .ErrorSet) return false; | |
| 1772 | return pl_type.hasRuntimeBitsIgnoreComptime(mod); | |
| 1763 | 1773 | }, |
| 1764 | 1774 | .Pointer => { |
| 1765 | 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 | 1777 | return false; |
| 1768 | 1778 | }, |
| 1769 | 1779 | } |
| ... | ... | @@ -1778,10 +1788,11 @@ const SimdStoreStrategy = enum { |
| 1778 | 1788 | /// This means when a given type is 128 bits and either the simd128 or relaxed-simd |
| 1779 | 1789 | /// features are enabled, the function will return `.direct`. This would allow to store |
| 1780 | 1790 | /// it using a instruction, rather than an unrolled version. |
| 1781 | fn determineSimdStoreStrategy(ty: Type, target: std.Target) SimdStoreStrategy { | |
| 1782 | std.debug.assert(ty.zigTypeTag() == .Vector); | |
| 1783 | if (ty.bitSize(target) != 128) return .unrolled; | |
| 1791 | fn determineSimdStoreStrategy(ty: Type, mod: *Module) SimdStoreStrategy { | |
| 1792 | std.debug.assert(ty.zigTypeTag(mod) == .Vector); | |
| 1793 | if (ty.bitSize(mod) != 128) return .unrolled; | |
| 1784 | 1794 | const hasFeature = std.Target.wasm.featureSetHas; |
| 1795 | const target = mod.getTarget(); | |
| 1785 | 1796 | const features = target.cpu.features; |
| 1786 | 1797 | if (hasFeature(features, .relaxed_simd) or hasFeature(features, .simd128)) { |
| 1787 | 1798 | return .direct; |
| ... | ... | @@ -1821,8 +1832,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en |
| 1821 | 1832 | fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1822 | 1833 | const air_tags = func.air.instructions.items(.tag); |
| 1823 | 1834 | return switch (air_tags[inst]) { |
| 1824 | .constant => unreachable, | |
| 1825 | .const_ty => unreachable, | |
| 1835 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 1826 | 1836 | |
| 1827 | 1837 | .add => func.airBinOp(inst, .add), |
| 1828 | 1838 | .add_sat => func.airSatBinOp(inst, .add), |
| ... | ... | @@ -2062,8 +2072,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2062 | 2072 | } |
| 2063 | 2073 | |
| 2064 | 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 | 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 | 2080 | continue; |
| 2068 | 2081 | } |
| 2069 | 2082 | const old_bookkeeping_value = func.air_bookkeeping; |
| ... | ... | @@ -2080,36 +2093,37 @@ fn genBody(func: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2080 | 2093 | } |
| 2081 | 2094 | |
| 2082 | 2095 | fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2096 | const mod = func.bin_file.base.options.module.?; | |
| 2083 | 2097 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 2084 | 2098 | const operand = try func.resolveInst(un_op); |
| 2085 | const fn_info = func.decl.ty.fnInfo(); | |
| 2086 | const ret_ty = fn_info.return_type; | |
| 2099 | const fn_info = mod.typeToFunc(func.decl.ty).?; | |
| 2100 | const ret_ty = fn_info.return_type.toType(); | |
| 2087 | 2101 | |
| 2088 | 2102 | // result must be stored in the stack and we return a pointer |
| 2089 | 2103 | // to the stack instead |
| 2090 | 2104 | if (func.return_value != .none) { |
| 2091 | 2105 | try func.store(func.return_value, operand, ret_ty, 0); |
| 2092 | } else if (fn_info.cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2093 | switch (ret_ty.zigTypeTag()) { | |
| 2106 | } else if (fn_info.cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2107 | switch (ret_ty.zigTypeTag(mod)) { | |
| 2094 | 2108 | // Aggregate types can be lowered as a singular value |
| 2095 | 2109 | .Struct, .Union => { |
| 2096 | const scalar_type = abi.scalarType(ret_ty, func.target); | |
| 2110 | const scalar_type = abi.scalarType(ret_ty, mod); | |
| 2097 | 2111 | try func.emitWValue(operand); |
| 2098 | 2112 | const opcode = buildOpcode(.{ |
| 2099 | 2113 | .op = .load, |
| 2100 | .width = @intCast(u8, scalar_type.abiSize(func.target) * 8), | |
| 2101 | .signedness = if (scalar_type.isSignedInt()) .signed else .unsigned, | |
| 2102 | .valtype1 = typeToValtype(scalar_type, func.target), | |
| 2114 | .width = @intCast(u8, scalar_type.abiSize(mod) * 8), | |
| 2115 | .signedness = if (scalar_type.isSignedInt(mod)) .signed else .unsigned, | |
| 2116 | .valtype1 = typeToValtype(scalar_type, mod), | |
| 2103 | 2117 | }); |
| 2104 | 2118 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 2105 | 2119 | .offset = operand.offset(), |
| 2106 | .alignment = scalar_type.abiAlignment(func.target), | |
| 2120 | .alignment = scalar_type.abiAlignment(mod), | |
| 2107 | 2121 | }); |
| 2108 | 2122 | }, |
| 2109 | 2123 | else => try func.emitWValue(operand), |
| 2110 | 2124 | } |
| 2111 | 2125 | } else { |
| 2112 | if (!ret_ty.hasRuntimeBitsIgnoreComptime() and ret_ty.isError()) { | |
| 2126 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod) and ret_ty.isError(mod)) { | |
| 2113 | 2127 | try func.addImm32(0); |
| 2114 | 2128 | } else { |
| 2115 | 2129 | try func.emitWValue(operand); |
| ... | ... | @@ -2122,15 +2136,16 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2122 | 2136 | } |
| 2123 | 2137 | |
| 2124 | 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 | 2142 | var result = result: { |
| 2128 | if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime()) { | |
| 2143 | if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { | |
| 2129 | 2144 | break :result try func.allocStack(Type.usize); // create pointer to void |
| 2130 | 2145 | } |
| 2131 | 2146 | |
| 2132 | const fn_info = func.decl.ty.fnInfo(); | |
| 2133 | if (firstParamSRet(fn_info.cc, fn_info.return_type, func.target)) { | |
| 2147 | const fn_info = mod.typeToFunc(func.decl.ty).?; | |
| 2148 | if (firstParamSRet(fn_info.cc, fn_info.return_type.toType(), mod)) { | |
| 2134 | 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 | 2156 | } |
| 2142 | 2157 | |
| 2143 | 2158 | fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2159 | const mod = func.bin_file.base.options.module.?; | |
| 2144 | 2160 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 2145 | 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(); | |
| 2149 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2150 | if (ret_ty.isError()) { | |
| 2164 | const fn_info = mod.typeToFunc(func.decl.ty).?; | |
| 2165 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2166 | if (ret_ty.isError(mod)) { | |
| 2151 | 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 | 2170 | // leave on the stack |
| 2155 | 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 | 2181 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 2166 | 2182 | const extra = func.air.extraData(Air.Call, pl_op.payload); |
| 2167 | 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 | 2188 | .Fn => ty, |
| 2172 | .Pointer => ty.childType(), | |
| 2189 | .Pointer => ty.childType(mod), | |
| 2173 | 2190 | else => unreachable, |
| 2174 | 2191 | }; |
| 2175 | const ret_ty = fn_ty.fnReturnType(); | |
| 2176 | const fn_info = fn_ty.fnInfo(); | |
| 2177 | const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type, func.target); | |
| 2192 | const ret_ty = fn_ty.fnReturnType(mod); | |
| 2193 | const fn_info = mod.typeToFunc(fn_ty).?; | |
| 2194 | const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type.toType(), mod); | |
| 2178 | 2195 | |
| 2179 | 2196 | const callee: ?Decl.Index = blk: { |
| 2180 | const func_val = func.air.value(pl_op.operand) orelse break :blk null; | |
| 2181 | const module = func.bin_file.base.options.module.?; | |
| 2182 | ||
| 2183 | if (func_val.castTag(.function)) |function| { | |
| 2184 | _ = try func.bin_file.getOrCreateAtomForDecl(function.data.owner_decl); | |
| 2185 | break :blk function.data.owner_decl; | |
| 2186 | } else if (func_val.castTag(.extern_fn)) |extern_fn| { | |
| 2187 | const ext_decl = module.declPtr(extern_fn.data.owner_decl); | |
| 2188 | const ext_info = ext_decl.ty.fnInfo(); | |
| 2189 | var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target); | |
| 2197 | const func_val = (try func.air.value(pl_op.operand, mod)) orelse break :blk null; | |
| 2198 | ||
| 2199 | if (func_val.getFunction(mod)) |function| { | |
| 2200 | _ = try func.bin_file.getOrCreateAtomForDecl(function.owner_decl); | |
| 2201 | break :blk function.owner_decl; | |
| 2202 | } else if (func_val.getExternFunc(mod)) |extern_func| { | |
| 2203 | const ext_decl = mod.declPtr(extern_func.decl); | |
| 2204 | const ext_info = mod.typeToFunc(ext_decl.ty).?; | |
| 2205 | var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type.toType(), mod); | |
| 2190 | 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 | 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 | 2210 | try func.bin_file.addOrUpdateImport( |
| 2195 | mem.sliceTo(ext_decl.name, 0), | |
| 2211 | mod.intern_pool.stringToSlice(ext_decl.name), | |
| 2196 | 2212 | atom.getSymbolIndex().?, |
| 2197 | ext_decl.getExternFn().?.lib_name, | |
| 2213 | mod.intern_pool.stringToSliceUnwrap(ext_decl.getOwnedExternFunc(mod).?.lib_name), | |
| 2198 | 2214 | type_index, |
| 2199 | 2215 | ); |
| 2200 | break :blk extern_fn.data.owner_decl; | |
| 2201 | } else if (func_val.castTag(.decl_ref)) |decl_ref| { | |
| 2202 | _ = try func.bin_file.getOrCreateAtomForDecl(decl_ref.data); | |
| 2203 | break :blk decl_ref.data; | |
| 2216 | break :blk extern_func.decl; | |
| 2217 | } else switch (mod.intern_pool.indexToKey(func_val.ip_index)) { | |
| 2218 | .ptr => |ptr| switch (ptr.addr) { | |
| 2219 | .decl => |decl| { | |
| 2220 | _ = try func.bin_file.getOrCreateAtomForDecl(decl); | |
| 2221 | break :blk decl; | |
| 2222 | }, | |
| 2223 | else => {}, | |
| 2224 | }, | |
| 2225 | else => {}, | |
| 2204 | 2226 | } |
| 2205 | 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 | 2236 | for (args) |arg| { |
| 2215 | 2237 | const arg_val = try func.resolveInst(arg); |
| 2216 | 2238 | |
| 2217 | const arg_ty = func.air.typeOf(arg); | |
| 2218 | if (!arg_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2239 | const arg_ty = func.typeOf(arg); | |
| 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 | 2245 | if (callee) |direct| { |
| ... | ... | @@ -2226,11 +2248,11 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif |
| 2226 | 2248 | } else { |
| 2227 | 2249 | // in this case we call a function pointer |
| 2228 | 2250 | // so load its value onto the stack |
| 2229 | std.debug.assert(ty.zigTypeTag() == .Pointer); | |
| 2251 | std.debug.assert(ty.zigTypeTag(mod) == .Pointer); | |
| 2230 | 2252 | const operand = try func.resolveInst(pl_op.operand); |
| 2231 | 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 | 2256 | defer fn_type.deinit(func.gpa); |
| 2235 | 2257 | |
| 2236 | 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 | 2260 | } |
| 2239 | 2261 | |
| 2240 | 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 | 2264 | break :result_value WValue{ .none = {} }; |
| 2243 | } else if (ret_ty.isNoReturn()) { | |
| 2265 | } else if (ret_ty.isNoReturn(mod)) { | |
| 2244 | 2266 | try func.addTag(.@"unreachable"); |
| 2245 | 2267 | break :result_value WValue{ .none = {} }; |
| 2246 | 2268 | } else if (first_param_sret) { |
| 2247 | 2269 | break :result_value sret; |
| 2248 | 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 | 2272 | const result_local = try func.allocLocal(ret_ty); |
| 2251 | 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 | 2275 | const result = try func.allocStack(scalar_type); |
| 2254 | 2276 | try func.store(result, result_local, scalar_type, 0); |
| 2255 | 2277 | break :result_value result; |
| ... | ... | @@ -2272,6 +2294,7 @@ fn airAlloc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2272 | 2294 | } |
| 2273 | 2295 | |
| 2274 | 2296 | fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 2297 | const mod = func.bin_file.base.options.module.?; | |
| 2275 | 2298 | if (safety) { |
| 2276 | 2299 | // TODO if the value is undef, write 0xaa bytes to dest |
| 2277 | 2300 | } else { |
| ... | ... | @@ -2281,26 +2304,22 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void |
| 2281 | 2304 | |
| 2282 | 2305 | const lhs = try func.resolveInst(bin_op.lhs); |
| 2283 | 2306 | const rhs = try func.resolveInst(bin_op.rhs); |
| 2284 | const ptr_ty = func.air.typeOf(bin_op.lhs); | |
| 2285 | const ptr_info = ptr_ty.ptrInfo().data; | |
| 2286 | const ty = ptr_ty.childType(); | |
| 2307 | const ptr_ty = func.typeOf(bin_op.lhs); | |
| 2308 | const ptr_info = ptr_ty.ptrInfo(mod); | |
| 2309 | const ty = ptr_ty.childType(mod); | |
| 2287 | 2310 | |
| 2288 | 2311 | if (ptr_info.host_size == 0) { |
| 2289 | 2312 | try func.store(lhs, rhs, ty, 0); |
| 2290 | 2313 | } else { |
| 2291 | 2314 | // at this point we have a non-natural alignment, we must |
| 2292 | 2315 | // load the value, and then shift+or the rhs into the result location. |
| 2293 | var int_ty_payload: Type.Payload.Bits = .{ | |
| 2294 | .base = .{ .tag = .int_unsigned }, | |
| 2295 | .data = ptr_info.host_size * 8, | |
| 2296 | }; | |
| 2297 | const int_elem_ty = Type.initPayload(&int_ty_payload.base); | |
| 2316 | const int_elem_ty = try mod.intType(.unsigned, ptr_info.host_size * 8); | |
| 2298 | 2317 | |
| 2299 | if (isByRef(int_elem_ty, func.target)) { | |
| 2318 | if (isByRef(int_elem_ty, mod)) { | |
| 2300 | 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 | 2323 | mask <<= @intCast(u6, ptr_info.bit_offset); |
| 2305 | 2324 | mask ^= ~@as(u64, 0); |
| 2306 | 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 | 2348 | |
| 2330 | 2349 | fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { |
| 2331 | 2350 | assert(!(lhs != .stack and rhs == .stack)); |
| 2332 | const abi_size = ty.abiSize(func.target); | |
| 2333 | switch (ty.zigTypeTag()) { | |
| 2351 | const mod = func.bin_file.base.options.module.?; | |
| 2352 | const abi_size = ty.abiSize(mod); | |
| 2353 | switch (ty.zigTypeTag(mod)) { | |
| 2334 | 2354 | .ErrorUnion => { |
| 2335 | const pl_ty = ty.errorUnionPayload(); | |
| 2336 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2355 | const pl_ty = ty.errorUnionPayload(mod); | |
| 2356 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2337 | 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 | 2361 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| 2342 | 2362 | }, |
| 2343 | 2363 | .Optional => { |
| 2344 | if (ty.isPtrLikeOptional()) { | |
| 2364 | if (ty.isPtrLikeOptional(mod)) { | |
| 2345 | 2365 | return func.store(lhs, rhs, Type.usize, 0); |
| 2346 | 2366 | } |
| 2347 | var buf: Type.Payload.ElemType = undefined; | |
| 2348 | const pl_ty = ty.optionalChild(&buf); | |
| 2349 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2367 | const pl_ty = ty.optionalChild(mod); | |
| 2368 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2350 | 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 | 2372 | return func.store(lhs, rhs, Type.anyerror, 0); |
| 2354 | 2373 | } |
| 2355 | 2374 | |
| 2356 | 2375 | const len = @intCast(u32, abi_size); |
| 2357 | 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 | 2379 | const len = @intCast(u32, abi_size); |
| 2361 | 2380 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| 2362 | 2381 | }, |
| 2363 | .Vector => switch (determineSimdStoreStrategy(ty, func.target)) { | |
| 2382 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { | |
| 2364 | 2383 | .unrolled => { |
| 2365 | 2384 | const len = @intCast(u32, abi_size); |
| 2366 | 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 | 2393 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2375 | 2394 | std.wasm.simdOpcode(.v128_store), |
| 2376 | 2395 | offset + lhs.offset(), |
| 2377 | ty.abiAlignment(func.target), | |
| 2396 | ty.abiAlignment(mod), | |
| 2378 | 2397 | }); |
| 2379 | 2398 | return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2380 | 2399 | }, |
| 2381 | 2400 | }, |
| 2382 | 2401 | .Pointer => { |
| 2383 | if (ty.isSlice()) { | |
| 2402 | if (ty.isSlice(mod)) { | |
| 2384 | 2403 | // store pointer first |
| 2385 | 2404 | // lower it to the stack so we do not have to store rhs into a local first |
| 2386 | 2405 | try func.emitWValue(lhs); |
| ... | ... | @@ -2404,7 +2423,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2404 | 2423 | try func.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset()); |
| 2405 | 2424 | return; |
| 2406 | 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 | 2428 | else => if (abi_size > 8) { |
| 2410 | 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 | 2437 | // into lhs, so we calculate that and emit that instead |
| 2419 | 2438 | try func.lowerToStack(rhs); |
| 2420 | 2439 | |
| 2421 | const valtype = typeToValtype(ty, func.target); | |
| 2440 | const valtype = typeToValtype(ty, mod); | |
| 2422 | 2441 | const opcode = buildOpcode(.{ |
| 2423 | 2442 | .valtype1 = valtype, |
| 2424 | 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 | 2447 | // store rhs value at stack pointer's location in memory |
| 2429 | 2448 | try func.addMemArg( |
| 2430 | 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 | 2454 | fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2455 | const mod = func.bin_file.base.options.module.?; | |
| 2436 | 2456 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 2437 | 2457 | const operand = try func.resolveInst(ty_op.operand); |
| 2438 | 2458 | const ty = func.air.getRefType(ty_op.ty); |
| 2439 | const ptr_ty = func.air.typeOf(ty_op.operand); | |
| 2440 | const ptr_info = ptr_ty.ptrInfo().data; | |
| 2459 | const ptr_ty = func.typeOf(ty_op.operand); | |
| 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 | 2464 | const result = result: { |
| 2445 | if (isByRef(ty, func.target)) { | |
| 2465 | if (isByRef(ty, mod)) { | |
| 2446 | 2466 | const new_local = try func.allocStack(ty); |
| 2447 | 2467 | try func.store(new_local, operand, ty, 0); |
| 2448 | 2468 | break :result new_local; |
| ... | ... | @@ -2455,11 +2475,7 @@ fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2455 | 2475 | |
| 2456 | 2476 | // at this point we have a non-natural alignment, we must |
| 2457 | 2477 | // shift the value to obtain the correct bit. |
| 2458 | var int_ty_payload: Type.Payload.Bits = .{ | |
| 2459 | .base = .{ .tag = .int_unsigned }, | |
| 2460 | .data = ptr_info.host_size * 8, | |
| 2461 | }; | |
| 2462 | const int_elem_ty = Type.initPayload(&int_ty_payload.base); | |
| 2478 | const int_elem_ty = try mod.intType(.unsigned, ptr_info.host_size * 8); | |
| 2463 | 2479 | const shift_val = if (ptr_info.host_size <= 4) |
| 2464 | 2480 | WValue{ .imm32 = ptr_info.bit_offset } |
| 2465 | 2481 | else if (ptr_info.host_size <= 8) |
| ... | ... | @@ -2479,25 +2495,26 @@ fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2479 | 2495 | /// Loads an operand from the linear memory section. |
| 2480 | 2496 | /// NOTE: Leaves the value on the stack. |
| 2481 | 2497 | fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 2498 | const mod = func.bin_file.base.options.module.?; | |
| 2482 | 2499 | // load local's value from memory by its stack position |
| 2483 | 2500 | try func.emitWValue(operand); |
| 2484 | 2501 | |
| 2485 | if (ty.zigTypeTag() == .Vector) { | |
| 2502 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2486 | 2503 | // TODO: Add helper functions for simd opcodes |
| 2487 | 2504 | const extra_index = @intCast(u32, func.mir_extra.items.len); |
| 2488 | 2505 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 2489 | 2506 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2490 | 2507 | std.wasm.simdOpcode(.v128_load), |
| 2491 | 2508 | offset + operand.offset(), |
| 2492 | ty.abiAlignment(func.target), | |
| 2509 | ty.abiAlignment(mod), | |
| 2493 | 2510 | }); |
| 2494 | 2511 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2495 | 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 | 2516 | const opcode = buildOpcode(.{ |
| 2500 | .valtype1 = typeToValtype(ty, func.target), | |
| 2517 | .valtype1 = typeToValtype(ty, mod), | |
| 2501 | 2518 | .width = abi_size * 8, |
| 2502 | 2519 | .op = .load, |
| 2503 | 2520 | .signedness = .unsigned, |
| ... | ... | @@ -2505,19 +2522,20 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2505 | 2522 | |
| 2506 | 2523 | try func.addMemArg( |
| 2507 | 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 | 2528 | return WValue{ .stack = {} }; |
| 2512 | 2529 | } |
| 2513 | 2530 | |
| 2514 | 2531 | fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2532 | const mod = func.bin_file.base.options.module.?; | |
| 2515 | 2533 | const arg_index = func.arg_index; |
| 2516 | 2534 | const arg = func.args[arg_index]; |
| 2517 | const cc = func.decl.ty.fnInfo().cc; | |
| 2518 | const arg_ty = func.air.typeOfIndex(inst); | |
| 2535 | const cc = mod.typeToFunc(func.decl.ty).?.cc; | |
| 2536 | const arg_ty = func.typeOfIndex(inst); | |
| 2519 | 2537 | if (cc == .C) { |
| 2520 | const arg_classes = abi.classifyType(arg_ty, func.target); | |
| 2538 | const arg_classes = abi.classifyType(arg_ty, mod); | |
| 2521 | 2539 | for (arg_classes) |class| { |
| 2522 | 2540 | if (class != .none) { |
| 2523 | 2541 | func.arg_index += 1; |
| ... | ... | @@ -2527,7 +2545,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2527 | 2545 | // When we have an argument that's passed using more than a single parameter, |
| 2528 | 2546 | // we combine them into a single stack value |
| 2529 | 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 | 2549 | return func.fail( |
| 2532 | 2550 | "TODO: Implement C-ABI argument for type '{}'", |
| 2533 | 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 | 2575 | } |
| 2558 | 2576 | |
| 2559 | 2577 | fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2578 | const mod = func.bin_file.base.options.module.?; | |
| 2560 | 2579 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 2561 | 2580 | const lhs = try func.resolveInst(bin_op.lhs); |
| 2562 | 2581 | const rhs = try func.resolveInst(bin_op.rhs); |
| 2563 | const lhs_ty = func.air.typeOf(bin_op.lhs); | |
| 2564 | const rhs_ty = func.air.typeOf(bin_op.rhs); | |
| 2582 | const lhs_ty = func.typeOf(bin_op.lhs); | |
| 2583 | const rhs_ty = func.typeOf(bin_op.rhs); | |
| 2565 | 2584 | |
| 2566 | 2585 | // For certain operations, such as shifting, the types are different. |
| 2567 | 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 | 2589 | // For big integers we can ignore this as we will call into compiler-rt which handles this. |
| 2571 | 2590 | const result = switch (op) { |
| 2572 | 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 | 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 | 2596 | const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128) blk: { |
| 2578 | 2597 | const tmp = try func.intcast(rhs, rhs_ty, lhs_ty); |
| 2579 | 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 | 2612 | /// Performs a binary operation on the given `WValue`'s |
| 2594 | 2613 | /// NOTE: THis leaves the value on top of the stack. |
| 2595 | 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 | 2616 | assert(!(lhs != .stack and rhs == .stack)); |
| 2597 | 2617 | |
| 2598 | 2618 | if (ty.isAnyFloat()) { |
| ... | ... | @@ -2600,8 +2620,8 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! |
| 2600 | 2620 | return func.floatOp(float_op, ty, &.{ lhs, rhs }); |
| 2601 | 2621 | } |
| 2602 | 2622 | |
| 2603 | if (isByRef(ty, func.target)) { | |
| 2604 | if (ty.zigTypeTag() == .Int) { | |
| 2623 | if (isByRef(ty, mod)) { | |
| 2624 | if (ty.zigTypeTag(mod) == .Int) { | |
| 2605 | 2625 | return func.binOpBigInt(lhs, rhs, ty, op); |
| 2606 | 2626 | } else { |
| 2607 | 2627 | return func.fail( |
| ... | ... | @@ -2613,8 +2633,8 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! |
| 2613 | 2633 | |
| 2614 | 2634 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 2615 | 2635 | .op = op, |
| 2616 | .valtype1 = typeToValtype(ty, func.target), | |
| 2617 | .signedness = if (ty.isSignedInt()) .signed else .unsigned, | |
| 2636 | .valtype1 = typeToValtype(ty, mod), | |
| 2637 | .signedness = if (ty.isSignedInt(mod)) .signed else .unsigned, | |
| 2618 | 2638 | }); |
| 2619 | 2639 | try func.emitWValue(lhs); |
| 2620 | 2640 | try func.emitWValue(rhs); |
| ... | ... | @@ -2625,14 +2645,15 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! |
| 2625 | 2645 | } |
| 2626 | 2646 | |
| 2627 | 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 | 2650 | return func.fail("TODO: Implement binary operation for big integers larger than 128 bits", .{}); |
| 2630 | 2651 | } |
| 2631 | 2652 | |
| 2632 | 2653 | switch (op) { |
| 2633 | .mul => return func.callIntrinsic("__multi3", &.{ ty, ty }, ty, &.{ lhs, rhs }), | |
| 2634 | .shr => return func.callIntrinsic("__lshrti3", &.{ ty, Type.i32 }, ty, &.{ lhs, rhs }), | |
| 2635 | .shl => return func.callIntrinsic("__ashlti3", &.{ ty, Type.i32 }, ty, &.{ lhs, rhs }), | |
| 2654 | .mul => return func.callIntrinsic("__multi3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), | |
| 2655 | .shr => return func.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), | |
| 2656 | .shl => return func.callIntrinsic("__ashlti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), | |
| 2636 | 2657 | .xor => { |
| 2637 | 2658 | const result = try func.allocStack(ty); |
| 2638 | 2659 | try func.emitWValue(result); |
| ... | ... | @@ -2756,14 +2777,15 @@ const FloatOp = enum { |
| 2756 | 2777 | fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void { |
| 2757 | 2778 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 2758 | 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 | 2782 | const result = try (try func.floatOp(op, ty, &.{operand})).toLocal(func, ty); |
| 2762 | 2783 | func.finishAir(inst, result, &.{un_op}); |
| 2763 | 2784 | } |
| 2764 | 2785 | |
| 2765 | 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 | 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 | 2795 | for (args) |operand| { |
| 2774 | 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 | 2799 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2778 | 2800 | return .stack; |
| 2779 | 2801 | } |
| ... | ... | @@ -2821,20 +2843,21 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In |
| 2821 | 2843 | }; |
| 2822 | 2844 | |
| 2823 | 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 | 2847 | const param_types = param_types_buffer[0..args.len]; |
| 2826 | 2848 | return func.callIntrinsic(fn_name, param_types, ty, args); |
| 2827 | 2849 | } |
| 2828 | 2850 | |
| 2829 | 2851 | fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2852 | const mod = func.bin_file.base.options.module.?; | |
| 2830 | 2853 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 2831 | 2854 | |
| 2832 | 2855 | const lhs = try func.resolveInst(bin_op.lhs); |
| 2833 | 2856 | const rhs = try func.resolveInst(bin_op.rhs); |
| 2834 | const lhs_ty = func.air.typeOf(bin_op.lhs); | |
| 2835 | const rhs_ty = func.air.typeOf(bin_op.rhs); | |
| 2857 | const lhs_ty = func.typeOf(bin_op.lhs); | |
| 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 | 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 | 2868 | // For big integers we can ignore this as we will call into compiler-rt which handles this. |
| 2846 | 2869 | const result = switch (op) { |
| 2847 | 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 | 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 | 2875 | const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128) blk: { |
| 2853 | 2876 | const tmp = try func.intcast(rhs, rhs_ty, lhs_ty); |
| 2854 | 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 | 2900 | /// Asserts `Type` is <= 128 bits. |
| 2878 | 2901 | /// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack. |
| 2879 | 2902 | fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 2880 | assert(ty.abiSize(func.target) <= 16); | |
| 2881 | const bitsize = @intCast(u16, ty.bitSize(func.target)); | |
| 2903 | const mod = func.bin_file.base.options.module.?; | |
| 2904 | assert(ty.abiSize(mod) <= 16); | |
| 2905 | const bitsize = @intCast(u16, ty.bitSize(mod)); | |
| 2882 | 2906 | const wasm_bits = toWasmBits(bitsize) orelse { |
| 2883 | 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 | 2938 | return WValue{ .stack = {} }; |
| 2915 | 2939 | } |
| 2916 | 2940 | |
| 2917 | fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue { | |
| 2918 | switch (ptr_val.tag()) { | |
| 2919 | .decl_ref_mut => { | |
| 2920 | const decl_index = ptr_val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 2921 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | |
| 2941 | fn lowerParentPtr(func: *CodeGen, ptr_val: Value) InnerError!WValue { | |
| 2942 | const mod = func.bin_file.base.options.module.?; | |
| 2943 | const ptr = mod.intern_pool.indexToKey(ptr_val.ip_index).ptr; | |
| 2944 | switch (ptr.addr) { | |
| 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 => { | |
| 2924 | const decl_index = ptr_val.castTag(.decl_ref).?.data; | |
| 2925 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | |
| 2952 | .int, .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}), | |
| 2953 | .opt_payload => |base_ptr| { | |
| 2954 | return func.lowerParentPtr(base_ptr.toValue()); | |
| 2926 | 2955 | }, |
| 2927 | .variable => { | |
| 2928 | const decl_index = ptr_val.castTag(.variable).?.data.owner_decl; | |
| 2929 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | |
| 2956 | .comptime_field => unreachable, | |
| 2957 | .elem => |elem| { | |
| 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 => { | |
| 2932 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 2933 | const parent_ty = field_ptr.container_ty; | |
| 2934 | ||
| 2935 | const field_offset = switch (parent_ty.zigTypeTag()) { | |
| 2936 | .Struct => switch (parent_ty.containerLayout()) { | |
| 2937 | .Packed => parent_ty.packedStructFieldByteOffset(field_ptr.field_index, func.target), | |
| 2938 | else => parent_ty.structFieldOffset(field_ptr.field_index, func.target), | |
| 2979 | .field => |field| { | |
| 2980 | const parent_ty = mod.intern_pool.typeOf(field.base).toType().childType(mod); | |
| 2981 | const parent_ptr = try func.lowerParentPtr(field.base.toValue()); | |
| 2982 | ||
| 2983 | const offset = switch (parent_ty.zigTypeTag(mod)) { | |
| 2984 | .Struct => switch (parent_ty.containerLayout(mod)) { | |
| 2985 | .Packed => parent_ty.packedStructFieldByteOffset(@intCast(usize, field.index), mod), | |
| 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 | 2989 | .Packed => 0, |
| 2942 | 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 | 2992 | if (layout.payload_size == 0) break :blk 0; |
| 2945 | 2993 | if (layout.payload_align > layout.tag_align) break :blk 0; |
| 2946 | 2994 | |
| 2947 | 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)); | |
| 2949 | break :blk field_offset; | |
| 2996 | const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align)); | |
| 2997 | break :blk offset; | |
| 2950 | 2998 | }, |
| 2951 | 2999 | }, |
| 2952 | .Pointer => switch (parent_ty.ptrSize()) { | |
| 2953 | .Slice => switch (field_ptr.field_index) { | |
| 3000 | .Pointer => switch (parent_ty.ptrSize(mod)) { | |
| 3001 | .Slice => switch (field.index) { | |
| 2954 | 3002 | 0 => 0, |
| 2955 | 3003 | 1 => func.ptrSize(), |
| 2956 | 3004 | else => unreachable, |
| ... | ... | @@ -2959,51 +3007,51 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue |
| 2959 | 3007 | }, |
| 2960 | 3008 | else => unreachable, |
| 2961 | 3009 | }; |
| 2962 | return func.lowerParentPtr(field_ptr.container_ptr, offset + @intCast(u32, field_offset)); | |
| 2963 | }, | |
| 2964 | .elem_ptr => { | |
| 2965 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 2966 | const index = elem_ptr.index; | |
| 2967 | const elem_offset = index * elem_ptr.elem_ty.abiSize(func.target); | |
| 2968 | return func.lowerParentPtr(elem_ptr.array_ptr, offset + @intCast(u32, elem_offset)); | |
| 2969 | }, | |
| 2970 | .opt_payload_ptr => { | |
| 2971 | const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | |
| 2972 | return func.lowerParentPtr(payload_ptr.container_ptr, offset); | |
| 3010 | ||
| 3011 | return switch (parent_ptr) { | |
| 3012 | .memory => |ptr_| WValue{ | |
| 3013 | .memory_offset = .{ | |
| 3014 | .pointer = ptr_, | |
| 3015 | .offset = @intCast(u32, offset), | |
| 3016 | }, | |
| 3017 | }, | |
| 3018 | .memory_offset => |mem_off| WValue{ | |
| 3019 | .memory_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 | 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.?; | |
| 2980 | const decl = module.declPtr(decl_index); | |
| 2981 | module.markDeclAlive(decl); | |
| 2982 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 2983 | .base = .{ .tag = .single_mut_pointer }, | |
| 2984 | .data = decl.ty, | |
| 2985 | }; | |
| 2986 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 3031 | const mod = func.bin_file.base.options.module.?; | |
| 3032 | const decl = mod.declPtr(decl_index); | |
| 3033 | try mod.markDeclAlive(decl); | |
| 3034 | const ptr_ty = try mod.singleMutPtrType(decl.ty); | |
| 2987 | 3035 | return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); |
| 2988 | 3036 | } |
| 2989 | 3037 | |
| 2990 | 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 | 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.?; | |
| 2996 | const decl = module.declPtr(decl_index); | |
| 2997 | if (decl.ty.zigTypeTag() != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3044 | const decl = mod.declPtr(decl_index); | |
| 3045 | if (decl.ty.zigTypeTag(mod) != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2998 | 3046 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 2999 | 3047 | } |
| 3000 | 3048 | |
| 3001 | module.markDeclAlive(decl); | |
| 3049 | try mod.markDeclAlive(decl); | |
| 3002 | 3050 | const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index); |
| 3003 | 3051 | const atom = func.bin_file.getAtom(atom_index); |
| 3004 | 3052 | |
| 3005 | 3053 | const target_sym_index = atom.sym_index; |
| 3006 | if (decl.ty.zigTypeTag() == .Fn) { | |
| 3054 | if (decl.ty.zigTypeTag(mod) == .Fn) { | |
| 3007 | 3055 | try func.bin_file.addTableFunction(target_sym_index); |
| 3008 | 3056 | return WValue{ .function_index = target_sym_index }; |
| 3009 | 3057 | } else if (offset == 0) { |
| ... | ... | @@ -3028,142 +3076,201 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( |
| 3028 | 3076 | } |
| 3029 | 3077 | |
| 3030 | 3078 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3079 | const mod = func.bin_file.base.options.module.?; | |
| 3031 | 3080 | var val = arg_val; |
| 3032 | if (val.castTag(.runtime_value)) |rt| { | |
| 3033 | val = rt.data; | |
| 3034 | } | |
| 3035 | if (val.isUndefDeep()) return func.emitUndefined(ty); | |
| 3036 | if (val.castTag(.decl_ref)) |decl_ref| { | |
| 3037 | const decl_index = decl_ref.data; | |
| 3038 | return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0); | |
| 3039 | } | |
| 3040 | if (val.castTag(.decl_ref_mut)) |decl_ref_mut| { | |
| 3041 | const decl_index = decl_ref_mut.data.decl_index; | |
| 3042 | return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0); | |
| 3043 | } | |
| 3044 | const target = func.target; | |
| 3045 | switch (ty.zigTypeTag()) { | |
| 3046 | .Void => return WValue{ .none = {} }, | |
| 3047 | .Int => { | |
| 3048 | const int_info = ty.intInfo(func.target); | |
| 3081 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 3082 | .runtime_value => |rt| val = rt.val.toValue(), | |
| 3083 | else => {}, | |
| 3084 | } | |
| 3085 | if (val.isUndefDeep(mod)) return func.emitUndefined(ty); | |
| 3086 | ||
| 3087 | if (val.ip_index == .none) switch (ty.zigTypeTag(mod)) { | |
| 3088 | .Array => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}), | |
| 3089 | .Struct => { | |
| 3090 | const struct_obj = mod.typeToStruct(ty).?; | |
| 3091 | assert(struct_obj.layout == .Packed); | |
| 3092 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | |
| 3093 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | |
| 3094 | const int_val = try mod.intValue( | |
| 3095 | struct_obj.backing_int_ty, | |
| 3096 | std.mem.readIntLittle(u64, &buf), | |
| 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 | 3174 | switch (int_info.signedness) { |
| 3050 | 3175 | .signed => switch (int_info.bits) { |
| 3051 | 3176 | 0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement( |
| 3052 | val.toSignedInt(target), | |
| 3177 | val.toSignedInt(mod), | |
| 3053 | 3178 | @intCast(u6, int_info.bits), |
| 3054 | 3179 | )) }, |
| 3055 | 3180 | 33...64 => return WValue{ .imm64 = toTwosComplement( |
| 3056 | val.toSignedInt(target), | |
| 3181 | val.toSignedInt(mod), | |
| 3057 | 3182 | @intCast(u7, int_info.bits), |
| 3058 | 3183 | ) }, |
| 3059 | 3184 | else => unreachable, |
| 3060 | 3185 | }, |
| 3061 | 3186 | .unsigned => switch (int_info.bits) { |
| 3062 | 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) }, | |
| 3063 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt(target) }, | |
| 3187 | 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(mod)) }, | |
| 3188 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt(mod) }, | |
| 3064 | 3189 | else => unreachable, |
| 3065 | 3190 | }, |
| 3066 | 3191 | } |
| 3067 | 3192 | }, |
| 3068 | .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) }, | |
| 3069 | .Float => switch (ty.floatBits(func.target)) { | |
| 3070 | 16 => return WValue{ .imm32 = @bitCast(u16, val.toFloat(f16)) }, | |
| 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()}), | |
| 3193 | .err => |err| { | |
| 3194 | const int = try mod.getErrorValue(err.name); | |
| 3195 | return WValue{ .imm32 = int }; | |
| 3080 | 3196 | }, |
| 3081 | .Enum => { | |
| 3082 | if (val.castTag(.enum_field_index)) |field_index| { | |
| 3083 | switch (ty.tag()) { | |
| 3084 | .enum_simple => return WValue{ .imm32 = field_index.data }, | |
| 3085 | .enum_full, .enum_nonexhaustive => { | |
| 3086 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | |
| 3087 | if (enum_full.values.count() != 0) { | |
| 3088 | const tag_val = enum_full.values.keys()[field_index.data]; | |
| 3089 | return func.lowerConstant(tag_val, enum_full.tag_ty); | |
| 3090 | } else { | |
| 3091 | return WValue{ .imm32 = field_index.data }; | |
| 3092 | } | |
| 3093 | }, | |
| 3094 | .enum_numbered => { | |
| 3095 | const index = field_index.data; | |
| 3096 | const enum_data = ty.castTag(.enum_numbered).?.data; | |
| 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()) { | |
| 3197 | .error_union => |error_union| { | |
| 3198 | const err_tv: TypedValue = switch (error_union.val) { | |
| 3199 | .err_name => |err_name| .{ | |
| 3200 | .ty = ty.errorUnionSet(mod), | |
| 3201 | .val = (try mod.intern(.{ .err = .{ | |
| 3202 | .ty = ty.errorUnionSet(mod).toIntern(), | |
| 3203 | .name = err_name, | |
| 3204 | } })).toValue(), | |
| 3205 | }, | |
| 3206 | .payload => .{ | |
| 3207 | .ty = Type.err_int, | |
| 3208 | .val = try mod.intValue(Type.err_int, 0), | |
| 3209 | }, | |
| 3210 | }; | |
| 3211 | const payload_type = ty.errorUnionPayload(mod); | |
| 3212 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3119 | 3213 | // We use the error type directly as the type. |
| 3120 | const is_pl = val.errorUnionIsPayload(); | |
| 3121 | const err_val = if (!is_pl) val else Value.initTag(.zero); | |
| 3122 | return func.lowerConstant(err_val, error_type); | |
| 3214 | return func.lowerConstant(err_tv.val, err_tv.ty); | |
| 3123 | 3215 | } |
| 3216 | ||
| 3124 | 3217 | return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{}); |
| 3125 | 3218 | }, |
| 3126 | .Optional => if (ty.optionalReprIsPayload()) { | |
| 3127 | var buf: Type.Payload.ElemType = undefined; | |
| 3128 | const pl_ty = ty.optionalChild(&buf); | |
| 3129 | if (val.castTag(.opt_payload)) |payload| { | |
| 3130 | return func.lowerConstant(payload.data, pl_ty); | |
| 3131 | } else if (val.isNull()) { | |
| 3132 | return WValue{ .imm32 = 0 }; | |
| 3219 | .enum_tag => |enum_tag| { | |
| 3220 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); | |
| 3221 | return func.lowerConstant(enum_tag.int.toValue(), int_tag_ty.toType()); | |
| 3222 | }, | |
| 3223 | .float => |float| switch (float.storage) { | |
| 3224 | .f16 => |f16_val| return WValue{ .imm32 = @bitCast(u16, f16_val) }, | |
| 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 | 3240 | } else { |
| 3134 | return func.lowerConstant(val, pl_ty); | |
| 3241 | return WValue{ .imm32 = 0 }; | |
| 3135 | 3242 | } |
| 3136 | 3243 | } else { |
| 3137 | const is_pl = val.tag() == .opt_payload; | |
| 3138 | return WValue{ .imm32 = @boolToInt(is_pl) }; | |
| 3244 | return WValue{ .imm32 = @boolToInt(!val.isNull(mod)) }; | |
| 3139 | 3245 | }, |
| 3140 | .Struct => { | |
| 3141 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3142 | assert(struct_obj.layout == .Packed); | |
| 3143 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | |
| 3144 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | |
| 3145 | var payload: Value.Payload.U64 = .{ | |
| 3146 | .base = .{ .tag = .int_u64 }, | |
| 3147 | .data = std.mem.readIntLittle(u64, &buf), | |
| 3148 | }; | |
| 3149 | const int_val = Value.initPayload(&payload.base); | |
| 3150 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | |
| 3151 | }, | |
| 3152 | .Vector => { | |
| 3153 | assert(determineSimdStoreStrategy(ty, target) == .direct); | |
| 3154 | var buf: [16]u8 = undefined; | |
| 3155 | val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf) catch unreachable; | |
| 3156 | return func.storeSimdImmd(buf); | |
| 3246 | .aggregate => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 3247 | .array_type => return func.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(mod)}), | |
| 3248 | .vector_type => { | |
| 3249 | assert(determineSimdStoreStrategy(ty, mod) == .direct); | |
| 3250 | var buf: [16]u8 = undefined; | |
| 3251 | val.writeToMemory(ty, mod, &buf) catch unreachable; | |
| 3252 | return func.storeSimdImmd(buf); | |
| 3253 | }, | |
| 3254 | .struct_type, .anon_struct_type => { | |
| 3255 | const struct_obj = mod.typeToStruct(ty).?; | |
| 3256 | assert(struct_obj.layout == .Packed); | |
| 3257 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | |
| 3258 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | |
| 3259 | const int_val = try mod.intValue( | |
| 3260 | struct_obj.backing_int_ty, | |
| 3261 | std.mem.readIntLittle(u64, &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 | 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; | |
| 3161 | const union_obj = val.castTag(.@"union").?.data; | |
| 3162 | const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?; | |
| 3163 | const field_ty = union_ty.fields.values()[field_index].ty; | |
| 3164 | return func.lowerConstant(union_obj.val, field_ty); | |
| 3269 | const field_index = ty.unionTagFieldIndex(union_obj.tag.toValue(), func.bin_file.base.options.module.?).?; | |
| 3270 | const field_ty = ty.unionFields(mod).values()[field_index].ty; | |
| 3271 | return func.lowerConstant(union_obj.val.toValue(), 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 | 3283 | } |
| 3177 | 3284 | |
| 3178 | 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 | 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 | 3290 | 0...32 => return WValue{ .imm32 = 0xaaaaaaaa }, |
| 3183 | 3291 | 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa }, |
| 3184 | 3292 | else => unreachable, |
| ... | ... | @@ -3195,9 +3303,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3195 | 3303 | else => unreachable, |
| 3196 | 3304 | }, |
| 3197 | 3305 | .Optional => { |
| 3198 | var buf: Type.Payload.ElemType = undefined; | |
| 3199 | const pl_ty = ty.optionalChild(&buf); | |
| 3200 | if (ty.optionalReprIsPayload()) { | |
| 3306 | const pl_ty = ty.optionalChild(mod); | |
| 3307 | if (ty.optionalReprIsPayload(mod)) { | |
| 3201 | 3308 | return func.emitUndefined(pl_ty); |
| 3202 | 3309 | } |
| 3203 | 3310 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| ... | ... | @@ -3206,11 +3313,11 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3206 | 3313 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 3207 | 3314 | }, |
| 3208 | 3315 | .Struct => { |
| 3209 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3316 | const struct_obj = mod.typeToStruct(ty).?; | |
| 3210 | 3317 | assert(struct_obj.layout == .Packed); |
| 3211 | 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 | 3325 | /// It's illegal to provide a value with a type that cannot be represented |
| 3219 | 3326 | /// as an integer value. |
| 3220 | 3327 | fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { |
| 3221 | const target = func.target; | |
| 3222 | switch (ty.zigTypeTag()) { | |
| 3223 | .Enum => { | |
| 3224 | if (val.castTag(.enum_field_index)) |field_index| { | |
| 3225 | switch (ty.tag()) { | |
| 3226 | .enum_simple => return @bitCast(i32, field_index.data), | |
| 3227 | .enum_full, .enum_nonexhaustive => { | |
| 3228 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | |
| 3229 | if (enum_full.values.count() != 0) { | |
| 3230 | const tag_val = enum_full.values.keys()[field_index.data]; | |
| 3231 | return func.valueAsI32(tag_val, enum_full.tag_ty); | |
| 3232 | } else return @bitCast(i32, field_index.data); | |
| 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); | |
| 3328 | const mod = func.bin_file.base.options.module.?; | |
| 3329 | ||
| 3330 | switch (val.ip_index) { | |
| 3331 | .none => {}, | |
| 3332 | .bool_true => return 1, | |
| 3333 | .bool_false => return 0, | |
| 3334 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 3335 | .enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int, mod), | |
| 3336 | .int => |int| intStorageAsI32(int.storage, mod), | |
| 3337 | .ptr => |ptr| intIndexAsI32(&mod.intern_pool, ptr.addr.int, mod), | |
| 3338 | .err => |err| @bitCast(i32, @intCast(Module.ErrorInt, mod.global_error_set.getIndex(err.name).?)), | |
| 3339 | else => unreachable, | |
| 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 | 3363 | fn airBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3364 | const mod = func.bin_file.base.options.module.?; | |
| 3262 | 3365 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3263 | 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 | 3368 | const extra = func.air.extraData(Air.Block, ty_pl.payload); |
| 3266 | 3369 | const body = func.air.extra[extra.end..][0..extra.data.body_len]; |
| 3267 | 3370 | |
| 3268 | 3371 | // if wasm_block_ty is non-empty, we create a register to store the temporary value |
| 3269 | 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 | 3374 | break :blk try func.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten |
| 3272 | 3375 | } else WValue.none; |
| 3273 | 3376 | |
| ... | ... | @@ -3369,7 +3472,7 @@ fn airCmp(func: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) In |
| 3369 | 3472 | |
| 3370 | 3473 | const lhs = try func.resolveInst(bin_op.lhs); |
| 3371 | 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 | 3476 | const result = try (try func.cmp(lhs, rhs, operand_ty, op)).toLocal(func, Type.u32); // comparison result is always 32 bits |
| 3374 | 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 | 3482 | /// NOTE: This leaves the result on top of the stack, rather than a new local. |
| 3380 | 3483 | fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 3381 | 3484 | assert(!(lhs != .stack and rhs == .stack)); |
| 3382 | if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) { | |
| 3383 | var buf: Type.Payload.ElemType = undefined; | |
| 3384 | const payload_ty = ty.optionalChild(&buf); | |
| 3385 | if (payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3485 | const mod = func.bin_file.base.options.module.?; | |
| 3486 | if (ty.zigTypeTag(mod) == .Optional and !ty.optionalReprIsPayload(mod)) { | |
| 3487 | const payload_ty = ty.optionalChild(mod); | |
| 3488 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3386 | 3489 | // When we hit this case, we must check the value of optionals |
| 3387 | 3490 | // that are not pointers. This means first checking against non-null for |
| 3388 | 3491 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs |
| 3389 | 3492 | return func.cmpOptionals(lhs, rhs, ty, op); |
| 3390 | 3493 | } |
| 3391 | } else if (isByRef(ty, func.target)) { | |
| 3494 | } else if (isByRef(ty, mod)) { | |
| 3392 | 3495 | return func.cmpBigInt(lhs, rhs, ty, op); |
| 3393 | 3496 | } else if (ty.isAnyFloat() and ty.floatBits(func.target) == 16) { |
| 3394 | 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 | 3504 | |
| 3402 | 3505 | const signedness: std.builtin.Signedness = blk: { |
| 3403 | 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 | 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 | 3512 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 3410 | .valtype1 = typeToValtype(ty, func.target), | |
| 3513 | .valtype1 = typeToValtype(ty, mod), | |
| 3411 | 3514 | .op = switch (op) { |
| 3412 | 3515 | .lt => .lt, |
| 3413 | 3516 | .lte => .le, |
| ... | ... | @@ -3464,11 +3567,12 @@ fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3464 | 3567 | } |
| 3465 | 3568 | |
| 3466 | 3569 | fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3570 | const mod = func.bin_file.base.options.module.?; | |
| 3467 | 3571 | const br = func.air.instructions.items(.data)[inst].br; |
| 3468 | 3572 | const block = func.blocks.get(br.block_inst).?; |
| 3469 | 3573 | |
| 3470 | 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 | 3576 | const operand = try func.resolveInst(br.operand); |
| 3473 | 3577 | try func.lowerToStack(operand); |
| 3474 | 3578 | |
| ... | ... | @@ -3489,17 +3593,18 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3489 | 3593 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3490 | 3594 | |
| 3491 | 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 | 3599 | const result = result: { |
| 3495 | if (operand_ty.zigTypeTag() == .Bool) { | |
| 3600 | if (operand_ty.zigTypeTag(mod) == .Bool) { | |
| 3496 | 3601 | try func.emitWValue(operand); |
| 3497 | 3602 | try func.addTag(.i32_eqz); |
| 3498 | 3603 | const not_tmp = try func.allocLocal(operand_ty); |
| 3499 | 3604 | try func.addLabel(.local_set, not_tmp.local.value); |
| 3500 | 3605 | break :result not_tmp; |
| 3501 | 3606 | } else { |
| 3502 | const operand_bits = operand_ty.intInfo(func.target).bits; | |
| 3607 | const operand_bits = operand_ty.intInfo(mod).bits; | |
| 3503 | 3608 | const wasm_bits = toWasmBits(operand_bits) orelse { |
| 3504 | 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 | 3659 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3555 | 3660 | const result = result: { |
| 3556 | 3661 | const operand = try func.resolveInst(ty_op.operand); |
| 3557 | const wanted_ty = func.air.typeOfIndex(inst); | |
| 3558 | const given_ty = func.air.typeOf(ty_op.operand); | |
| 3662 | const wanted_ty = func.typeOfIndex(inst); | |
| 3663 | const given_ty = func.typeOf(ty_op.operand); | |
| 3559 | 3664 | if (given_ty.isAnyFloat() or wanted_ty.isAnyFloat()) { |
| 3560 | 3665 | const bitcast_result = try func.bitcast(wanted_ty, given_ty, operand); |
| 3561 | 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 | 3671 | } |
| 3567 | 3672 | |
| 3568 | 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 | 3675 | // if we bitcast a float to or from an integer we must use the 'reinterpret' instruction |
| 3570 | 3676 | if (!(wanted_ty.isAnyFloat() or given_ty.isAnyFloat())) return operand; |
| 3571 | if (wanted_ty.tag() == .f16 or given_ty.tag() == .f16) return operand; | |
| 3572 | if (wanted_ty.bitSize(func.target) > 64) return operand; | |
| 3573 | assert((wanted_ty.isInt() and given_ty.isAnyFloat()) or (wanted_ty.isAnyFloat() and given_ty.isInt())); | |
| 3677 | if (wanted_ty.ip_index == .f16_type or given_ty.ip_index == .f16_type) return operand; | |
| 3678 | if (wanted_ty.bitSize(mod) > 64) return operand; | |
| 3679 | assert((wanted_ty.isInt(mod) and given_ty.isAnyFloat()) or (wanted_ty.isAnyFloat() and given_ty.isInt(mod))); | |
| 3574 | 3680 | |
| 3575 | 3681 | const opcode = buildOpcode(.{ |
| 3576 | 3682 | .op = .reinterpret, |
| 3577 | .valtype1 = typeToValtype(wanted_ty, func.target), | |
| 3578 | .valtype2 = typeToValtype(given_ty, func.target), | |
| 3683 | .valtype1 = typeToValtype(wanted_ty, mod), | |
| 3684 | .valtype2 = typeToValtype(given_ty, mod), | |
| 3579 | 3685 | }); |
| 3580 | 3686 | try func.emitWValue(operand); |
| 3581 | 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 | 3689 | } |
| 3584 | 3690 | |
| 3585 | 3691 | fn airStructFieldPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3692 | const mod = func.bin_file.base.options.module.?; | |
| 3586 | 3693 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3587 | 3694 | const extra = func.air.extraData(Air.StructField, ty_pl.payload); |
| 3588 | 3695 | |
| 3589 | 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 | 3698 | const result = try func.structFieldPtr(inst, extra.data.struct_operand, struct_ptr, struct_ty, extra.data.field_index); |
| 3592 | 3699 | func.finishAir(inst, result, &.{extra.data.struct_operand}); |
| 3593 | 3700 | } |
| 3594 | 3701 | |
| 3595 | 3702 | fn airStructFieldPtrIndex(func: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void { |
| 3703 | const mod = func.bin_file.base.options.module.?; | |
| 3596 | 3704 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3597 | 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 | 3708 | const result = try func.structFieldPtr(inst, ty_op.operand, struct_ptr, struct_ty, index); |
| 3601 | 3709 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | ... | @@ -3609,19 +3717,20 @@ fn structFieldPtr( |
| 3609 | 3717 | struct_ty: Type, |
| 3610 | 3718 | index: u32, |
| 3611 | 3719 | ) InnerError!WValue { |
| 3612 | const result_ty = func.air.typeOfIndex(inst); | |
| 3613 | const offset = switch (struct_ty.containerLayout()) { | |
| 3614 | .Packed => switch (struct_ty.zigTypeTag()) { | |
| 3720 | const mod = func.bin_file.base.options.module.?; | |
| 3721 | const result_ty = func.typeOfIndex(inst); | |
| 3722 | const offset = switch (struct_ty.containerLayout(mod)) { | |
| 3723 | .Packed => switch (struct_ty.zigTypeTag(mod)) { | |
| 3615 | 3724 | .Struct => offset: { |
| 3616 | if (result_ty.ptrInfo().data.host_size != 0) { | |
| 3725 | if (result_ty.ptrInfo(mod).host_size != 0) { | |
| 3617 | 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 | 3730 | .Union => 0, |
| 3622 | 3731 | else => unreachable, |
| 3623 | 3732 | }, |
| 3624 | else => struct_ty.structFieldOffset(index, func.target), | |
| 3733 | else => struct_ty.structFieldOffset(index, mod), | |
| 3625 | 3734 | }; |
| 3626 | 3735 | // save a load and store when we can simply reuse the operand |
| 3627 | 3736 | if (offset == 0) { |
| ... | ... | @@ -3636,22 +3745,23 @@ fn structFieldPtr( |
| 3636 | 3745 | } |
| 3637 | 3746 | |
| 3638 | 3747 | fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3748 | const mod = func.bin_file.base.options.module.?; | |
| 3639 | 3749 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3640 | 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 | 3753 | const operand = try func.resolveInst(struct_field.struct_operand); |
| 3644 | 3754 | const field_index = struct_field.field_index; |
| 3645 | const field_ty = struct_ty.structFieldType(field_index); | |
| 3646 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) return func.finishAir(inst, .none, &.{struct_field.struct_operand}); | |
| 3755 | const field_ty = struct_ty.structFieldType(field_index, mod); | |
| 3756 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return func.finishAir(inst, .none, &.{struct_field.struct_operand}); | |
| 3647 | 3757 | |
| 3648 | const result = switch (struct_ty.containerLayout()) { | |
| 3649 | .Packed => switch (struct_ty.zigTypeTag()) { | |
| 3758 | const result = switch (struct_ty.containerLayout(mod)) { | |
| 3759 | .Packed => switch (struct_ty.zigTypeTag(mod)) { | |
| 3650 | 3760 | .Struct => result: { |
| 3651 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | |
| 3652 | const offset = struct_obj.packedFieldBitOffset(func.target, field_index); | |
| 3761 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 3762 | const offset = struct_obj.packedFieldBitOffset(mod, field_index); | |
| 3653 | 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 | 3765 | return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{}); |
| 3656 | 3766 | }; |
| 3657 | 3767 | const const_wvalue = if (wasm_bits == 32) |
| ... | ... | @@ -3667,25 +3777,17 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3667 | 3777 | else |
| 3668 | 3778 | try func.binOp(operand, const_wvalue, backing_ty, .shr); |
| 3669 | 3779 | |
| 3670 | if (field_ty.zigTypeTag() == .Float) { | |
| 3671 | var payload: Type.Payload.Bits = .{ | |
| 3672 | .base = .{ .tag = .int_unsigned }, | |
| 3673 | .data = @intCast(u16, field_ty.bitSize(func.target)), | |
| 3674 | }; | |
| 3675 | const int_type = Type.initPayload(&payload.base); | |
| 3780 | if (field_ty.zigTypeTag(mod) == .Float) { | |
| 3781 | const int_type = try mod.intType(.unsigned, @intCast(u16, field_ty.bitSize(mod))); | |
| 3676 | 3782 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); |
| 3677 | 3783 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); |
| 3678 | 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 | 3786 | // In this case we do not have to perform any transformations, |
| 3681 | 3787 | // we can simply reuse the operand. |
| 3682 | 3788 | break :result func.reuseOperand(struct_field.struct_operand, operand); |
| 3683 | } else if (field_ty.isPtrAtRuntime()) { | |
| 3684 | var payload: Type.Payload.Bits = .{ | |
| 3685 | .base = .{ .tag = .int_unsigned }, | |
| 3686 | .data = @intCast(u16, field_ty.bitSize(func.target)), | |
| 3687 | }; | |
| 3688 | const int_type = Type.initPayload(&payload.base); | |
| 3789 | } else if (field_ty.isPtrAtRuntime(mod)) { | |
| 3790 | const int_type = try mod.intType(.unsigned, @intCast(u16, field_ty.bitSize(mod))); | |
| 3689 | 3791 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); |
| 3690 | 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 | 3795 | break :result try truncated.toLocal(func, field_ty); |
| 3694 | 3796 | }, |
| 3695 | 3797 | .Union => result: { |
| 3696 | if (isByRef(struct_ty, func.target)) { | |
| 3697 | if (!isByRef(field_ty, func.target)) { | |
| 3798 | if (isByRef(struct_ty, mod)) { | |
| 3799 | if (!isByRef(field_ty, mod)) { | |
| 3698 | 3800 | const val = try func.load(operand, field_ty, 0); |
| 3699 | 3801 | break :result try val.toLocal(func, field_ty); |
| 3700 | 3802 | } else { |
| ... | ... | @@ -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 = .{ | |
| 3708 | .base = .{ .tag = .int_unsigned }, | |
| 3709 | .data = @intCast(u16, struct_ty.bitSize(func.target)), | |
| 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); | |
| 3809 | const union_int_type = try mod.intType(.unsigned, @intCast(u16, struct_ty.bitSize(mod))); | |
| 3810 | if (field_ty.zigTypeTag(mod) == .Float) { | |
| 3811 | const int_type = try mod.intType(.unsigned, @intCast(u16, field_ty.bitSize(mod))); | |
| 3718 | 3812 | const truncated = try func.trunc(operand, int_type, union_int_type); |
| 3719 | 3813 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); |
| 3720 | 3814 | break :result try bitcasted.toLocal(func, field_ty); |
| 3721 | } else if (field_ty.isPtrAtRuntime()) { | |
| 3722 | var int_payload: Type.Payload.Bits = .{ | |
| 3723 | .base = .{ .tag = .int_unsigned }, | |
| 3724 | .data = @intCast(u16, field_ty.bitSize(func.target)), | |
| 3725 | }; | |
| 3726 | const int_type = Type.initPayload(&int_payload.base); | |
| 3815 | } else if (field_ty.isPtrAtRuntime(mod)) { | |
| 3816 | const int_type = try mod.intType(.unsigned, @intCast(u16, field_ty.bitSize(mod))); | |
| 3727 | 3817 | const truncated = try func.trunc(operand, int_type, union_int_type); |
| 3728 | 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 | 3823 | else => unreachable, |
| 3734 | 3824 | }, |
| 3735 | 3825 | else => result: { |
| 3736 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, func.target)) orelse { | |
| 3737 | const module = func.bin_file.base.options.module.?; | |
| 3738 | return func.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(module)}); | |
| 3826 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, mod)) orelse { | |
| 3827 | return func.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(mod)}); | |
| 3739 | 3828 | }; |
| 3740 | if (isByRef(field_ty, func.target)) { | |
| 3829 | if (isByRef(field_ty, mod)) { | |
| 3741 | 3830 | switch (operand) { |
| 3742 | 3831 | .stack_offset => |stack_offset| { |
| 3743 | 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 | 3843 | } |
| 3755 | 3844 | |
| 3756 | 3845 | fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3846 | const mod = func.bin_file.base.options.module.?; | |
| 3757 | 3847 | // result type is always 'noreturn' |
| 3758 | 3848 | const blocktype = wasm.block_empty; |
| 3759 | 3849 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 3760 | 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 | 3852 | const switch_br = func.air.extraData(Air.SwitchBr, pl_op.payload); |
| 3763 | 3853 | const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.data.cases_len + 1); |
| 3764 | 3854 | defer func.gpa.free(liveness.deaths); |
| ... | ... | @@ -3787,7 +3877,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3787 | 3877 | errdefer func.gpa.free(values); |
| 3788 | 3878 | |
| 3789 | 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 | 3881 | const int_val = func.valueAsI32(item_val, target_ty); |
| 3792 | 3882 | if (lowest_maybe == null or int_val < lowest_maybe.?) { |
| 3793 | 3883 | lowest_maybe = int_val; |
| ... | ... | @@ -3810,7 +3900,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3810 | 3900 | // When the target is an integer size larger than u32, we have no way to use the value |
| 3811 | 3901 | // as an index, therefore we also use an if/else-chain for those cases. |
| 3812 | 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 | 3905 | const else_body = func.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| 3816 | 3906 | const has_else_body = else_body.len != 0; |
| ... | ... | @@ -3855,7 +3945,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3855 | 3945 | // for errors that are not present in any branch. This is fine as this default |
| 3856 | 3946 | // case will never be hit for those cases but we do save runtime cost and size |
| 3857 | 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 | 3950 | func.mir_extra.appendAssumeCapacity(idx); |
| 3861 | 3951 | } else if (has_else_body) { |
| ... | ... | @@ -3866,10 +3956,10 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3866 | 3956 | |
| 3867 | 3957 | const signedness: std.builtin.Signedness = blk: { |
| 3868 | 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 | 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 | 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 | 3972 | const val = try func.lowerConstant(case.values[0].value, target_ty); |
| 3883 | 3973 | try func.emitWValue(val); |
| 3884 | 3974 | const opcode = buildOpcode(.{ |
| 3885 | .valtype1 = typeToValtype(target_ty, func.target), | |
| 3975 | .valtype1 = typeToValtype(target_ty, mod), | |
| 3886 | 3976 | .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition. |
| 3887 | 3977 | .signedness = signedness, |
| 3888 | 3978 | }); |
| ... | ... | @@ -3896,7 +3986,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3896 | 3986 | const val = try func.lowerConstant(value.value, target_ty); |
| 3897 | 3987 | try func.emitWValue(val); |
| 3898 | 3988 | const opcode = buildOpcode(.{ |
| 3899 | .valtype1 = typeToValtype(target_ty, func.target), | |
| 3989 | .valtype1 = typeToValtype(target_ty, mod), | |
| 3900 | 3990 | .op = .eq, |
| 3901 | 3991 | .signedness = signedness, |
| 3902 | 3992 | }); |
| ... | ... | @@ -3933,13 +4023,14 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3933 | 4023 | } |
| 3934 | 4024 | |
| 3935 | 4025 | fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!void { |
| 4026 | const mod = func.bin_file.base.options.module.?; | |
| 3936 | 4027 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 3937 | 4028 | const operand = try func.resolveInst(un_op); |
| 3938 | const err_union_ty = func.air.typeOf(un_op); | |
| 3939 | const pl_ty = err_union_ty.errorUnionPayload(); | |
| 4029 | const err_union_ty = func.typeOf(un_op); | |
| 4030 | const pl_ty = err_union_ty.errorUnionPayload(mod); | |
| 3940 | 4031 | |
| 3941 | 4032 | const result = result: { |
| 3942 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { | |
| 4033 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { | |
| 3943 | 4034 | switch (opcode) { |
| 3944 | 4035 | .i32_ne => break :result WValue{ .imm32 = 0 }, |
| 3945 | 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 | 4039 | } |
| 3949 | 4040 | |
| 3950 | 4041 | try func.emitWValue(operand); |
| 3951 | if (pl_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4042 | if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3952 | 4043 | try func.addMemArg(.i32_load16_u, .{ |
| 3953 | .offset = operand.offset() + @intCast(u32, errUnionErrorOffset(pl_ty, func.target)), | |
| 3954 | .alignment = Type.anyerror.abiAlignment(func.target), | |
| 4044 | .offset = operand.offset() + @intCast(u32, errUnionErrorOffset(pl_ty, mod)), | |
| 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 | 4058 | } |
| 3968 | 4059 | |
| 3969 | 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 | 4062 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3971 | 4063 | |
| 3972 | 4064 | const operand = try func.resolveInst(ty_op.operand); |
| 3973 | const op_ty = func.air.typeOf(ty_op.operand); | |
| 3974 | const err_ty = if (op_is_ptr) op_ty.childType() else op_ty; | |
| 3975 | const payload_ty = err_ty.errorUnionPayload(); | |
| 4065 | const op_ty = func.typeOf(ty_op.operand); | |
| 4066 | const err_ty = if (op_is_ptr) op_ty.childType(mod) else op_ty; | |
| 4067 | const payload_ty = err_ty.errorUnionPayload(mod); | |
| 3976 | 4068 | |
| 3977 | 4069 | const result = result: { |
| 3978 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4070 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3979 | 4071 | if (op_is_ptr) { |
| 3980 | 4072 | break :result func.reuseOperand(ty_op.operand, operand); |
| 3981 | 4073 | } |
| 3982 | 4074 | break :result WValue{ .none = {} }; |
| 3983 | 4075 | } |
| 3984 | 4076 | |
| 3985 | const pl_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, func.target)); | |
| 3986 | if (op_is_ptr or isByRef(payload_ty, func.target)) { | |
| 4077 | const pl_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, mod)); | |
| 4078 | if (op_is_ptr or isByRef(payload_ty, mod)) { | |
| 3987 | 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 | 4086 | } |
| 3995 | 4087 | |
| 3996 | 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 | 4090 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3998 | 4091 | |
| 3999 | 4092 | const operand = try func.resolveInst(ty_op.operand); |
| 4000 | const op_ty = func.air.typeOf(ty_op.operand); | |
| 4001 | const err_ty = if (op_is_ptr) op_ty.childType() else op_ty; | |
| 4002 | const payload_ty = err_ty.errorUnionPayload(); | |
| 4093 | const op_ty = func.typeOf(ty_op.operand); | |
| 4094 | const err_ty = if (op_is_ptr) op_ty.childType(mod) else op_ty; | |
| 4095 | const payload_ty = err_ty.errorUnionPayload(mod); | |
| 4003 | 4096 | |
| 4004 | 4097 | const result = result: { |
| 4005 | if (err_ty.errorUnionSet().errorSetIsEmpty()) { | |
| 4098 | if (err_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { | |
| 4006 | 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 | 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 | 4107 | break :result try error_val.toLocal(func, Type.anyerror); |
| 4015 | 4108 | }; |
| 4016 | 4109 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 4017 | 4110 | } |
| 4018 | 4111 | |
| 4019 | 4112 | fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4113 | const mod = func.bin_file.base.options.module.?; | |
| 4020 | 4114 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4021 | 4115 | |
| 4022 | 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 | 4120 | const result = result: { |
| 4027 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4121 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4028 | 4122 | break :result func.reuseOperand(ty_op.operand, operand); |
| 4029 | 4123 | } |
| 4030 | 4124 | |
| 4031 | 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 | 4127 | try func.store(payload_ptr, operand, pl_ty, 0); |
| 4034 | 4128 | |
| 4035 | 4129 | // ensure we also write '0' to the error part, so any present stack value gets overwritten by it. |
| 4036 | 4130 | try func.emitWValue(err_union); |
| 4037 | 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 | 4133 | try func.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 }); |
| 4040 | 4134 | break :result err_union; |
| 4041 | 4135 | }; |
| ... | ... | @@ -4043,24 +4137,25 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void |
| 4043 | 4137 | } |
| 4044 | 4138 | |
| 4045 | 4139 | fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4140 | const mod = func.bin_file.base.options.module.?; | |
| 4046 | 4141 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4047 | 4142 | |
| 4048 | 4143 | const operand = try func.resolveInst(ty_op.operand); |
| 4049 | 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 | 4147 | const result = result: { |
| 4053 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4148 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4054 | 4149 | break :result func.reuseOperand(ty_op.operand, operand); |
| 4055 | 4150 | } |
| 4056 | 4151 | |
| 4057 | 4152 | const err_union = try func.allocStack(err_ty); |
| 4058 | 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 | 4156 | // write 'undefined' to the payload |
| 4062 | const payload_ptr = try func.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, func.target)), .new); | |
| 4063 | const len = @intCast(u32, err_ty.errorUnionPayload().abiSize(func.target)); | |
| 4157 | const payload_ptr = try func.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, mod)), .new); | |
| 4158 | const len = @intCast(u32, err_ty.errorUnionPayload(mod).abiSize(mod)); | |
| 4064 | 4159 | try func.memset(Type.u8, payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaa }); |
| 4065 | 4160 | |
| 4066 | 4161 | break :result err_union; |
| ... | ... | @@ -4073,16 +4168,17 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4073 | 4168 | |
| 4074 | 4169 | const ty = func.air.getRefType(ty_op.ty); |
| 4075 | 4170 | const operand = try func.resolveInst(ty_op.operand); |
| 4076 | const operand_ty = func.air.typeOf(ty_op.operand); | |
| 4077 | if (ty.zigTypeTag() == .Vector or operand_ty.zigTypeTag() == .Vector) { | |
| 4171 | const operand_ty = func.typeOf(ty_op.operand); | |
| 4172 | const mod = func.bin_file.base.options.module.?; | |
| 4173 | if (ty.zigTypeTag(mod) == .Vector or operand_ty.zigTypeTag(mod) == .Vector) { | |
| 4078 | 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 | 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))).?; | |
| 4085 | const wanted_bits = toWasmBits(@intCast(u16, ty.bitSize(func.target))).?; | |
| 4180 | const op_bits = toWasmBits(@intCast(u16, operand_ty.bitSize(mod))).?; | |
| 4181 | const wanted_bits = toWasmBits(@intCast(u16, ty.bitSize(mod))).?; | |
| 4086 | 4182 | const result = if (op_bits == wanted_bits) |
| 4087 | 4183 | func.reuseOperand(ty_op.operand, operand) |
| 4088 | 4184 | else |
| ... | ... | @@ -4096,8 +4192,9 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4096 | 4192 | /// Asserts type's bitsize <= 128 |
| 4097 | 4193 | /// NOTE: May leave the result on the top of the stack. |
| 4098 | 4194 | fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue { |
| 4099 | const given_bitsize = @intCast(u16, given.bitSize(func.target)); | |
| 4100 | const wanted_bitsize = @intCast(u16, wanted.bitSize(func.target)); | |
| 4195 | const mod = func.bin_file.base.options.module.?; | |
| 4196 | const given_bitsize = @intCast(u16, given.bitSize(mod)); | |
| 4197 | const wanted_bitsize = @intCast(u16, wanted.bitSize(mod)); | |
| 4101 | 4198 | assert(given_bitsize <= 128); |
| 4102 | 4199 | assert(wanted_bitsize <= 128); |
| 4103 | 4200 | |
| ... | ... | @@ -4110,7 +4207,7 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4110 | 4207 | try func.addTag(.i32_wrap_i64); |
| 4111 | 4208 | } else if (op_bits == 32 and wanted_bits > 32 and wanted_bits <= 64) { |
| 4112 | 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 | 4211 | } else if (wanted_bits == 128) { |
| 4115 | 4212 | // for 128bit integers we store the integer in the virtual stack, rather than a local |
| 4116 | 4213 | const stack_ptr = try func.allocStack(wanted); |
| ... | ... | @@ -4119,14 +4216,14 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4119 | 4216 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it |
| 4120 | 4217 | // meaning less store operations are required. |
| 4121 | 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 | 4220 | } else operand; |
| 4124 | 4221 | |
| 4125 | 4222 | // store msb first |
| 4126 | 4223 | try func.store(.{ .stack = {} }, lhs, Type.u64, 0 + stack_ptr.offset()); |
| 4127 | 4224 | |
| 4128 | 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 | 4227 | try func.emitWValue(stack_ptr); |
| 4131 | 4228 | const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); |
| 4132 | 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 | 4238 | } |
| 4142 | 4239 | |
| 4143 | 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 | 4242 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 4145 | 4243 | const operand = try func.resolveInst(un_op); |
| 4146 | 4244 | |
| 4147 | const op_ty = func.air.typeOf(un_op); | |
| 4148 | const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty; | |
| 4245 | const op_ty = func.typeOf(un_op); | |
| 4246 | const optional_ty = if (op_kind == .ptr) op_ty.childType(mod) else op_ty; | |
| 4149 | 4247 | const is_null = try func.isNull(operand, optional_ty, opcode); |
| 4150 | 4248 | const result = try is_null.toLocal(func, optional_ty); |
| 4151 | 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 | 4252 | /// For a given type and operand, checks if it's considered `null`. |
| 4155 | 4253 | /// NOTE: Leaves the result on the stack |
| 4156 | 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 | 4256 | try func.emitWValue(operand); |
| 4158 | var buf: Type.Payload.ElemType = undefined; | |
| 4159 | const payload_ty = optional_ty.optionalChild(&buf); | |
| 4160 | if (!optional_ty.optionalReprIsPayload()) { | |
| 4257 | const payload_ty = optional_ty.optionalChild(mod); | |
| 4258 | if (!optional_ty.optionalReprIsPayload(mod)) { | |
| 4161 | 4259 | // When payload is zero-bits, we can treat operand as a value, rather than |
| 4162 | 4260 | // a pointer to the stack value |
| 4163 | if (payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4164 | const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse { | |
| 4165 | const module = func.bin_file.base.options.module.?; | |
| 4166 | return func.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(module)}); | |
| 4261 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4262 | const offset = std.math.cast(u32, payload_ty.abiSize(mod)) orelse { | |
| 4263 | return func.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(mod)}); | |
| 4167 | 4264 | }; |
| 4168 | 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 | 4268 | switch (func.arch()) { |
| 4172 | 4269 | .wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }), |
| 4173 | 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 | 4280 | } |
| 4184 | 4281 | |
| 4185 | 4282 | fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4283 | const mod = func.bin_file.base.options.module.?; | |
| 4186 | 4284 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4187 | const opt_ty = func.air.typeOf(ty_op.operand); | |
| 4188 | const payload_ty = func.air.typeOfIndex(inst); | |
| 4189 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4285 | const opt_ty = func.typeOf(ty_op.operand); | |
| 4286 | const payload_ty = func.typeOfIndex(inst); | |
| 4287 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4190 | 4288 | return func.finishAir(inst, .none, &.{ty_op.operand}); |
| 4191 | 4289 | } |
| 4192 | 4290 | |
| 4193 | 4291 | const result = result: { |
| 4194 | 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 | 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 | 4303 | } |
| 4206 | 4304 | |
| 4207 | 4305 | fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4306 | const mod = func.bin_file.base.options.module.?; | |
| 4208 | 4307 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4209 | 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 | 4311 | const result = result: { |
| 4213 | var buf: Type.Payload.ElemType = undefined; | |
| 4214 | const payload_ty = opt_ty.optionalChild(&buf); | |
| 4215 | if (!payload_ty.hasRuntimeBitsIgnoreComptime() or opt_ty.optionalReprIsPayload()) { | |
| 4312 | const payload_ty = opt_ty.optionalChild(mod); | |
| 4313 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or opt_ty.optionalReprIsPayload(mod)) { | |
| 4216 | 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 | 4320 | } |
| 4223 | 4321 | |
| 4224 | 4322 | fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4323 | const mod = func.bin_file.base.options.module.?; | |
| 4225 | 4324 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4226 | 4325 | const operand = try func.resolveInst(ty_op.operand); |
| 4227 | const opt_ty = func.air.typeOf(ty_op.operand).childType(); | |
| 4228 | var buf: Type.Payload.ElemType = undefined; | |
| 4229 | const payload_ty = opt_ty.optionalChild(&buf); | |
| 4230 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4326 | const opt_ty = func.typeOf(ty_op.operand).childType(mod); | |
| 4327 | const payload_ty = opt_ty.optionalChild(mod); | |
| 4328 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4231 | 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 | 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 { | |
| 4239 | const module = func.bin_file.base.options.module.?; | |
| 4240 | return func.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(module)}); | |
| 4336 | const offset = std.math.cast(u32, payload_ty.abiSize(mod)) orelse { | |
| 4337 | return func.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(mod)}); | |
| 4241 | 4338 | }; |
| 4242 | 4339 | |
| 4243 | 4340 | try func.emitWValue(operand); |
| ... | ... | @@ -4250,11 +4347,12 @@ fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi |
| 4250 | 4347 | |
| 4251 | 4348 | fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4252 | 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 | 4353 | const result = result: { |
| 4256 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4257 | const non_null_bit = try func.allocStack(Type.initTag(.u1)); | |
| 4354 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4355 | const non_null_bit = try func.allocStack(Type.u1); | |
| 4258 | 4356 | try func.emitWValue(non_null_bit); |
| 4259 | 4357 | try func.addImm32(1); |
| 4260 | 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 | 4360 | } |
| 4263 | 4361 | |
| 4264 | 4362 | const operand = try func.resolveInst(ty_op.operand); |
| 4265 | const op_ty = func.air.typeOfIndex(inst); | |
| 4266 | if (op_ty.optionalReprIsPayload()) { | |
| 4363 | const op_ty = func.typeOfIndex(inst); | |
| 4364 | if (op_ty.optionalReprIsPayload(mod)) { | |
| 4267 | 4365 | break :result func.reuseOperand(ty_op.operand, operand); |
| 4268 | 4366 | } |
| 4269 | const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse { | |
| 4270 | const module = func.bin_file.base.options.module.?; | |
| 4271 | return func.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(module)}); | |
| 4367 | const offset = std.math.cast(u32, payload_ty.abiSize(mod)) orelse { | |
| 4368 | return func.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(mod)}); | |
| 4272 | 4369 | }; |
| 4273 | 4370 | |
| 4274 | 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 | 4388 | |
| 4292 | 4389 | const lhs = try func.resolveInst(bin_op.lhs); |
| 4293 | 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 | 4393 | const slice = try func.allocStack(slice_ty); |
| 4297 | 4394 | try func.store(slice, lhs, Type.usize, 0); |
| ... | ... | @@ -4308,13 +4405,14 @@ fn airSliceLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4308 | 4405 | } |
| 4309 | 4406 | |
| 4310 | 4407 | fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4408 | const mod = func.bin_file.base.options.module.?; | |
| 4311 | 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 | 4412 | const slice = try func.resolveInst(bin_op.lhs); |
| 4315 | 4413 | const index = try func.resolveInst(bin_op.rhs); |
| 4316 | const elem_ty = slice_ty.childType(); | |
| 4317 | const elem_size = elem_ty.abiSize(func.target); | |
| 4414 | const elem_ty = slice_ty.childType(mod); | |
| 4415 | const elem_size = elem_ty.abiSize(mod); | |
| 4318 | 4416 | |
| 4319 | 4417 | // load pointer onto stack |
| 4320 | 4418 | _ = try func.load(slice, Type.usize, 0); |
| ... | ... | @@ -4328,7 +4426,7 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4328 | 4426 | const result_ptr = try func.allocLocal(Type.usize); |
| 4329 | 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 | 4430 | const elem_val = try func.load(result_ptr, elem_ty, 0); |
| 4333 | 4431 | break :result try elem_val.toLocal(func, elem_ty); |
| 4334 | 4432 | } else result_ptr; |
| ... | ... | @@ -4337,11 +4435,12 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4337 | 4435 | } |
| 4338 | 4436 | |
| 4339 | 4437 | fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4438 | const mod = func.bin_file.base.options.module.?; | |
| 4340 | 4439 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4341 | 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(); | |
| 4344 | const elem_size = elem_ty.abiSize(func.target); | |
| 4442 | const elem_ty = func.air.getRefType(ty_pl.ty).childType(mod); | |
| 4443 | const elem_size = elem_ty.abiSize(mod); | |
| 4345 | 4444 | |
| 4346 | 4445 | const slice = try func.resolveInst(bin_op.lhs); |
| 4347 | 4446 | const index = try func.resolveInst(bin_op.rhs); |
| ... | ... | @@ -4380,7 +4479,7 @@ fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4380 | 4479 | |
| 4381 | 4480 | const operand = try func.resolveInst(ty_op.operand); |
| 4382 | 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 | 4484 | const result = try func.trunc(operand, wanted_ty, op_ty); |
| 4386 | 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 | 4488 | /// Truncates a given operand to a given type, discarding any overflown bits. |
| 4390 | 4489 | /// NOTE: Resulting value is left on the stack. |
| 4391 | 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 | 4493 | if (toWasmBits(given_bits) == null) { |
| 4394 | 4494 | return func.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{given_bits}); |
| 4395 | 4495 | } |
| 4396 | 4496 | |
| 4397 | 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 | 4499 | const wasm_bits = toWasmBits(wanted_bits).?; |
| 4400 | 4500 | if (wasm_bits != wanted_bits) { |
| 4401 | 4501 | result = try func.wrapOperand(result, wanted_ty); |
| ... | ... | @@ -4412,32 +4512,34 @@ fn airBoolToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4412 | 4512 | } |
| 4413 | 4513 | |
| 4414 | 4514 | fn airArrayToSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4515 | const mod = func.bin_file.base.options.module.?; | |
| 4415 | 4516 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4416 | 4517 | |
| 4417 | 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 | 4520 | const slice_ty = func.air.getRefType(ty_op.ty); |
| 4420 | 4521 | |
| 4421 | 4522 | // create a slice on the stack |
| 4422 | 4523 | const slice_local = try func.allocStack(slice_ty); |
| 4423 | 4524 | |
| 4424 | 4525 | // store the array ptr in the slice |
| 4425 | if (array_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4526 | if (array_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4426 | 4527 | try func.store(slice_local, operand, Type.usize, 0); |
| 4427 | 4528 | } |
| 4428 | 4529 | |
| 4429 | 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 | 4532 | try func.store(slice_local, len, Type.usize, func.ptrSize()); |
| 4432 | 4533 | |
| 4433 | 4534 | func.finishAir(inst, slice_local, &.{ty_op.operand}); |
| 4434 | 4535 | } |
| 4435 | 4536 | |
| 4436 | 4537 | fn airPtrToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4538 | const mod = func.bin_file.base.options.module.?; | |
| 4437 | 4539 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 4438 | 4540 | const operand = try func.resolveInst(un_op); |
| 4439 | const ptr_ty = func.air.typeOf(un_op); | |
| 4440 | const result = if (ptr_ty.isSlice()) | |
| 4541 | const ptr_ty = func.typeOf(un_op); | |
| 4542 | const result = if (ptr_ty.isSlice(mod)) | |
| 4441 | 4543 | try func.slicePtr(operand) |
| 4442 | 4544 | else switch (operand) { |
| 4443 | 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 | 4550 | } |
| 4449 | 4551 | |
| 4450 | 4552 | fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4553 | const mod = func.bin_file.base.options.module.?; | |
| 4451 | 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 | 4557 | const ptr = try func.resolveInst(bin_op.lhs); |
| 4455 | 4558 | const index = try func.resolveInst(bin_op.rhs); |
| 4456 | const elem_ty = ptr_ty.childType(); | |
| 4457 | const elem_size = elem_ty.abiSize(func.target); | |
| 4559 | const elem_ty = ptr_ty.childType(mod); | |
| 4560 | const elem_size = elem_ty.abiSize(mod); | |
| 4458 | 4561 | |
| 4459 | 4562 | // load pointer onto the stack |
| 4460 | if (ptr_ty.isSlice()) { | |
| 4563 | if (ptr_ty.isSlice(mod)) { | |
| 4461 | 4564 | _ = try func.load(ptr, Type.usize, 0); |
| 4462 | 4565 | } else { |
| 4463 | 4566 | try func.lowerToStack(ptr); |
| ... | ... | @@ -4472,7 +4575,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4472 | 4575 | const elem_result = val: { |
| 4473 | 4576 | var result = try func.allocLocal(Type.usize); |
| 4474 | 4577 | try func.addLabel(.local_set, result.local.value); |
| 4475 | if (isByRef(elem_ty, func.target)) { | |
| 4578 | if (isByRef(elem_ty, mod)) { | |
| 4476 | 4579 | break :val result; |
| 4477 | 4580 | } |
| 4478 | 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 | 4587 | } |
| 4485 | 4588 | |
| 4486 | 4589 | fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4590 | const mod = func.bin_file.base.options.module.?; | |
| 4487 | 4591 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4488 | 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); | |
| 4491 | const elem_ty = func.air.getRefType(ty_pl.ty).childType(); | |
| 4492 | const elem_size = elem_ty.abiSize(func.target); | |
| 4594 | const ptr_ty = func.typeOf(bin_op.lhs); | |
| 4595 | const elem_ty = func.air.getRefType(ty_pl.ty).childType(mod); | |
| 4596 | const elem_size = elem_ty.abiSize(mod); | |
| 4493 | 4597 | |
| 4494 | 4598 | const ptr = try func.resolveInst(bin_op.lhs); |
| 4495 | 4599 | const index = try func.resolveInst(bin_op.rhs); |
| 4496 | 4600 | |
| 4497 | 4601 | // load pointer onto the stack |
| 4498 | if (ptr_ty.isSlice()) { | |
| 4602 | if (ptr_ty.isSlice(mod)) { | |
| 4499 | 4603 | _ = try func.load(ptr, Type.usize, 0); |
| 4500 | 4604 | } else { |
| 4501 | 4605 | try func.lowerToStack(ptr); |
| ... | ... | @@ -4513,24 +4617,25 @@ fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4513 | 4617 | } |
| 4514 | 4618 | |
| 4515 | 4619 | fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 4620 | const mod = func.bin_file.base.options.module.?; | |
| 4516 | 4621 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4517 | 4622 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 4518 | 4623 | |
| 4519 | 4624 | const ptr = try func.resolveInst(bin_op.lhs); |
| 4520 | 4625 | const offset = try func.resolveInst(bin_op.rhs); |
| 4521 | const ptr_ty = func.air.typeOf(bin_op.lhs); | |
| 4522 | const pointee_ty = switch (ptr_ty.ptrSize()) { | |
| 4523 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | |
| 4524 | else => ptr_ty.childType(), | |
| 4626 | const ptr_ty = func.typeOf(bin_op.lhs); | |
| 4627 | const pointee_ty = switch (ptr_ty.ptrSize(mod)) { | |
| 4628 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type | |
| 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 | 4633 | const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul }); |
| 4529 | 4634 | const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op }); |
| 4530 | 4635 | |
| 4531 | 4636 | try func.lowerToStack(ptr); |
| 4532 | 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 | 4639 | try func.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode)); |
| 4535 | 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 | 4645 | } |
| 4541 | 4646 | |
| 4542 | 4647 | fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 4648 | const mod = func.bin_file.base.options.module.?; | |
| 4543 | 4649 | if (safety) { |
| 4544 | 4650 | // TODO if the value is undef, write 0xaa bytes to dest |
| 4545 | 4651 | } else { |
| ... | ... | @@ -4548,18 +4654,18 @@ fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void |
| 4548 | 4654 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 4549 | 4655 | |
| 4550 | 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 | 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 | 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 | 4662 | .C, .Many => unreachable, |
| 4557 | 4663 | }; |
| 4558 | 4664 | |
| 4559 | const elem_ty = if (ptr_ty.ptrSize() == .One) | |
| 4560 | ptr_ty.childType().childType() | |
| 4665 | const elem_ty = if (ptr_ty.ptrSize(mod) == .One) | |
| 4666 | ptr_ty.childType(mod).childType(mod) | |
| 4561 | 4667 | else |
| 4562 | ptr_ty.childType(); | |
| 4668 | ptr_ty.childType(mod); | |
| 4563 | 4669 | |
| 4564 | 4670 | const dst_ptr = try func.sliceOrArrayPtr(ptr, ptr_ty); |
| 4565 | 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 | 4678 | /// this to wasm's memset instruction. When the feature is not present, |
| 4573 | 4679 | /// we implement it manually. |
| 4574 | 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 | 4684 | // When bulk_memory is enabled, we lower it to wasm's memset instruction. |
| 4578 | 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 | 4767 | } |
| 4661 | 4768 | |
| 4662 | 4769 | fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4770 | const mod = func.bin_file.base.options.module.?; | |
| 4663 | 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 | 4774 | const array = try func.resolveInst(bin_op.lhs); |
| 4667 | 4775 | const index = try func.resolveInst(bin_op.rhs); |
| 4668 | const elem_ty = array_ty.childType(); | |
| 4669 | const elem_size = elem_ty.abiSize(func.target); | |
| 4776 | const elem_ty = array_ty.childType(mod); | |
| 4777 | const elem_size = elem_ty.abiSize(mod); | |
| 4670 | 4778 | |
| 4671 | if (isByRef(array_ty, func.target)) { | |
| 4779 | if (isByRef(array_ty, mod)) { | |
| 4672 | 4780 | try func.lowerToStack(array); |
| 4673 | 4781 | try func.emitWValue(index); |
| 4674 | 4782 | try func.addImm32(@bitCast(i32, @intCast(u32, elem_size))); |
| 4675 | 4783 | try func.addTag(.i32_mul); |
| 4676 | 4784 | try func.addTag(.i32_add); |
| 4677 | 4785 | } else { |
| 4678 | std.debug.assert(array_ty.zigTypeTag() == .Vector); | |
| 4786 | std.debug.assert(array_ty.zigTypeTag(mod) == .Vector); | |
| 4679 | 4787 | |
| 4680 | 4788 | switch (index) { |
| 4681 | 4789 | inline .imm32, .imm64 => |lane| { |
| 4682 | const opcode: wasm.SimdOpcode = switch (elem_ty.bitSize(func.target)) { | |
| 4683 | 8 => if (elem_ty.isSignedInt()) .i8x16_extract_lane_s else .i8x16_extract_lane_u, | |
| 4684 | 16 => if (elem_ty.isSignedInt()) .i16x8_extract_lane_s else .i16x8_extract_lane_u, | |
| 4685 | 32 => if (elem_ty.isInt()) .i32x4_extract_lane else .f32x4_extract_lane, | |
| 4686 | 64 => if (elem_ty.isInt()) .i64x2_extract_lane else .f64x2_extract_lane, | |
| 4790 | const opcode: wasm.SimdOpcode = switch (elem_ty.bitSize(mod)) { | |
| 4791 | 8 => if (elem_ty.isSignedInt(mod)) .i8x16_extract_lane_s else .i8x16_extract_lane_u, | |
| 4792 | 16 => if (elem_ty.isSignedInt(mod)) .i16x8_extract_lane_s else .i16x8_extract_lane_u, | |
| 4793 | 32 => if (elem_ty.isInt(mod)) .i32x4_extract_lane else .f32x4_extract_lane, | |
| 4794 | 64 => if (elem_ty.isInt(mod)) .i64x2_extract_lane else .f64x2_extract_lane, | |
| 4687 | 4795 | else => unreachable, |
| 4688 | 4796 | }; |
| 4689 | 4797 | |
| ... | ... | @@ -4715,7 +4823,7 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4715 | 4823 | var result = try func.allocLocal(Type.usize); |
| 4716 | 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 | 4827 | break :val result; |
| 4720 | 4828 | } |
| 4721 | 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 | 4836 | } |
| 4729 | 4837 | |
| 4730 | 4838 | fn airFloatToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4839 | const mod = func.bin_file.base.options.module.?; | |
| 4731 | 4840 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4732 | 4841 | |
| 4733 | 4842 | const operand = try func.resolveInst(ty_op.operand); |
| 4734 | const dest_ty = func.air.typeOfIndex(inst); | |
| 4735 | const op_ty = func.air.typeOf(ty_op.operand); | |
| 4843 | const dest_ty = func.typeOfIndex(inst); | |
| 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 | 4847 | return func.fail("TODO: floatToInt for integers/floats with bitsize larger than 64 bits", .{}); |
| 4739 | 4848 | } |
| 4740 | 4849 | |
| 4741 | 4850 | try func.emitWValue(operand); |
| 4742 | 4851 | const op = buildOpcode(.{ |
| 4743 | 4852 | .op = .trunc, |
| 4744 | .valtype1 = typeToValtype(dest_ty, func.target), | |
| 4745 | .valtype2 = typeToValtype(op_ty, func.target), | |
| 4746 | .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned, | |
| 4853 | .valtype1 = typeToValtype(dest_ty, mod), | |
| 4854 | .valtype2 = typeToValtype(op_ty, mod), | |
| 4855 | .signedness = if (dest_ty.isSignedInt(mod)) .signed else .unsigned, | |
| 4747 | 4856 | }); |
| 4748 | 4857 | try func.addTag(Mir.Inst.Tag.fromOpcode(op)); |
| 4749 | 4858 | const wrapped = try func.wrapOperand(.{ .stack = {} }, dest_ty); |
| ... | ... | @@ -4752,22 +4861,23 @@ fn airFloatToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4752 | 4861 | } |
| 4753 | 4862 | |
| 4754 | 4863 | fn airIntToFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4864 | const mod = func.bin_file.base.options.module.?; | |
| 4755 | 4865 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4756 | 4866 | |
| 4757 | 4867 | const operand = try func.resolveInst(ty_op.operand); |
| 4758 | const dest_ty = func.air.typeOfIndex(inst); | |
| 4759 | const op_ty = func.air.typeOf(ty_op.operand); | |
| 4868 | const dest_ty = func.typeOfIndex(inst); | |
| 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 | 4872 | return func.fail("TODO: intToFloat for integers/floats with bitsize larger than 64 bits", .{}); |
| 4763 | 4873 | } |
| 4764 | 4874 | |
| 4765 | 4875 | try func.emitWValue(operand); |
| 4766 | 4876 | const op = buildOpcode(.{ |
| 4767 | 4877 | .op = .convert, |
| 4768 | .valtype1 = typeToValtype(dest_ty, func.target), | |
| 4769 | .valtype2 = typeToValtype(op_ty, func.target), | |
| 4770 | .signedness = if (op_ty.isSignedInt()) .signed else .unsigned, | |
| 4878 | .valtype1 = typeToValtype(dest_ty, mod), | |
| 4879 | .valtype2 = typeToValtype(op_ty, mod), | |
| 4880 | .signedness = if (op_ty.isSignedInt(mod)) .signed else .unsigned, | |
| 4771 | 4881 | }); |
| 4772 | 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 | 4887 | } |
| 4778 | 4888 | |
| 4779 | 4889 | fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4890 | const mod = func.bin_file.base.options.module.?; | |
| 4780 | 4891 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4781 | 4892 | const operand = try func.resolveInst(ty_op.operand); |
| 4782 | const ty = func.air.typeOfIndex(inst); | |
| 4783 | const elem_ty = ty.childType(); | |
| 4893 | const ty = func.typeOfIndex(inst); | |
| 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 | 4897 | switch (operand) { |
| 4787 | 4898 | // when the operand lives in the linear memory section, we can directly |
| 4788 | 4899 | // load and splat the value at once. Meaning we do not first have to load |
| 4789 | 4900 | // the scalar value onto the stack. |
| 4790 | 4901 | .stack_offset, .memory, .memory_offset => { |
| 4791 | const opcode = switch (elem_ty.bitSize(func.target)) { | |
| 4902 | const opcode = switch (elem_ty.bitSize(mod)) { | |
| 4792 | 4903 | 8 => std.wasm.simdOpcode(.v128_load8_splat), |
| 4793 | 4904 | 16 => std.wasm.simdOpcode(.v128_load16_splat), |
| 4794 | 4905 | 32 => std.wasm.simdOpcode(.v128_load32_splat), |
| ... | ... | @@ -4803,18 +4914,18 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4803 | 4914 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 4804 | 4915 | opcode, |
| 4805 | 4916 | operand.offset(), |
| 4806 | elem_ty.abiAlignment(func.target), | |
| 4917 | elem_ty.abiAlignment(mod), | |
| 4807 | 4918 | }); |
| 4808 | 4919 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 4809 | 4920 | try func.addLabel(.local_set, result.local.value); |
| 4810 | 4921 | return func.finishAir(inst, result, &.{ty_op.operand}); |
| 4811 | 4922 | }, |
| 4812 | 4923 | .local => { |
| 4813 | const opcode = switch (elem_ty.bitSize(func.target)) { | |
| 4924 | const opcode = switch (elem_ty.bitSize(mod)) { | |
| 4814 | 4925 | 8 => std.wasm.simdOpcode(.i8x16_splat), |
| 4815 | 4926 | 16 => std.wasm.simdOpcode(.i16x8_splat), |
| 4816 | 32 => if (elem_ty.isInt()) 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), | |
| 4927 | 32 => if (elem_ty.isInt(mod)) std.wasm.simdOpcode(.i32x4_splat) else std.wasm.simdOpcode(.f32x4_splat), | |
| 4928 | 64 => if (elem_ty.isInt(mod)) std.wasm.simdOpcode(.i64x2_splat) else std.wasm.simdOpcode(.f64x2_splat), | |
| 4818 | 4929 | else => break :blk, // Cannot make use of simd-instructions |
| 4819 | 4930 | }; |
| 4820 | 4931 | const result = try func.allocLocal(ty); |
| ... | ... | @@ -4828,14 +4939,14 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4828 | 4939 | else => unreachable, |
| 4829 | 4940 | } |
| 4830 | 4941 | } |
| 4831 | const elem_size = elem_ty.bitSize(func.target); | |
| 4832 | const vector_len = @intCast(usize, ty.vectorLen()); | |
| 4942 | const elem_size = elem_ty.bitSize(mod); | |
| 4943 | const vector_len = @intCast(usize, ty.vectorLen(mod)); | |
| 4833 | 4944 | if ((!std.math.isPowerOfTwo(elem_size) or elem_size % 8 != 0) and vector_len > 1) { |
| 4834 | 4945 | return func.fail("TODO: WebAssembly `@splat` for arbitrary element bitsize {d}", .{elem_size}); |
| 4835 | 4946 | } |
| 4836 | 4947 | |
| 4837 | 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 | 4950 | var index: usize = 0; |
| 4840 | 4951 | var offset: u32 = 0; |
| 4841 | 4952 | while (index < vector_len) : (index += 1) { |
| ... | ... | @@ -4855,26 +4966,25 @@ fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4855 | 4966 | } |
| 4856 | 4967 | |
| 4857 | 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 | 4971 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4860 | 4972 | const extra = func.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 4861 | 4973 | |
| 4862 | 4974 | const a = try func.resolveInst(extra.a); |
| 4863 | 4975 | const b = try func.resolveInst(extra.b); |
| 4864 | const mask = func.air.values[extra.mask]; | |
| 4976 | const mask = extra.mask.toValue(); | |
| 4865 | 4977 | const mask_len = extra.mask_len; |
| 4866 | 4978 | |
| 4867 | const child_ty = inst_ty.childType(); | |
| 4868 | const elem_size = child_ty.abiSize(func.target); | |
| 4979 | const child_ty = inst_ty.childType(mod); | |
| 4980 | const elem_size = child_ty.abiSize(mod); | |
| 4869 | 4981 | |
| 4870 | const module = func.bin_file.base.options.module.?; | |
| 4871 | 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 | 4984 | const result = try func.allocStack(inst_ty); |
| 4874 | 4985 | |
| 4875 | 4986 | for (0..mask_len) |index| { |
| 4876 | var buf: Value.ElemValueBuffer = undefined; | |
| 4877 | const value = mask.elemValueBuffer(module, index, &buf).toSignedInt(func.target); | |
| 4987 | const value = (try mask.elemValue(mod, index)).toSignedInt(mod); | |
| 4878 | 4988 | |
| 4879 | 4989 | try func.emitWValue(result); |
| 4880 | 4990 | |
| ... | ... | @@ -4894,8 +5004,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4894 | 5004 | |
| 4895 | 5005 | var lanes = std.mem.asBytes(operands[1..]); |
| 4896 | 5006 | for (0..@intCast(usize, mask_len)) |index| { |
| 4897 | var buf: Value.ElemValueBuffer = undefined; | |
| 4898 | const mask_elem = mask.elemValueBuffer(module, index, &buf).toSignedInt(func.target); | |
| 5007 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); | |
| 4899 | 5008 | const base_index = if (mask_elem >= 0) |
| 4900 | 5009 | @intCast(u8, @intCast(i64, elem_size) * mask_elem) |
| 4901 | 5010 | else |
| ... | ... | @@ -4926,25 +5035,26 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4926 | 5035 | } |
| 4927 | 5036 | |
| 4928 | 5037 | fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5038 | const mod = func.bin_file.base.options.module.?; | |
| 4929 | 5039 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4930 | const result_ty = func.air.typeOfIndex(inst); | |
| 4931 | const len = @intCast(usize, result_ty.arrayLen()); | |
| 5040 | const result_ty = func.typeOfIndex(inst); | |
| 5041 | const len = @intCast(usize, result_ty.arrayLen(mod)); | |
| 4932 | 5042 | const elements = @ptrCast([]const Air.Inst.Ref, func.air.extra[ty_pl.payload..][0..len]); |
| 4933 | 5043 | |
| 4934 | 5044 | const result: WValue = result_value: { |
| 4935 | switch (result_ty.zigTypeTag()) { | |
| 5045 | switch (result_ty.zigTypeTag(mod)) { | |
| 4936 | 5046 | .Array => { |
| 4937 | 5047 | const result = try func.allocStack(result_ty); |
| 4938 | const elem_ty = result_ty.childType(); | |
| 4939 | const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); | |
| 4940 | const sentinel = if (result_ty.sentinel()) |sent| blk: { | |
| 5048 | const elem_ty = result_ty.childType(mod); | |
| 5049 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | |
| 5050 | const sentinel = if (result_ty.sentinel(mod)) |sent| blk: { | |
| 4941 | 5051 | break :blk try func.lowerConstant(sent, elem_ty); |
| 4942 | 5052 | } else null; |
| 4943 | 5053 | |
| 4944 | 5054 | // When the element type is by reference, we must copy the entire |
| 4945 | 5055 | // value. It is therefore safer to move the offset pointer and store |
| 4946 | 5056 | // each value individually, instead of using store offsets. |
| 4947 | if (isByRef(elem_ty, func.target)) { | |
| 5057 | if (isByRef(elem_ty, mod)) { | |
| 4948 | 5058 | // copy stack pointer into a temporary local, which is |
| 4949 | 5059 | // moved for each element to store each value in the right position. |
| 4950 | 5060 | const offset = try func.buildPointerOffset(result, 0, .new); |
| ... | ... | @@ -4972,18 +5082,18 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4972 | 5082 | } |
| 4973 | 5083 | break :result_value result; |
| 4974 | 5084 | }, |
| 4975 | .Struct => switch (result_ty.containerLayout()) { | |
| 5085 | .Struct => switch (result_ty.containerLayout(mod)) { | |
| 4976 | 5086 | .Packed => { |
| 4977 | if (isByRef(result_ty, func.target)) { | |
| 5087 | if (isByRef(result_ty, mod)) { | |
| 4978 | 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 | 5091 | const fields = struct_obj.fields.values(); |
| 4982 | 5092 | const backing_type = struct_obj.backing_int_ty; |
| 4983 | 5093 | |
| 4984 | 5094 | // ensure the result is zero'd |
| 4985 | 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 | 5097 | try func.addImm32(0) |
| 4988 | 5098 | else |
| 4989 | 5099 | try func.addImm64(0); |
| ... | ... | @@ -4992,20 +5102,16 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4992 | 5102 | var current_bit: u16 = 0; |
| 4993 | 5103 | for (elements, 0..) |elem, elem_index| { |
| 4994 | 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 | 5108 | WValue{ .imm32 = current_bit } |
| 4999 | 5109 | else |
| 5000 | 5110 | WValue{ .imm64 = current_bit }; |
| 5001 | 5111 | |
| 5002 | 5112 | const value = try func.resolveInst(elem); |
| 5003 | const value_bit_size = @intCast(u16, field.ty.bitSize(func.target)); | |
| 5004 | var int_ty_payload: Type.Payload.Bits = .{ | |
| 5005 | .base = .{ .tag = .int_unsigned }, | |
| 5006 | .data = value_bit_size, | |
| 5007 | }; | |
| 5008 | const int_ty = Type.initPayload(&int_ty_payload.base); | |
| 5113 | const value_bit_size = @intCast(u16, field.ty.bitSize(mod)); | |
| 5114 | const int_ty = try mod.intType(.unsigned, value_bit_size); | |
| 5009 | 5115 | |
| 5010 | 5116 | // load our current result on stack so we can perform all transformations |
| 5011 | 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 | 5133 | const result = try func.allocStack(result_ty); |
| 5028 | 5134 | const offset = try func.buildPointerOffset(result, 0, .new); // pointer to offset |
| 5029 | 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); | |
| 5033 | const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); | |
| 5138 | const elem_ty = result_ty.structFieldType(elem_index, mod); | |
| 5139 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | |
| 5034 | 5140 | const value = try func.resolveInst(elem); |
| 5035 | 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 | 5164 | } |
| 5059 | 5165 | |
| 5060 | 5166 | fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5167 | const mod = func.bin_file.base.options.module.?; | |
| 5061 | 5168 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5062 | 5169 | const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 5063 | 5170 | |
| 5064 | 5171 | const result = result: { |
| 5065 | const union_ty = func.air.typeOfIndex(inst); | |
| 5066 | const layout = union_ty.unionGetLayout(func.target); | |
| 5067 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | |
| 5172 | const union_ty = func.typeOfIndex(inst); | |
| 5173 | const layout = union_ty.unionGetLayout(mod); | |
| 5174 | const union_obj = mod.typeToUnion(union_ty).?; | |
| 5068 | 5175 | const field = union_obj.fields.values()[extra.field_index]; |
| 5069 | 5176 | const field_name = union_obj.fields.keys()[extra.field_index]; |
| 5070 | 5177 | |
| 5071 | 5178 | const tag_int = blk: { |
| 5072 | const tag_ty = union_ty.unionTagTypeHypothetical(); | |
| 5073 | const enum_field_index = tag_ty.enumFieldIndex(field_name).?; | |
| 5074 | var tag_val_payload: Value.Payload.U32 = .{ | |
| 5075 | .base = .{ .tag = .enum_field_index }, | |
| 5076 | .data = @intCast(u32, enum_field_index), | |
| 5077 | }; | |
| 5078 | const tag_val = Value.initPayload(&tag_val_payload.base); | |
| 5179 | const tag_ty = union_ty.unionTagTypeHypothetical(mod); | |
| 5180 | const enum_field_index = tag_ty.enumFieldIndex(field_name, mod).?; | |
| 5181 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); | |
| 5079 | 5182 | break :blk try func.lowerConstant(tag_val, tag_ty); |
| 5080 | 5183 | }; |
| 5081 | 5184 | if (layout.payload_size == 0) { |
| 5082 | 5185 | if (layout.tag_size == 0) { |
| 5083 | 5186 | break :result WValue{ .none = {} }; |
| 5084 | 5187 | } |
| 5085 | assert(!isByRef(union_ty, func.target)); | |
| 5188 | assert(!isByRef(union_ty, mod)); | |
| 5086 | 5189 | break :result tag_int; |
| 5087 | 5190 | } |
| 5088 | 5191 | |
| 5089 | if (isByRef(union_ty, func.target)) { | |
| 5192 | if (isByRef(union_ty, mod)) { | |
| 5090 | 5193 | const result_ptr = try func.allocStack(union_ty); |
| 5091 | 5194 | const payload = try func.resolveInst(extra.init); |
| 5092 | 5195 | if (layout.tag_align >= layout.payload_align) { |
| 5093 | if (isByRef(field.ty, func.target)) { | |
| 5196 | if (isByRef(field.ty, mod)) { | |
| 5094 | 5197 | const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); |
| 5095 | 5198 | try func.store(payload_ptr, payload, field.ty, 0); |
| 5096 | 5199 | } else { |
| ... | ... | @@ -5114,26 +5217,14 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5114 | 5217 | break :result result_ptr; |
| 5115 | 5218 | } else { |
| 5116 | 5219 | const operand = try func.resolveInst(extra.init); |
| 5117 | var payload: Type.Payload.Bits = .{ | |
| 5118 | .base = .{ .tag = .int_unsigned }, | |
| 5119 | .data = @intCast(u16, union_ty.bitSize(func.target)), | |
| 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); | |
| 5220 | const union_int_type = try mod.intType(.unsigned, @intCast(u16, union_ty.bitSize(mod))); | |
| 5221 | if (field.ty.zigTypeTag(mod) == .Float) { | |
| 5222 | const int_type = try mod.intType(.unsigned, @intCast(u16, field.ty.bitSize(mod))); | |
| 5128 | 5223 | const bitcasted = try func.bitcast(field.ty, int_type, operand); |
| 5129 | 5224 | const casted = try func.trunc(bitcasted, int_type, union_int_type); |
| 5130 | 5225 | break :result try casted.toLocal(func, field.ty); |
| 5131 | } else if (field.ty.isPtrAtRuntime()) { | |
| 5132 | var int_payload: Type.Payload.Bits = .{ | |
| 5133 | .base = .{ .tag = .int_unsigned }, | |
| 5134 | .data = @intCast(u16, field.ty.bitSize(func.target)), | |
| 5135 | }; | |
| 5136 | const int_type = Type.initPayload(&int_payload.base); | |
| 5226 | } else if (field.ty.isPtrAtRuntime(mod)) { | |
| 5227 | const int_type = try mod.intType(.unsigned, @intCast(u16, field.ty.bitSize(mod))); | |
| 5137 | 5228 | const casted = try func.intcast(operand, int_type, union_int_type); |
| 5138 | 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 | 5244 | fn airWasmMemorySize(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5154 | 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 | 5248 | try func.addLabel(.memory_size, pl_op.payload); |
| 5158 | 5249 | try func.addLabel(.local_set, result.local.value); |
| 5159 | 5250 | func.finishAir(inst, result, &.{pl_op.operand}); |
| ... | ... | @@ -5163,7 +5254,7 @@ fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void { |
| 5163 | 5254 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 5164 | 5255 | |
| 5165 | 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 | 5258 | try func.emitWValue(operand); |
| 5168 | 5259 | try func.addLabel(.memory_grow, pl_op.payload); |
| 5169 | 5260 | try func.addLabel(.local_set, result.local.value); |
| ... | ... | @@ -5171,14 +5262,14 @@ fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void { |
| 5171 | 5262 | } |
| 5172 | 5263 | |
| 5173 | 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 | 5267 | assert(op == .eq or op == .neq); |
| 5176 | var buf: Type.Payload.ElemType = undefined; | |
| 5177 | const payload_ty = operand_ty.optionalChild(&buf); | |
| 5268 | const payload_ty = operand_ty.optionalChild(mod); | |
| 5178 | 5269 | |
| 5179 | 5270 | // We store the final result in here that will be validated |
| 5180 | 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 | 5273 | defer result.free(func); |
| 5183 | 5274 | |
| 5184 | 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 | 5280 | |
| 5190 | 5281 | _ = try func.load(lhs, payload_ty, 0); |
| 5191 | 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 | 5284 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 5194 | 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 | 5298 | /// NOTE: Leaves the result of the comparison on top of the stack. |
| 5208 | 5299 | /// TODO: Lower this to compiler_rt call when bitsize > 128 |
| 5209 | 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 | 5303 | assert(!(lhs != .stack and rhs == .stack)); |
| 5212 | if (operand_ty.bitSize(func.target) > 128) { | |
| 5213 | return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(func.target)}); | |
| 5304 | if (operand_ty.bitSize(mod) > 128) { | |
| 5305 | return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(mod)}); | |
| 5214 | 5306 | } |
| 5215 | 5307 | |
| 5216 | 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 | 5325 | } |
| 5234 | 5326 | }, |
| 5235 | 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 | 5329 | // leave those value on top of the stack for '.select' |
| 5238 | 5330 | const lhs_low_bit = try func.load(lhs, Type.u64, 8); |
| 5239 | 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 | 5340 | } |
| 5249 | 5341 | |
| 5250 | 5342 | fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5343 | const mod = func.bin_file.base.options.module.?; | |
| 5251 | 5344 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 5252 | const un_ty = func.air.typeOf(bin_op.lhs).childType(); | |
| 5253 | const tag_ty = func.air.typeOf(bin_op.rhs); | |
| 5254 | const layout = un_ty.unionGetLayout(func.target); | |
| 5345 | const un_ty = func.typeOf(bin_op.lhs).childType(mod); | |
| 5346 | const tag_ty = func.typeOf(bin_op.rhs); | |
| 5347 | const layout = un_ty.unionGetLayout(mod); | |
| 5255 | 5348 | if (layout.tag_size == 0) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| 5256 | 5349 | |
| 5257 | 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 | 5364 | } |
| 5272 | 5365 | |
| 5273 | 5366 | fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5367 | const mod = func.bin_file.base.options.module.?; | |
| 5274 | 5368 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5275 | 5369 | |
| 5276 | const un_ty = func.air.typeOf(ty_op.operand); | |
| 5277 | const tag_ty = func.air.typeOfIndex(inst); | |
| 5278 | const layout = un_ty.unionGetLayout(func.target); | |
| 5370 | const un_ty = func.typeOf(ty_op.operand); | |
| 5371 | const tag_ty = func.typeOfIndex(inst); | |
| 5372 | const layout = un_ty.unionGetLayout(mod); | |
| 5279 | 5373 | if (layout.tag_size == 0) return func.finishAir(inst, .none, &.{ty_op.operand}); |
| 5280 | 5374 | |
| 5281 | 5375 | const operand = try func.resolveInst(ty_op.operand); |
| ... | ... | @@ -5292,9 +5386,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5292 | 5386 | fn airFpext(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5293 | 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 | 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 | 5392 | const result = try extended.toLocal(func, dest_ty); |
| 5299 | 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 | 5407 | // call __extendhfsf2(f16) f32 |
| 5314 | 5408 | const f32_result = try func.callIntrinsic( |
| 5315 | 5409 | "__extendhfsf2", |
| 5316 | &.{Type.f16}, | |
| 5410 | &.{.f16_type}, | |
| 5317 | 5411 | Type.f32, |
| 5318 | 5412 | &.{operand}, |
| 5319 | 5413 | ); |
| ... | ... | @@ -5331,15 +5425,15 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError! |
| 5331 | 5425 | target_util.compilerRtFloatAbbrev(wanted_bits), |
| 5332 | 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 | 5431 | fn airFptrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5338 | 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 | 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 | 5437 | const result = try truncated.toLocal(func, dest_ty); |
| 5344 | 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 | 5456 | } else operand; |
| 5363 | 5457 | |
| 5364 | 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 | 5462 | var fn_name_buf: [12]u8 = undefined; |
| ... | ... | @@ -5371,14 +5465,15 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 5371 | 5465 | target_util.compilerRtFloatAbbrev(wanted_bits), |
| 5372 | 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 | 5471 | fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5472 | const mod = func.bin_file.base.options.module.?; | |
| 5378 | 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(); | |
| 5381 | const payload_ty = err_set_ty.errorUnionPayload(); | |
| 5475 | const err_set_ty = func.typeOf(ty_op.operand).childType(mod); | |
| 5476 | const payload_ty = err_set_ty.errorUnionPayload(mod); | |
| 5382 | 5477 | const operand = try func.resolveInst(ty_op.operand); |
| 5383 | 5478 | |
| 5384 | 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 | 5481 | operand, |
| 5387 | 5482 | .{ .imm32 = 0 }, |
| 5388 | 5483 | Type.anyerror, |
| 5389 | @intCast(u32, errUnionErrorOffset(payload_ty, func.target)), | |
| 5484 | @intCast(u32, errUnionErrorOffset(payload_ty, mod)), | |
| 5390 | 5485 | ); |
| 5391 | 5486 | |
| 5392 | 5487 | const result = result: { |
| 5393 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5488 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 5394 | 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 | 5494 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 5400 | 5495 | } |
| 5401 | 5496 | |
| 5402 | 5497 | fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5498 | const mod = func.bin_file.base.options.module.?; | |
| 5403 | 5499 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5404 | 5500 | const extra = func.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 5405 | 5501 | |
| 5406 | 5502 | const field_ptr = try func.resolveInst(extra.field_ptr); |
| 5407 | const parent_ty = func.air.getRefType(ty_pl.ty).childType(); | |
| 5408 | const field_offset = parent_ty.structFieldOffset(extra.field_index, func.target); | |
| 5503 | const parent_ty = func.air.getRefType(ty_pl.ty).childType(mod); | |
| 5504 | const field_offset = parent_ty.structFieldOffset(extra.field_index, mod); | |
| 5409 | 5505 | |
| 5410 | 5506 | const result = if (field_offset != 0) result: { |
| 5411 | 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 | 5516 | } |
| 5421 | 5517 | |
| 5422 | 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 | 5521 | return func.slicePtr(ptr); |
| 5425 | 5522 | } else { |
| 5426 | 5523 | return ptr; |
| ... | ... | @@ -5428,25 +5525,26 @@ fn sliceOrArrayPtr(func: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue |
| 5428 | 5525 | } |
| 5429 | 5526 | |
| 5430 | 5527 | fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5528 | const mod = func.bin_file.base.options.module.?; | |
| 5431 | 5529 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 5432 | 5530 | const dst = try func.resolveInst(bin_op.lhs); |
| 5433 | const dst_ty = func.air.typeOf(bin_op.lhs); | |
| 5434 | const ptr_elem_ty = dst_ty.childType(); | |
| 5531 | const dst_ty = func.typeOf(bin_op.lhs); | |
| 5532 | const ptr_elem_ty = dst_ty.childType(mod); | |
| 5435 | 5533 | const src = try func.resolveInst(bin_op.rhs); |
| 5436 | const src_ty = func.air.typeOf(bin_op.rhs); | |
| 5437 | const len = switch (dst_ty.ptrSize()) { | |
| 5534 | const src_ty = func.typeOf(bin_op.rhs); | |
| 5535 | const len = switch (dst_ty.ptrSize(mod)) { | |
| 5438 | 5536 | .Slice => blk: { |
| 5439 | 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 | 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 | 5541 | try func.addTag(.i32_mul); |
| 5444 | 5542 | try func.addLabel(.local_set, slice_len.local.value); |
| 5445 | 5543 | } |
| 5446 | 5544 | break :blk slice_len; |
| 5447 | 5545 | }, |
| 5448 | 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 | 5549 | .C, .Many => unreachable, |
| 5452 | 5550 | }; |
| ... | ... | @@ -5467,17 +5565,18 @@ fn airRetAddr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5467 | 5565 | } |
| 5468 | 5566 | |
| 5469 | 5567 | fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5568 | const mod = func.bin_file.base.options.module.?; | |
| 5470 | 5569 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5471 | 5570 | |
| 5472 | 5571 | const operand = try func.resolveInst(ty_op.operand); |
| 5473 | const op_ty = func.air.typeOf(ty_op.operand); | |
| 5474 | const result_ty = func.air.typeOfIndex(inst); | |
| 5572 | const op_ty = func.typeOf(ty_op.operand); | |
| 5573 | const result_ty = func.typeOfIndex(inst); | |
| 5475 | 5574 | |
| 5476 | if (op_ty.zigTypeTag() == .Vector) { | |
| 5575 | if (op_ty.zigTypeTag(mod) == .Vector) { | |
| 5477 | 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 | 5580 | const bits = int_info.bits; |
| 5482 | 5581 | const wasm_bits = toWasmBits(bits) orelse { |
| 5483 | 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 | 5625 | // As the names are global and the slice elements are constant, we do not have |
| 5527 | 5626 | // to make a copy of the ptr+value but can point towards them directly. |
| 5528 | 5627 | const error_table_symbol = try func.bin_file.getErrorTableSymbol(); |
| 5529 | const name_ty = Type.initTag(.const_slice_u8_sentinel_0); | |
| 5530 | const abi_size = name_ty.abiSize(func.target); | |
| 5628 | const name_ty = Type.slice_const_u8_sentinel_0; | |
| 5629 | const mod = func.bin_file.base.options.module.?; | |
| 5630 | const abi_size = name_ty.abiSize(mod); | |
| 5531 | 5631 | |
| 5532 | 5632 | const error_name_value: WValue = .{ .memory = error_table_symbol }; // emitting this will create a relocation |
| 5533 | 5633 | try func.emitWValue(error_name_value); |
| ... | ... | @@ -5565,20 +5665,21 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 5565 | 5665 | |
| 5566 | 5666 | const lhs_op = try func.resolveInst(extra.lhs); |
| 5567 | 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 | 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 | 5676 | const is_signed = int_info.signedness == .signed; |
| 5576 | 5677 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 5577 | 5678 | return func.fail("TODO: Implement {{add/sub}}_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 5578 | 5679 | }; |
| 5579 | 5680 | |
| 5580 | 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 | 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 | 5729 | var overflow_local = try overflow_bit.toLocal(func, Type.u32); |
| 5629 | 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 | 5733 | try func.store(result_ptr, result, lhs_ty, 0); |
| 5633 | const offset = @intCast(u32, lhs_ty.abiSize(func.target)); | |
| 5634 | try func.store(result_ptr, overflow_local, Type.initTag(.u1), offset); | |
| 5734 | const offset = @intCast(u32, lhs_ty.abiSize(mod)); | |
| 5735 | try func.store(result_ptr, overflow_local, Type.u1, offset); | |
| 5635 | 5736 | |
| 5636 | 5737 | func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); |
| 5637 | 5738 | } |
| 5638 | 5739 | |
| 5639 | 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 | 5742 | assert(op == .add or op == .sub); |
| 5641 | const int_info = ty.intInfo(func.target); | |
| 5743 | const int_info = ty.intInfo(mod); | |
| 5642 | 5744 | const is_signed = int_info.signedness == .signed; |
| 5643 | 5745 | if (int_info.bits != 128) { |
| 5644 | 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 | 5791 | |
| 5690 | 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 | 5795 | defer overflow_local.free(func); |
| 5694 | 5796 | |
| 5695 | 5797 | const result_ptr = try func.allocStack(result_ty); |
| 5696 | 5798 | try func.store(result_ptr, high_op_res, Type.u64, 0); |
| 5697 | 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 | 5802 | return result_ptr; |
| 5701 | 5803 | } |
| 5702 | 5804 | |
| 5703 | 5805 | fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5806 | const mod = func.bin_file.base.options.module.?; | |
| 5704 | 5807 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5705 | 5808 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5706 | 5809 | |
| 5707 | 5810 | const lhs = try func.resolveInst(extra.lhs); |
| 5708 | 5811 | const rhs = try func.resolveInst(extra.rhs); |
| 5709 | const lhs_ty = func.air.typeOf(extra.lhs); | |
| 5710 | const rhs_ty = func.air.typeOf(extra.rhs); | |
| 5812 | const lhs_ty = func.typeOf(extra.lhs); | |
| 5813 | const rhs_ty = func.typeOf(extra.rhs); | |
| 5711 | 5814 | |
| 5712 | if (lhs_ty.zigTypeTag() == .Vector) { | |
| 5815 | if (lhs_ty.zigTypeTag(mod) == .Vector) { | |
| 5713 | 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 | 5820 | const is_signed = int_info.signedness == .signed; |
| 5718 | 5821 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 5719 | 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 | 5824 | |
| 5722 | 5825 | // Ensure rhs is coerced to lhs as they must have the same WebAssembly types |
| 5723 | 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 | 5828 | const rhs_final = if (wasm_bits != rhs_wasm_bits) blk: { |
| 5726 | 5829 | const rhs_casted = try func.intcast(rhs, rhs_ty, lhs_ty); |
| 5727 | 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 | 5848 | const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); |
| 5746 | 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 | 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 | 5855 | try func.store(result_ptr, result, lhs_ty, 0); |
| 5753 | const offset = @intCast(u32, lhs_ty.abiSize(func.target)); | |
| 5754 | try func.store(result_ptr, overflow_local, Type.initTag(.u1), offset); | |
| 5856 | const offset = @intCast(u32, lhs_ty.abiSize(mod)); | |
| 5857 | try func.store(result_ptr, overflow_local, Type.u1, offset); | |
| 5755 | 5858 | |
| 5756 | 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 | 5865 | |
| 5763 | 5866 | const lhs = try func.resolveInst(extra.lhs); |
| 5764 | 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 | 5872 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); |
| 5769 | 5873 | } |
| 5770 | 5874 | |
| 5771 | 5875 | // We store the bit if it's overflowed or not in this. As it's zero-initialized |
| 5772 | 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 | 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 | 5881 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 5778 | 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 | 5931 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5828 | 5932 | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| 5829 | 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 | 5935 | var lhs_upcast = try (try func.intcast(lhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); |
| 5832 | 5936 | defer lhs_upcast.free(func); |
| 5833 | 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 | 5951 | |
| 5848 | 5952 | const bin_op = try func.callIntrinsic( |
| 5849 | 5953 | "__multi3", |
| 5850 | &[_]Type{Type.i64} ** 4, | |
| 5851 | Type.initTag(.i128), | |
| 5954 | &[_]InternPool.Index{.i64_type} ** 4, | |
| 5955 | Type.i128, | |
| 5852 | 5956 | &.{ lhs, lhs_shifted, rhs, rhs_shifted }, |
| 5853 | 5957 | ); |
| 5854 | 5958 | const res = try func.allocLocal(lhs_ty); |
| ... | ... | @@ -5871,20 +5975,20 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5871 | 5975 | |
| 5872 | 5976 | const mul1 = try func.callIntrinsic( |
| 5873 | 5977 | "__multi3", |
| 5874 | &[_]Type{Type.i64} ** 4, | |
| 5875 | Type.initTag(.i128), | |
| 5978 | &[_]InternPool.Index{.i64_type} ** 4, | |
| 5979 | Type.i128, | |
| 5876 | 5980 | &.{ lhs_lsb, zero, rhs_msb, zero }, |
| 5877 | 5981 | ); |
| 5878 | 5982 | const mul2 = try func.callIntrinsic( |
| 5879 | 5983 | "__multi3", |
| 5880 | &[_]Type{Type.i64} ** 4, | |
| 5881 | Type.initTag(.i128), | |
| 5984 | &[_]InternPool.Index{.i64_type} ** 4, | |
| 5985 | Type.i128, | |
| 5882 | 5986 | &.{ rhs_lsb, zero, lhs_msb, zero }, |
| 5883 | 5987 | ); |
| 5884 | 5988 | const mul3 = try func.callIntrinsic( |
| 5885 | 5989 | "__multi3", |
| 5886 | &[_]Type{Type.i64} ** 4, | |
| 5887 | Type.initTag(.i128), | |
| 5990 | &[_]InternPool.Index{.i64_type} ** 4, | |
| 5991 | Type.i128, | |
| 5888 | 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 | 6016 | _ = try func.binOp(lsb_or, mul_add_lt, Type.bool, .@"or"); |
| 5913 | 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 | 6020 | try func.emitWValue(tmp_result); |
| 5917 | 6021 | const mul3_msb = try func.load(mul3, Type.u64, 0); |
| 5918 | 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 | 6026 | var bin_op_local = try bin_op.toLocal(func, lhs_ty); |
| 5923 | 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 | 6030 | try func.store(result_ptr, bin_op_local, lhs_ty, 0); |
| 5927 | const offset = @intCast(u32, lhs_ty.abiSize(func.target)); | |
| 5928 | try func.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); | |
| 6031 | const offset = @intCast(u32, lhs_ty.abiSize(mod)); | |
| 6032 | try func.store(result_ptr, overflow_bit, Type.u1, offset); | |
| 5929 | 6033 | |
| 5930 | 6034 | func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); |
| 5931 | 6035 | } |
| 5932 | 6036 | |
| 5933 | 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 | 6039 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 5935 | 6040 | |
| 5936 | const ty = func.air.typeOfIndex(inst); | |
| 5937 | if (ty.zigTypeTag() == .Vector) { | |
| 6041 | const ty = func.typeOfIndex(inst); | |
| 6042 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 5938 | 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 | 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 | 6059 | try func.addTag(.select); |
| 5955 | 6060 | |
| 5956 | 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 | 6063 | const result = try func.allocLocal(result_ty); |
| 5959 | 6064 | try func.addLabel(.local_set, result.local.value); |
| 5960 | 6065 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 5961 | 6066 | } |
| 5962 | 6067 | |
| 5963 | 6068 | fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6069 | const mod = func.bin_file.base.options.module.?; | |
| 5964 | 6070 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 5965 | 6071 | const bin_op = func.air.extraData(Air.Bin, pl_op.payload).data; |
| 5966 | 6072 | |
| 5967 | const ty = func.air.typeOfIndex(inst); | |
| 5968 | if (ty.zigTypeTag() == .Vector) { | |
| 6073 | const ty = func.typeOfIndex(inst); | |
| 6074 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 5969 | 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 | 6086 | // call to compiler-rt `fn fmaf(f32, f32, f32) f32` |
| 5981 | 6087 | var result = try func.callIntrinsic( |
| 5982 | 6088 | "fmaf", |
| 5983 | &.{ Type.f32, Type.f32, Type.f32 }, | |
| 6089 | &.{ .f32_type, .f32_type, .f32_type }, | |
| 5984 | 6090 | Type.f32, |
| 5985 | 6091 | &.{ rhs_ext, lhs_ext, addend_ext }, |
| 5986 | 6092 | ); |
| ... | ... | @@ -5994,16 +6100,17 @@ fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5994 | 6100 | } |
| 5995 | 6101 | |
| 5996 | 6102 | fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6103 | const mod = func.bin_file.base.options.module.?; | |
| 5997 | 6104 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5998 | 6105 | |
| 5999 | const ty = func.air.typeOf(ty_op.operand); | |
| 6000 | const result_ty = func.air.typeOfIndex(inst); | |
| 6001 | if (ty.zigTypeTag() == .Vector) { | |
| 6106 | const ty = func.typeOf(ty_op.operand); | |
| 6107 | const result_ty = func.typeOfIndex(inst); | |
| 6108 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 6002 | 6109 | return func.fail("TODO: `@clz` for vectors", .{}); |
| 6003 | 6110 | } |
| 6004 | 6111 | |
| 6005 | 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 | 6114 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6008 | 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 | 6153 | } |
| 6047 | 6154 | |
| 6048 | 6155 | fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6156 | const mod = func.bin_file.base.options.module.?; | |
| 6049 | 6157 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 6050 | 6158 | |
| 6051 | const ty = func.air.typeOf(ty_op.operand); | |
| 6052 | const result_ty = func.air.typeOfIndex(inst); | |
| 6159 | const ty = func.typeOf(ty_op.operand); | |
| 6160 | const result_ty = func.typeOfIndex(inst); | |
| 6053 | 6161 | |
| 6054 | if (ty.zigTypeTag() == .Vector) { | |
| 6162 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 6055 | 6163 | return func.fail("TODO: `@ctz` for vectors", .{}); |
| 6056 | 6164 | } |
| 6057 | 6165 | |
| 6058 | 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 | 6168 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6061 | 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 | 6221 | if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{}); |
| 6114 | 6222 | |
| 6115 | 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 | 6225 | const operand = try func.resolveInst(pl_op.operand); |
| 6118 | 6226 | |
| 6119 | 6227 | log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand }); |
| ... | ... | @@ -6151,17 +6259,18 @@ fn airTry(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6151 | 6259 | const err_union = try func.resolveInst(pl_op.operand); |
| 6152 | 6260 | const extra = func.air.extraData(Air.Try, pl_op.payload); |
| 6153 | 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 | 6263 | const result = try lowerTry(func, inst, err_union, body, err_union_ty, false); |
| 6156 | 6264 | func.finishAir(inst, result, &.{pl_op.operand}); |
| 6157 | 6265 | } |
| 6158 | 6266 | |
| 6159 | 6267 | fn airTryPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6268 | const mod = func.bin_file.base.options.module.?; | |
| 6160 | 6269 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 6161 | 6270 | const extra = func.air.extraData(Air.TryPtr, ty_pl.payload); |
| 6162 | 6271 | const err_union_ptr = try func.resolveInst(extra.data.ptr); |
| 6163 | 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 | 6274 | const result = try lowerTry(func, inst, err_union_ptr, body, err_union_ty, true); |
| 6166 | 6275 | func.finishAir(inst, result, &.{extra.data.ptr}); |
| 6167 | 6276 | } |
| ... | ... | @@ -6174,24 +6283,25 @@ fn lowerTry( |
| 6174 | 6283 | err_union_ty: Type, |
| 6175 | 6284 | operand_is_ptr: bool, |
| 6176 | 6285 | ) InnerError!WValue { |
| 6286 | const mod = func.bin_file.base.options.module.?; | |
| 6177 | 6287 | if (operand_is_ptr) { |
| 6178 | 6288 | return func.fail("TODO: lowerTry for pointers", .{}); |
| 6179 | 6289 | } |
| 6180 | 6290 | |
| 6181 | const pl_ty = err_union_ty.errorUnionPayload(); | |
| 6182 | const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(); | |
| 6291 | const pl_ty = err_union_ty.errorUnionPayload(mod); | |
| 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 | 6295 | // Block we can jump out of when error is not set |
| 6186 | 6296 | try func.startBlock(.block, wasm.block_empty); |
| 6187 | 6297 | |
| 6188 | 6298 | // check if the error tag is set for the error union. |
| 6189 | 6299 | try func.emitWValue(err_union); |
| 6190 | 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 | 6302 | try func.addMemArg(.i32_load16_u, .{ |
| 6193 | 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 | 6307 | try func.addTag(.i32_eqz); |
| ... | ... | @@ -6213,8 +6323,8 @@ fn lowerTry( |
| 6213 | 6323 | return WValue{ .none = {} }; |
| 6214 | 6324 | } |
| 6215 | 6325 | |
| 6216 | const pl_offset = @intCast(u32, errUnionPayloadOffset(pl_ty, func.target)); | |
| 6217 | if (isByRef(pl_ty, func.target)) { | |
| 6326 | const pl_offset = @intCast(u32, errUnionPayloadOffset(pl_ty, mod)); | |
| 6327 | if (isByRef(pl_ty, mod)) { | |
| 6218 | 6328 | return buildPointerOffset(func, err_union, pl_offset, .new); |
| 6219 | 6329 | } |
| 6220 | 6330 | const payload = try func.load(err_union, pl_ty, pl_offset); |
| ... | ... | @@ -6222,15 +6332,16 @@ fn lowerTry( |
| 6222 | 6332 | } |
| 6223 | 6333 | |
| 6224 | 6334 | fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6335 | const mod = func.bin_file.base.options.module.?; | |
| 6225 | 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 | 6339 | const operand = try func.resolveInst(ty_op.operand); |
| 6229 | 6340 | |
| 6230 | if (ty.zigTypeTag() == .Vector) { | |
| 6341 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 6231 | 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 | 6346 | // bytes are no-op |
| 6236 | 6347 | if (int_info.bits == 8) { |
| ... | ... | @@ -6292,13 +6403,14 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6292 | 6403 | } |
| 6293 | 6404 | |
| 6294 | 6405 | fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6406 | const mod = func.bin_file.base.options.module.?; | |
| 6295 | 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 | 6410 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6299 | 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 | 6414 | try func.divSigned(lhs, rhs, ty) |
| 6303 | 6415 | else |
| 6304 | 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 | 6418 | } |
| 6307 | 6419 | |
| 6308 | 6420 | fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6421 | const mod = func.bin_file.base.options.module.?; | |
| 6309 | 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 | 6425 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6313 | 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 | 6429 | try func.divSigned(lhs, rhs, ty) |
| 6317 | 6430 | else |
| 6318 | 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 | 6441 | fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6329 | 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 | 6446 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6333 | 6447 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6334 | 6448 | |
| 6335 | if (ty.isUnsignedInt()) { | |
| 6449 | if (ty.isUnsignedInt(mod)) { | |
| 6336 | 6450 | const result = try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| 6337 | 6451 | return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 6338 | } else if (ty.isSignedInt()) { | |
| 6339 | const int_bits = ty.intInfo(func.target).bits; | |
| 6452 | } else if (ty.isSignedInt(mod)) { | |
| 6453 | const int_bits = ty.intInfo(mod).bits; | |
| 6340 | 6454 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 6341 | 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 | 6528 | } |
| 6415 | 6529 | |
| 6416 | 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 | 6533 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 6419 | 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 | 6556 | /// Retrieves the absolute value of a signed integer |
| 6442 | 6557 | /// NOTE: Leaves the result value on the stack. |
| 6443 | 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 | 6561 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 6446 | 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 | 6592 | assert(op == .add or op == .sub); |
| 6477 | 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 | 6597 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6481 | 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 | 6601 | const is_signed = int_info.signedness == .signed; |
| 6485 | 6602 | |
| 6486 | 6603 | if (int_info.bits > 64) { |
| ... | ... | @@ -6523,7 +6640,8 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 6523 | 6640 | } |
| 6524 | 6641 | |
| 6525 | 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 | 6645 | const wasm_bits = toWasmBits(int_info.bits).?; |
| 6528 | 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 | 6706 | fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6589 | 6707 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 6590 | 6708 | |
| 6591 | const ty = func.air.typeOfIndex(inst); | |
| 6592 | const int_info = ty.intInfo(func.target); | |
| 6709 | const mod = func.bin_file.base.options.module.?; | |
| 6710 | const ty = func.typeOfIndex(inst); | |
| 6711 | const int_info = ty.intInfo(mod); | |
| 6593 | 6712 | const is_signed = int_info.signedness == .signed; |
| 6594 | 6713 | if (int_info.bits > 64) { |
| 6595 | 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 | 6816 | fn callIntrinsic( |
| 6698 | 6817 | func: *CodeGen, |
| 6699 | 6818 | name: []const u8, |
| 6700 | param_types: []const Type, | |
| 6819 | param_types: []const InternPool.Index, | |
| 6701 | 6820 | return_type: Type, |
| 6702 | 6821 | args: []const WValue, |
| 6703 | 6822 | ) InnerError!WValue { |
| ... | ... | @@ -6707,12 +6826,13 @@ fn callIntrinsic( |
| 6707 | 6826 | }; |
| 6708 | 6827 | |
| 6709 | 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 | 6831 | defer func_type.deinit(func.gpa); |
| 6712 | 6832 | const func_type_index = try func.bin_file.putOrGetFuncType(func_type); |
| 6713 | 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 | 6836 | // if we want return as first param, we allocate a pointer to stack, |
| 6717 | 6837 | // and emit it as our first argument |
| 6718 | 6838 | const sret = if (want_sret_param) blk: { |
| ... | ... | @@ -6724,16 +6844,16 @@ fn callIntrinsic( |
| 6724 | 6844 | // Lower all arguments to the stack before we call our function |
| 6725 | 6845 | for (args, 0..) |arg, arg_i| { |
| 6726 | 6846 | assert(!(want_sret_param and arg == .stack)); |
| 6727 | assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime()); | |
| 6728 | try func.lowerArg(.C, param_types[arg_i], arg); | |
| 6847 | assert(param_types[arg_i].toType().hasRuntimeBitsIgnoreComptime(mod)); | |
| 6848 | try func.lowerArg(.C, param_types[arg_i].toType(), arg); | |
| 6729 | 6849 | } |
| 6730 | 6850 | |
| 6731 | 6851 | // Actually call our intrinsic |
| 6732 | 6852 | try func.addLabel(.call, symbol_index); |
| 6733 | 6853 | |
| 6734 | if (!return_type.hasRuntimeBitsIgnoreComptime()) { | |
| 6854 | if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6735 | 6855 | return WValue.none; |
| 6736 | } else if (return_type.isNoReturn()) { | |
| 6856 | } else if (return_type.isNoReturn(mod)) { | |
| 6737 | 6857 | try func.addTag(.@"unreachable"); |
| 6738 | 6858 | return WValue.none; |
| 6739 | 6859 | } else if (want_sret_param) { |
| ... | ... | @@ -6746,11 +6866,11 @@ fn callIntrinsic( |
| 6746 | 6866 | fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6747 | 6867 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 6748 | 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 | 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 | 6874 | try func.lowerToStack(result_ptr); |
| 6755 | 6875 | try func.emitWValue(operand); |
| 6756 | 6876 | try func.addLabel(.call, func_sym_index); |
| ... | ... | @@ -6759,15 +6879,14 @@ fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6759 | 6879 | } |
| 6760 | 6880 | |
| 6761 | 6881 | fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6762 | const enum_decl_index = enum_ty.getOwnerDecl(); | |
| 6763 | const module = func.bin_file.base.options.module.?; | |
| 6882 | const mod = func.bin_file.base.options.module.?; | |
| 6883 | const enum_decl_index = enum_ty.getOwnerDecl(mod); | |
| 6764 | 6884 | |
| 6765 | 6885 | var arena_allocator = std.heap.ArenaAllocator.init(func.gpa); |
| 6766 | 6886 | defer arena_allocator.deinit(); |
| 6767 | 6887 | const arena = arena_allocator.allocator(); |
| 6768 | 6888 | |
| 6769 | const fqn = try module.declPtr(enum_decl_index).getFullyQualifiedName(module); | |
| 6770 | defer module.gpa.free(fqn); | |
| 6889 | const fqn = mod.intern_pool.stringToSlice(try mod.declPtr(enum_decl_index).getFullyQualifiedName(mod)); | |
| 6771 | 6890 | const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); |
| 6772 | 6891 | |
| 6773 | 6892 | // check if we already generated code for this. |
| ... | ... | @@ -6775,10 +6894,9 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6775 | 6894 | return loc.index; |
| 6776 | 6895 | } |
| 6777 | 6896 | |
| 6778 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | |
| 6779 | const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer); | |
| 6897 | const int_tag_ty = enum_ty.intTagType(mod); | |
| 6780 | 6898 | |
| 6781 | if (int_tag_ty.bitSize(func.target) > 64) { | |
| 6899 | if (int_tag_ty.bitSize(mod) > 64) { | |
| 6782 | 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 | 6916 | |
| 6799 | 6917 | // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse. |
| 6800 | 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 | 6922 | // for each tag name, create an unnamed const, |
| 6803 | 6923 | // and then get a pointer to its value. |
| 6804 | var name_ty_payload: Type.Payload.Len = .{ | |
| 6805 | .base = .{ .tag = .array_u8_sentinel_0 }, | |
| 6806 | .data = @intCast(u64, tag_name.len), | |
| 6807 | }; | |
| 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, | |
| 6924 | const name_ty = try mod.arrayType(.{ | |
| 6925 | .len = tag_name.len, | |
| 6926 | .child = .u8_type, | |
| 6927 | .sentinel = .zero_u8, | |
| 6815 | 6928 | }); |
| 6816 | if (!gop.found_existing) { | |
| 6817 | gop.key_ptr.* = .{ | |
| 6818 | .index = @intCast(u32, string_bytes.items.len), | |
| 6819 | .len = @intCast(u32, tag_name.len), | |
| 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); | |
| 6929 | const name_val = try mod.intern(.{ .aggregate = .{ | |
| 6930 | .ty = name_ty.toIntern(), | |
| 6931 | .storage = .{ .bytes = tag_name }, | |
| 6932 | } }); | |
| 6829 | 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 | 6935 | enum_decl_index, |
| 6832 | 6936 | ); |
| 6833 | 6937 | |
| ... | ... | @@ -6839,11 +6943,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6839 | 6943 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6840 | 6944 | try leb.writeULEB128(writer, @as(u32, 1)); |
| 6841 | 6945 | |
| 6842 | var tag_val_payload: Value.Payload.U32 = .{ | |
| 6843 | .base = .{ .tag = .enum_field_index }, | |
| 6844 | .data = @intCast(u32, field_index), | |
| 6845 | }; | |
| 6846 | const tag_value = try func.lowerConstant(Value.initPayload(&tag_val_payload.base), enum_ty); | |
| 6946 | const tag_val = try mod.enumValueFieldIndex(enum_ty, field_index); | |
| 6947 | const tag_value = try func.lowerConstant(tag_val, enum_ty); | |
| 6847 | 6948 | |
| 6848 | 6949 | switch (tag_value) { |
| 6849 | 6950 | .imm32 => |value| { |
| ... | ... | @@ -6928,27 +7029,27 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6928 | 7029 | // finish function body |
| 6929 | 7030 | try writer.writeByte(std.wasm.opcode(.end)); |
| 6930 | 7031 | |
| 6931 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | |
| 6932 | const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty}, slice_ty, func.target); | |
| 7032 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 7033 | const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty.ip_index}, slice_ty, mod); | |
| 6933 | 7034 | return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); |
| 6934 | 7035 | } |
| 6935 | 7036 | |
| 6936 | 7037 | fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7038 | const mod = func.bin_file.base.options.module.?; | |
| 6937 | 7039 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 6938 | 7040 | |
| 6939 | 7041 | const operand = try func.resolveInst(ty_op.operand); |
| 6940 | 7042 | const error_set_ty = func.air.getRefType(ty_op.ty); |
| 6941 | 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 | 7046 | var values = try std.ArrayList(u32).initCapacity(func.gpa, names.len); |
| 6945 | 7047 | defer values.deinit(); |
| 6946 | 7048 | |
| 6947 | const module = func.bin_file.base.options.module.?; | |
| 6948 | 7049 | var lowest: ?u32 = null; |
| 6949 | 7050 | var highest: ?u32 = null; |
| 6950 | 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 | 7053 | if (lowest) |*l| { |
| 6953 | 7054 | if (err_int < l.*) { |
| 6954 | 7055 | l.* = err_int; |
| ... | ... | @@ -7019,12 +7120,13 @@ inline fn useAtomicFeature(func: *const CodeGen) bool { |
| 7019 | 7120 | } |
| 7020 | 7121 | |
| 7021 | 7122 | fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7123 | const mod = func.bin_file.base.options.module.?; | |
| 7022 | 7124 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 7023 | 7125 | const extra = func.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 7024 | 7126 | |
| 7025 | const ptr_ty = func.air.typeOf(extra.ptr); | |
| 7026 | const ty = ptr_ty.childType(); | |
| 7027 | const result_ty = func.air.typeOfIndex(inst); | |
| 7127 | const ptr_ty = func.typeOf(extra.ptr); | |
| 7128 | const ty = ptr_ty.childType(mod); | |
| 7129 | const result_ty = func.typeOfIndex(inst); | |
| 7028 | 7130 | |
| 7029 | 7131 | const ptr_operand = try func.resolveInst(extra.ptr); |
| 7030 | 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 | 7139 | try func.emitWValue(ptr_operand); |
| 7038 | 7140 | try func.lowerToStack(expected_val); |
| 7039 | 7141 | try func.lowerToStack(new_val); |
| 7040 | try func.addAtomicMemArg(switch (ty.abiSize(func.target)) { | |
| 7142 | try func.addAtomicMemArg(switch (ty.abiSize(mod)) { | |
| 7041 | 7143 | 1 => .i32_atomic_rmw8_cmpxchg_u, |
| 7042 | 7144 | 2 => .i32_atomic_rmw16_cmpxchg_u, |
| 7043 | 7145 | 4 => .i32_atomic_rmw_cmpxchg, |
| ... | ... | @@ -7045,14 +7147,14 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7045 | 7147 | else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), |
| 7046 | 7148 | }, .{ |
| 7047 | 7149 | .offset = ptr_operand.offset(), |
| 7048 | .alignment = ty.abiAlignment(func.target), | |
| 7150 | .alignment = ty.abiAlignment(mod), | |
| 7049 | 7151 | }); |
| 7050 | 7152 | try func.addLabel(.local_tee, val_local.local.value); |
| 7051 | 7153 | _ = try func.cmp(.stack, expected_val, ty, .eq); |
| 7052 | 7154 | try func.addLabel(.local_set, cmp_result.local.value); |
| 7053 | 7155 | break :val val_local; |
| 7054 | 7156 | } else val: { |
| 7055 | if (ty.abiSize(func.target) > 8) { | |
| 7157 | if (ty.abiSize(mod) > 8) { | |
| 7056 | 7158 | return func.fail("TODO: Implement `@cmpxchg` for types larger than abi size of 8 bytes", .{}); |
| 7057 | 7159 | } |
| 7058 | 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 | 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 | 7174 | try func.emitWValue(cmp_result); |
| 7073 | 7175 | try func.addImm32(-1); |
| 7074 | 7176 | try func.addTag(.i32_xor); |
| ... | ... | @@ -7076,7 +7178,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7076 | 7178 | try func.addTag(.i32_and); |
| 7077 | 7179 | const and_result = try WValue.toLocal(.stack, func, Type.bool); |
| 7078 | 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 | 7182 | try func.store(result_ptr, ptr_val, ty, 0); |
| 7081 | 7183 | break :val result_ptr; |
| 7082 | 7184 | } else val: { |
| ... | ... | @@ -7087,16 +7189,17 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7087 | 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 | 7195 | fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7196 | const mod = func.bin_file.base.options.module.?; | |
| 7094 | 7197 | const atomic_load = func.air.instructions.items(.data)[inst].atomic_load; |
| 7095 | 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 | 7201 | if (func.useAtomicFeature()) { |
| 7099 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(func.target)) { | |
| 7202 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(mod)) { | |
| 7100 | 7203 | 1 => .i32_atomic_load8_u, |
| 7101 | 7204 | 2 => .i32_atomic_load16_u, |
| 7102 | 7205 | 4 => .i32_atomic_load, |
| ... | ... | @@ -7106,7 +7209,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7106 | 7209 | try func.emitWValue(ptr); |
| 7107 | 7210 | try func.addAtomicMemArg(tag, .{ |
| 7108 | 7211 | .offset = ptr.offset(), |
| 7109 | .alignment = ty.abiAlignment(func.target), | |
| 7212 | .alignment = ty.abiAlignment(mod), | |
| 7110 | 7213 | }); |
| 7111 | 7214 | } else { |
| 7112 | 7215 | _ = try func.load(ptr, ty, 0); |
| ... | ... | @@ -7117,12 +7220,13 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7117 | 7220 | } |
| 7118 | 7221 | |
| 7119 | 7222 | fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7223 | const mod = func.bin_file.base.options.module.?; | |
| 7120 | 7224 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 7121 | 7225 | const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 7122 | 7226 | |
| 7123 | 7227 | const ptr = try func.resolveInst(pl_op.operand); |
| 7124 | 7228 | const operand = try func.resolveInst(extra.operand); |
| 7125 | const ty = func.air.typeOfIndex(inst); | |
| 7229 | const ty = func.typeOfIndex(inst); | |
| 7126 | 7230 | const op: std.builtin.AtomicRmwOp = extra.op(); |
| 7127 | 7231 | |
| 7128 | 7232 | if (func.useAtomicFeature()) { |
| ... | ... | @@ -7140,7 +7244,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7140 | 7244 | try func.emitWValue(ptr); |
| 7141 | 7245 | try func.emitWValue(value); |
| 7142 | 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 | 7249 | const and_res = try func.binOp(value, operand, ty, .@"and"); |
| 7146 | 7250 | if (wasm_bits == 32) |
| ... | ... | @@ -7157,7 +7261,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7157 | 7261 | try func.addTag(.select); |
| 7158 | 7262 | } |
| 7159 | 7263 | try func.addAtomicMemArg( |
| 7160 | switch (ty.abiSize(func.target)) { | |
| 7264 | switch (ty.abiSize(mod)) { | |
| 7161 | 7265 | 1 => .i32_atomic_rmw8_cmpxchg_u, |
| 7162 | 7266 | 2 => .i32_atomic_rmw16_cmpxchg_u, |
| 7163 | 7267 | 4 => .i32_atomic_rmw_cmpxchg, |
| ... | ... | @@ -7166,7 +7270,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7166 | 7270 | }, |
| 7167 | 7271 | .{ |
| 7168 | 7272 | .offset = ptr.offset(), |
| 7169 | .alignment = ty.abiAlignment(func.target), | |
| 7273 | .alignment = ty.abiAlignment(mod), | |
| 7170 | 7274 | }, |
| 7171 | 7275 | ); |
| 7172 | 7276 | const select_res = try func.allocLocal(ty); |
| ... | ... | @@ -7185,7 +7289,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7185 | 7289 | else => { |
| 7186 | 7290 | try func.emitWValue(ptr); |
| 7187 | 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 | 7293 | 1 => switch (op) { |
| 7190 | 7294 | .Xchg => .i32_atomic_rmw8_xchg_u, |
| 7191 | 7295 | .Add => .i32_atomic_rmw8_add_u, |
| ... | ... | @@ -7226,7 +7330,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7226 | 7330 | }; |
| 7227 | 7331 | try func.addAtomicMemArg(tag, .{ |
| 7228 | 7332 | .offset = ptr.offset(), |
| 7229 | .alignment = ty.abiAlignment(func.target), | |
| 7333 | .alignment = ty.abiAlignment(mod), | |
| 7230 | 7334 | }); |
| 7231 | 7335 | const result = try WValue.toLocal(.stack, func, ty); |
| 7232 | 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 | 7359 | .Xor => .xor, |
| 7256 | 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 | 7363 | _ = try func.wrapOperand(.stack, ty); |
| 7260 | 7364 | } |
| 7261 | 7365 | try func.store(.stack, .stack, ty, ptr.offset()); |
| ... | ... | @@ -7271,7 +7375,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7271 | 7375 | try func.store(.stack, .stack, ty, ptr.offset()); |
| 7272 | 7376 | }, |
| 7273 | 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 | 7380 | try func.emitWValue(ptr); |
| 7277 | 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 | 7406 | } |
| 7303 | 7407 | |
| 7304 | 7408 | fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7409 | const mod = func.bin_file.base.options.module.?; | |
| 7305 | 7410 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 7306 | 7411 | |
| 7307 | 7412 | const ptr = try func.resolveInst(bin_op.lhs); |
| 7308 | 7413 | const operand = try func.resolveInst(bin_op.rhs); |
| 7309 | const ptr_ty = func.air.typeOf(bin_op.lhs); | |
| 7310 | const ty = ptr_ty.childType(); | |
| 7414 | const ptr_ty = func.typeOf(bin_op.lhs); | |
| 7415 | const ty = ptr_ty.childType(mod); | |
| 7311 | 7416 | |
| 7312 | 7417 | if (func.useAtomicFeature()) { |
| 7313 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(func.target)) { | |
| 7418 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(mod)) { | |
| 7314 | 7419 | 1 => .i32_atomic_store8, |
| 7315 | 7420 | 2 => .i32_atomic_store16, |
| 7316 | 7421 | 4 => .i32_atomic_store, |
| ... | ... | @@ -7321,7 +7426,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7321 | 7426 | try func.lowerToStack(operand); |
| 7322 | 7427 | try func.addAtomicMemArg(tag, .{ |
| 7323 | 7428 | .offset = ptr.offset(), |
| 7324 | .alignment = ty.abiAlignment(func.target), | |
| 7429 | .alignment = ty.abiAlignment(mod), | |
| 7325 | 7430 | }); |
| 7326 | 7431 | } else { |
| 7327 | 7432 | try func.store(ptr, operand, ty, 0); |
| ... | ... | @@ -7338,3 +7443,13 @@ fn airFrameAddress(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7338 | 7443 | const result = try WValue.toLocal(.stack, func, Type.usize); |
| 7339 | 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 | 254 | @setCold(true); |
| 255 | 255 | std.debug.assert(emit.error_msg == null); |
| 256 | 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 | 258 | return error.EmitFail; |
| 259 | 259 | } |
| 260 | 260 |
src/arch/wasm/abi.zig+33-30| ... | ... | @@ -5,9 +5,11 @@ |
| 5 | 5 | //! Note: Above mentioned document is not an official specification, therefore called a convention. |
| 6 | 6 | |
| 7 | 7 | const std = @import("std"); |
| 8 | const Type = @import("../../type.zig").Type; | |
| 9 | 8 | const Target = std.Target; |
| 10 | 9 | |
| 10 | const Type = @import("../../type.zig").Type; | |
| 11 | const Module = @import("../../Module.zig"); | |
| 12 | ||
| 11 | 13 | /// Defines how to pass a type as part of a function signature, |
| 12 | 14 | /// both for parameters as well as return values. |
| 13 | 15 | pub const Class = enum { direct, indirect, none }; |
| ... | ... | @@ -19,27 +21,28 @@ const direct: [2]Class = .{ .direct, .none }; |
| 19 | 21 | /// Classifies a given Zig type to determine how they must be passed |
| 20 | 22 | /// or returned as value within a wasm function. |
| 21 | 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 { | |
| 23 | if (!ty.hasRuntimeBitsIgnoreComptime()) return none; | |
| 24 | switch (ty.zigTypeTag()) { | |
| 24 | pub fn classifyType(ty: Type, mod: *Module) [2]Class { | |
| 25 | const target = mod.getTarget(); | |
| 26 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return none; | |
| 27 | switch (ty.zigTypeTag(mod)) { | |
| 25 | 28 | .Struct => { |
| 26 | if (ty.containerLayout() == .Packed) { | |
| 27 | if (ty.bitSize(target) <= 64) return direct; | |
| 29 | if (ty.containerLayout(mod) == .Packed) { | |
| 30 | if (ty.bitSize(mod) <= 64) return direct; | |
| 28 | 31 | return .{ .direct, .direct }; |
| 29 | 32 | } |
| 30 | 33 | // When the struct type is non-scalar |
| 31 | if (ty.structFieldCount() > 1) return memory; | |
| 34 | if (ty.structFieldCount(mod) > 1) return memory; | |
| 32 | 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 | 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 | 39 | return memory; |
| 37 | 40 | } |
| 38 | 41 | } |
| 39 | return classifyType(field.ty, target); | |
| 42 | return classifyType(field.ty, mod); | |
| 40 | 43 | }, |
| 41 | 44 | .Int, .Enum, .ErrorSet, .Vector => { |
| 42 | const int_bits = ty.intInfo(target).bits; | |
| 45 | const int_bits = ty.intInfo(mod).bits; | |
| 43 | 46 | if (int_bits <= 64) return direct; |
| 44 | 47 | if (int_bits <= 128) return .{ .direct, .direct }; |
| 45 | 48 | return memory; |
| ... | ... | @@ -53,22 +56,22 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 53 | 56 | .Bool => return direct, |
| 54 | 57 | .Array => return memory, |
| 55 | 58 | .Optional => { |
| 56 | std.debug.assert(ty.isPtrLikeOptional()); | |
| 59 | std.debug.assert(ty.isPtrLikeOptional(mod)); | |
| 57 | 60 | return direct; |
| 58 | 61 | }, |
| 59 | 62 | .Pointer => { |
| 60 | std.debug.assert(!ty.isSlice()); | |
| 63 | std.debug.assert(!ty.isSlice(mod)); | |
| 61 | 64 | return direct; |
| 62 | 65 | }, |
| 63 | 66 | .Union => { |
| 64 | if (ty.containerLayout() == .Packed) { | |
| 65 | if (ty.bitSize(target) <= 64) return direct; | |
| 67 | if (ty.containerLayout(mod) == .Packed) { | |
| 68 | if (ty.bitSize(mod) <= 64) return direct; | |
| 66 | 69 | return .{ .direct, .direct }; |
| 67 | 70 | } |
| 68 | const layout = ty.unionGetLayout(target); | |
| 71 | const layout = ty.unionGetLayout(mod); | |
| 69 | 72 | std.debug.assert(layout.tag_size == 0); |
| 70 | if (ty.unionFields().count() > 1) return memory; | |
| 71 | return classifyType(ty.unionFields().values()[0].ty, target); | |
| 73 | if (ty.unionFields(mod).count() > 1) return memory; | |
| 74 | return classifyType(ty.unionFields(mod).values()[0].ty, mod); | |
| 72 | 75 | }, |
| 73 | 76 | .ErrorUnion, |
| 74 | 77 | .Frame, |
| ... | ... | @@ -90,29 +93,29 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 90 | 93 | /// Returns the scalar type a given type can represent. |
| 91 | 94 | /// Asserts given type can be represented as scalar, such as |
| 92 | 95 | /// a struct with a single scalar field. |
| 93 | pub fn scalarType(ty: Type, target: std.Target) Type { | |
| 94 | switch (ty.zigTypeTag()) { | |
| 96 | pub fn scalarType(ty: Type, mod: *Module) Type { | |
| 97 | switch (ty.zigTypeTag(mod)) { | |
| 95 | 98 | .Struct => { |
| 96 | switch (ty.containerLayout()) { | |
| 99 | switch (ty.containerLayout(mod)) { | |
| 97 | 100 | .Packed => { |
| 98 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 99 | return scalarType(struct_obj.backing_int_ty, target); | |
| 101 | const struct_obj = mod.typeToStruct(ty).?; | |
| 102 | return scalarType(struct_obj.backing_int_ty, mod); | |
| 100 | 103 | }, |
| 101 | 104 | else => { |
| 102 | std.debug.assert(ty.structFieldCount() == 1); | |
| 103 | return scalarType(ty.structFieldType(0), target); | |
| 105 | std.debug.assert(ty.structFieldCount(mod) == 1); | |
| 106 | return scalarType(ty.structFieldType(0, mod), mod); | |
| 104 | 107 | }, |
| 105 | 108 | } |
| 106 | 109 | }, |
| 107 | 110 | .Union => { |
| 108 | if (ty.containerLayout() != .Packed) { | |
| 109 | const layout = ty.unionGetLayout(target); | |
| 111 | if (ty.containerLayout(mod) != .Packed) { | |
| 112 | const layout = ty.unionGetLayout(mod); | |
| 110 | 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 | 120 | else => return ty, |
| 118 | 121 | } |
src/arch/x86_64/CodeGen.zig+784-772| ... | ... | @@ -26,6 +26,7 @@ const Liveness = @import("../../Liveness.zig"); |
| 26 | 26 | const Lower = @import("Lower.zig"); |
| 27 | 27 | const Mir = @import("Mir.zig"); |
| 28 | 28 | const Module = @import("../../Module.zig"); |
| 29 | const InternPool = @import("../../InternPool.zig"); | |
| 29 | 30 | const Target = std.Target; |
| 30 | 31 | const Type = @import("../../type.zig").Type; |
| 31 | 32 | const TypedValue = @import("../../TypedValue.zig"); |
| ... | ... | @@ -112,10 +113,10 @@ const Owner = union(enum) { |
| 112 | 113 | mod_fn: *const Module.Fn, |
| 113 | 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 | 117 | return switch (owner) { |
| 117 | 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 | 448 | else => unreachable, |
| 448 | 449 | } |
| 449 | 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 | 454 | fn reuseFrame(self: *InstTracking) void { |
| ... | ... | @@ -537,7 +538,7 @@ const InstTracking = struct { |
| 537 | 538 | inst: Air.Inst.Index, |
| 538 | 539 | target: InstTracking, |
| 539 | 540 | ) !void { |
| 540 | const ty = function.air.typeOfIndex(inst); | |
| 541 | const ty = function.typeOfIndex(inst); | |
| 541 | 542 | if ((self.long == .none or self.long == .reserved_frame) and target.long == .load_frame) |
| 542 | 543 | try function.genCopy(ty, target.long, self.short); |
| 543 | 544 | try function.genCopy(ty, target.short, self.short); |
| ... | ... | @@ -605,14 +606,14 @@ const FrameAlloc = struct { |
| 605 | 606 | .ref_count = 0, |
| 606 | 607 | }; |
| 607 | 608 | } |
| 608 | fn initType(ty: Type, target: Target) FrameAlloc { | |
| 609 | return init(.{ .size = ty.abiSize(target), .alignment = ty.abiAlignment(target) }); | |
| 609 | fn initType(ty: Type, mod: *Module) FrameAlloc { | |
| 610 | return init(.{ .size = ty.abiSize(mod), .alignment = ty.abiAlignment(mod) }); | |
| 610 | 611 | } |
| 611 | 612 | }; |
| 612 | 613 | |
| 613 | 614 | const StackAllocation = struct { |
| 614 | 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 | 617 | size: u32, |
| 617 | 618 | }; |
| 618 | 619 | |
| ... | ... | @@ -631,7 +632,7 @@ const Self = @This(); |
| 631 | 632 | pub fn generate( |
| 632 | 633 | bin_file: *link.File, |
| 633 | 634 | src_loc: Module.SrcLoc, |
| 634 | module_fn: *Module.Fn, | |
| 635 | module_fn_index: Module.Fn.Index, | |
| 635 | 636 | air: Air, |
| 636 | 637 | liveness: Liveness, |
| 637 | 638 | code: *std.ArrayList(u8), |
| ... | ... | @@ -642,6 +643,7 @@ pub fn generate( |
| 642 | 643 | } |
| 643 | 644 | |
| 644 | 645 | const mod = bin_file.options.module.?; |
| 646 | const module_fn = mod.funcPtr(module_fn_index); | |
| 645 | 647 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 646 | 648 | assert(fn_owner_decl.has_tv); |
| 647 | 649 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -686,7 +688,7 @@ pub fn generate( |
| 686 | 688 | @enumToInt(FrameIndex.stack_frame), |
| 687 | 689 | FrameAlloc.init(.{ |
| 688 | 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 | 692 | set_align_stack.alignment |
| 691 | 693 | else |
| 692 | 694 | 1, |
| ... | ... | @@ -697,7 +699,8 @@ pub fn generate( |
| 697 | 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 | 704 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| 702 | 705 | error.OutOfRegisters => return Result{ |
| 703 | 706 | .fail = try ErrorMsg.create( |
| ... | ... | @@ -714,12 +717,12 @@ pub fn generate( |
| 714 | 717 | function.args = call_info.args; |
| 715 | 718 | function.ret_mcv = call_info.return_value; |
| 716 | 719 | function.frame_allocs.set(@enumToInt(FrameIndex.ret_addr), FrameAlloc.init(.{ |
| 717 | .size = Type.usize.abiSize(function.target.*), | |
| 718 | .alignment = @min(Type.usize.abiAlignment(function.target.*), call_info.stack_align), | |
| 720 | .size = Type.usize.abiSize(mod), | |
| 721 | .alignment = @min(Type.usize.abiAlignment(mod), call_info.stack_align), | |
| 719 | 722 | })); |
| 720 | 723 | function.frame_allocs.set(@enumToInt(FrameIndex.base_ptr), FrameAlloc.init(.{ |
| 721 | .size = Type.usize.abiSize(function.target.*), | |
| 722 | .alignment = @min(Type.usize.abiAlignment(function.target.*) * 2, call_info.stack_align), | |
| 724 | .size = Type.usize.abiSize(mod), | |
| 725 | .alignment = @min(Type.usize.abiAlignment(mod) * 2, call_info.stack_align), | |
| 723 | 726 | })); |
| 724 | 727 | function.frame_allocs.set( |
| 725 | 728 | @enumToInt(FrameIndex.args_frame), |
| ... | ... | @@ -1565,7 +1568,8 @@ fn asmMemoryRegisterImmediate( |
| 1565 | 1568 | } |
| 1566 | 1569 | |
| 1567 | 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 | 1573 | if (cc != .Naked) { |
| 1570 | 1574 | try self.asmRegister(.{ ._, .push }, .rbp); |
| 1571 | 1575 | const backpatch_push_callee_preserved_regs = try self.asmPlaceholder(); |
| ... | ... | @@ -1582,7 +1586,7 @@ fn gen(self: *Self) InnerError!void { |
| 1582 | 1586 | // register which the callee is free to clobber. Therefore, we purposely |
| 1583 | 1587 | // spill it to stack immediately. |
| 1584 | 1588 | const frame_index = |
| 1585 | try self.allocFrameIndex(FrameAlloc.initType(Type.usize, self.target.*)); | |
| 1589 | try self.allocFrameIndex(FrameAlloc.initType(Type.usize, mod)); | |
| 1586 | 1590 | try self.genSetMem( |
| 1587 | 1591 | .{ .frame = frame_index }, |
| 1588 | 1592 | 0, |
| ... | ... | @@ -1724,6 +1728,8 @@ fn gen(self: *Self) InnerError!void { |
| 1724 | 1728 | } |
| 1725 | 1729 | |
| 1726 | 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 | 1733 | const air_tags = self.air.instructions.items(.tag); |
| 1728 | 1734 | |
| 1729 | 1735 | for (body) |inst| { |
| ... | ... | @@ -1732,7 +1738,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1732 | 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 | 1742 | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); |
| 1737 | 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 | 1922 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 1917 | 1923 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 1918 | 1924 | |
| 1919 | .constant => unreachable, // excluded from function bodies | |
| 1920 | .const_ty => unreachable, // excluded from function bodies | |
| 1925 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 1921 | 1926 | .unreach => if (self.wantSafety()) try self.airTrap() else self.finishAirBookkeeping(), |
| 1922 | 1927 | |
| 1923 | 1928 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | ... | @@ -1999,7 +2004,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1999 | 2004 | } |
| 2000 | 2005 | |
| 2001 | 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 | 2009 | .Enum => { |
| 2004 | 2010 | const enum_ty = lazy_sym.ty; |
| 2005 | 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 | 2017 | const ret_reg = param_regs[0]; |
| 2012 | 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 | 2021 | defer self.gpa.free(exitlude_jump_relocs); |
| 2016 | 2022 | |
| 2017 | 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 | 2026 | try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty }); |
| 2021 | 2027 | |
| 2022 | 2028 | var data_off: i32 = 0; |
| 2023 | for ( | |
| 2024 | exitlude_jump_relocs, | |
| 2025 | enum_ty.enumFields().keys(), | |
| 2026 | 0.., | |
| 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); | |
| 2029 | for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, index_usize| { | |
| 2030 | const index = @intCast(u32, index_usize); | |
| 2031 | const tag_name = mod.intern_pool.stringToSlice(enum_ty.enumFields(mod)[index_usize]); | |
| 2032 | const tag_val = try mod.enumValueFieldIndex(enum_ty, index); | |
| 2033 | 2033 | const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val }); |
| 2034 | 2034 | try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv); |
| 2035 | 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 | 2092 | |
| 2093 | 2093 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 2094 | 2094 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 2095 | switch (self.air.instructions.items(.tag)[inst]) { | |
| 2096 | .constant, .const_ty => unreachable, | |
| 2097 | else => self.inst_tracking.getPtr(inst).?.die(self, inst), | |
| 2098 | } | |
| 2095 | assert(self.air.instructions.items(.tag)[inst] != .interned); | |
| 2096 | self.inst_tracking.getPtr(inst).?.die(self, inst); | |
| 2099 | 2097 | } |
| 2100 | 2098 | |
| 2101 | 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 | 2124 | const dies = @truncate(u1, tomb_bits) != 0; |
| 2127 | 2125 | tomb_bits >>= 1; |
| 2128 | 2126 | if (!dies) continue; |
| 2129 | const op_int = @enumToInt(op); | |
| 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); | |
| 2127 | self.processDeath(Air.refToIndexAllowNone(op) orelse continue); | |
| 2133 | 2128 | } |
| 2134 | 2129 | self.finishAirResult(inst, result); |
| 2135 | 2130 | } |
| ... | ... | @@ -2252,19 +2247,19 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 2252 | 2247 | |
| 2253 | 2248 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 2254 | 2249 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { |
| 2255 | const ptr_ty = self.air.typeOfIndex(inst); | |
| 2256 | const val_ty = ptr_ty.childType(); | |
| 2250 | const mod = self.bin_file.options.module.?; | |
| 2251 | const ptr_ty = self.typeOfIndex(inst); | |
| 2252 | const val_ty = ptr_ty.childType(mod); | |
| 2257 | 2253 | return self.allocFrameIndex(FrameAlloc.init(.{ |
| 2258 | .size = math.cast(u32, val_ty.abiSize(self.target.*)) orelse { | |
| 2259 | const mod = self.bin_file.options.module.?; | |
| 2254 | .size = math.cast(u32, val_ty.abiSize(mod)) orelse { | |
| 2260 | 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 | 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 | 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 | 2267 | } |
| 2273 | 2268 | |
| 2274 | 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 { | |
| 2276 | const mod = self.bin_file.options.module.?; | |
| 2270 | const mod = self.bin_file.options.module.?; | |
| 2271 | const abi_size = math.cast(u32, ty.abiSize(mod)) orelse { | |
| 2277 | 2272 | return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); |
| 2278 | 2273 | }; |
| 2279 | 2274 | |
| 2280 | 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 | 2277 | .Float => switch (ty.floatBits(self.target.*)) { |
| 2283 | 2278 | 16, 32, 64, 128 => 16, |
| 2284 | 2279 | 80 => break :need_mem, |
| 2285 | 2280 | else => unreachable, |
| 2286 | 2281 | }, |
| 2287 | .Vector => switch (ty.childType().zigTypeTag()) { | |
| 2288 | .Float => switch (ty.childType().floatBits(self.target.*)) { | |
| 2282 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { | |
| 2283 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { | |
| 2289 | 2284 | 16, 32, 64, 128 => if (self.hasFeature(.avx)) 32 else 16, |
| 2290 | 2285 | 80 => break :need_mem, |
| 2291 | 2286 | else => unreachable, |
| ... | ... | @@ -2294,18 +2289,18 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b |
| 2294 | 2289 | }, |
| 2295 | 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 | 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 | 2299 | return .{ .load_frame = .{ .index = frame_index } }; |
| 2305 | 2300 | } |
| 2306 | 2301 | |
| 2307 | fn regClassForType(ty: Type) RegisterManager.RegisterBitSet { | |
| 2308 | return switch (ty.zigTypeTag()) { | |
| 2302 | fn regClassForType(ty: Type, mod: *Module) RegisterManager.RegisterBitSet { | |
| 2303 | return switch (ty.zigTypeTag(mod)) { | |
| 2309 | 2304 | .Float, .Vector => sse, |
| 2310 | 2305 | else => gp, |
| 2311 | 2306 | }; |
| ... | ... | @@ -2449,7 +2444,8 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void { |
| 2449 | 2444 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 2450 | 2445 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 2451 | 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 | 2449 | try self.genSetReg(reg, ty, mcv); |
| 2454 | 2450 | return reg; |
| 2455 | 2451 | } |
| ... | ... | @@ -2464,7 +2460,8 @@ fn copyToRegisterWithInstTracking( |
| 2464 | 2460 | ty: Type, |
| 2465 | 2461 | mcv: MCValue, |
| 2466 | 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 | 2465 | try self.genSetReg(reg, ty, mcv); |
| 2469 | 2466 | return MCValue{ .register = reg }; |
| 2470 | 2467 | } |
| ... | ... | @@ -2481,7 +2478,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2481 | 2478 | .load_frame => .{ .register_offset = .{ |
| 2482 | 2479 | .reg = (try self.copyToRegisterWithInstTracking( |
| 2483 | 2480 | inst, |
| 2484 | self.air.typeOfIndex(inst), | |
| 2481 | self.typeOfIndex(inst), | |
| 2485 | 2482 | self.ret_mcv.long, |
| 2486 | 2483 | )).register, |
| 2487 | 2484 | .off = self.ret_mcv.short.indirect.off, |
| ... | ... | @@ -2492,9 +2489,9 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2492 | 2489 | |
| 2493 | 2490 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2494 | 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 | 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 | 2495 | const src_bits = src_ty.floatBits(self.target.*); |
| 2499 | 2496 | |
| 2500 | 2497 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -2558,9 +2555,9 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2558 | 2555 | |
| 2559 | 2556 | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 2560 | 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 | 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 | 2561 | const src_bits = src_ty.floatBits(self.target.*); |
| 2565 | 2562 | |
| 2566 | 2563 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -2618,14 +2615,15 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 2618 | 2615 | } |
| 2619 | 2616 | |
| 2620 | 2617 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2618 | const mod = self.bin_file.options.module.?; | |
| 2621 | 2619 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2622 | 2620 | const result: MCValue = result: { |
| 2623 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 2624 | const src_int_info = src_ty.intInfo(self.target.*); | |
| 2621 | const src_ty = self.typeOf(ty_op.operand); | |
| 2622 | const src_int_info = src_ty.intInfo(mod); | |
| 2625 | 2623 | |
| 2626 | const dst_ty = self.air.typeOfIndex(inst); | |
| 2627 | const dst_int_info = dst_ty.intInfo(self.target.*); | |
| 2628 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | |
| 2624 | const dst_ty = self.typeOfIndex(inst); | |
| 2625 | const dst_int_info = dst_ty.intInfo(mod); | |
| 2626 | const abi_size = @intCast(u32, dst_ty.abiSize(mod)); | |
| 2629 | 2627 | |
| 2630 | 2628 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| 2631 | 2629 | const extend = switch (src_int_info.signedness) { |
| ... | ... | @@ -2670,14 +2668,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2670 | 2668 | |
| 2671 | 2669 | const high_bits = src_int_info.bits % 64; |
| 2672 | 2670 | if (high_bits > 0) { |
| 2673 | var high_pl = Type.Payload.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); | |
| 2671 | const high_ty = try mod.intType(extend, high_bits); | |
| 2681 | 2672 | try self.truncateRegister(high_ty, high_reg); |
| 2682 | 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 | 2697 | } |
| 2707 | 2698 | |
| 2708 | 2699 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2700 | const mod = self.bin_file.options.module.?; | |
| 2709 | 2701 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2710 | 2702 | |
| 2711 | const dst_ty = self.air.typeOfIndex(inst); | |
| 2712 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | |
| 2713 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 2714 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | |
| 2703 | const dst_ty = self.typeOfIndex(inst); | |
| 2704 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); | |
| 2705 | const src_ty = self.typeOf(ty_op.operand); | |
| 2706 | const src_abi_size = @intCast(u32, src_ty.abiSize(mod)); | |
| 2715 | 2707 | |
| 2716 | 2708 | const result = result: { |
| 2717 | 2709 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -2724,13 +2716,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2724 | 2716 | else |
| 2725 | 2717 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2726 | 2718 | |
| 2727 | if (dst_ty.zigTypeTag() == .Vector) { | |
| 2728 | assert(src_ty.zigTypeTag() == .Vector and dst_ty.vectorLen() == src_ty.vectorLen()); | |
| 2729 | const dst_info = dst_ty.childType().intInfo(self.target.*); | |
| 2730 | const src_info = src_ty.childType().intInfo(self.target.*); | |
| 2719 | if (dst_ty.zigTypeTag(mod) == .Vector) { | |
| 2720 | assert(src_ty.zigTypeTag(mod) == .Vector and dst_ty.vectorLen(mod) == src_ty.vectorLen(mod)); | |
| 2721 | const dst_info = dst_ty.childType(mod).intInfo(mod); | |
| 2722 | const src_info = src_ty.childType(mod).intInfo(mod); | |
| 2731 | 2723 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (dst_info.bits) { |
| 2732 | 2724 | 8 => switch (src_info.bits) { |
| 2733 | 16 => switch (dst_ty.vectorLen()) { | |
| 2725 | 16 => switch (dst_ty.vectorLen(mod)) { | |
| 2734 | 2726 | 1...8 => if (self.hasFeature(.avx)) .{ .vp_b, .ackusw } else .{ .p_b, .ackusw }, |
| 2735 | 2727 | 9...16 => if (self.hasFeature(.avx2)) .{ .vp_b, .ackusw } else null, |
| 2736 | 2728 | else => null, |
| ... | ... | @@ -2738,7 +2730,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2738 | 2730 | else => null, |
| 2739 | 2731 | }, |
| 2740 | 2732 | 16 => switch (src_info.bits) { |
| 2741 | 32 => switch (dst_ty.vectorLen()) { | |
| 2733 | 32 => switch (dst_ty.vectorLen(mod)) { | |
| 2742 | 2734 | 1...4 => if (self.hasFeature(.avx)) |
| 2743 | 2735 | .{ .vp_w, .ackusd } |
| 2744 | 2736 | else if (self.hasFeature(.sse4_1)) |
| ... | ... | @@ -2755,29 +2747,21 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2755 | 2747 | dst_ty.fmt(self.bin_file.options.module.?), |
| 2756 | 2748 | }); |
| 2757 | 2749 | |
| 2758 | var mask_pl = Value.Payload.U64{ | |
| 2759 | .base = .{ .tag = .int_u64 }, | |
| 2760 | .data = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - dst_info.bits), | |
| 2761 | }; | |
| 2762 | const mask_val = Value.initPayload(&mask_pl.base); | |
| 2750 | const elem_ty = src_ty.childType(mod); | |
| 2751 | const mask_val = try mod.intValue(elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - dst_info.bits)); | |
| 2763 | 2752 | |
| 2764 | var splat_pl = Value.Payload.SubValue{ | |
| 2765 | .base = .{ .tag = .repeated }, | |
| 2766 | .data = mask_val, | |
| 2767 | }; | |
| 2768 | const splat_val = Value.initPayload(&splat_pl.base); | |
| 2753 | const splat_ty = try mod.vectorType(.{ | |
| 2754 | .len = @intCast(u32, @divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits)), | |
| 2755 | .child = elem_ty.ip_index, | |
| 2756 | }); | |
| 2757 | const splat_abi_size = @intCast(u32, splat_ty.abiSize(mod)); | |
| 2769 | 2758 | |
| 2770 | var full_pl = Type.Payload.Array{ | |
| 2771 | .base = .{ .tag = .vector }, | |
| 2772 | .data = .{ | |
| 2773 | .len = @divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits), | |
| 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.*)); | |
| 2759 | const splat_val = try mod.intern(.{ .aggregate = .{ | |
| 2760 | .ty = splat_ty.ip_index, | |
| 2761 | .storage = .{ .repeated_elem = mask_val.ip_index }, | |
| 2762 | } }); | |
| 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 | 2765 | const splat_addr_mcv: MCValue = switch (splat_mcv) { |
| 2782 | 2766 | .memory, .indirect, .load_frame => splat_mcv.address(), |
| 2783 | 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 | 2773 | .{ .vp_, .@"and" }, |
| 2790 | 2774 | dst_reg, |
| 2791 | 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 | 2778 | try self.asmRegisterRegisterRegister(mir_tag, dst_reg, dst_reg, dst_reg); |
| 2795 | 2779 | } else { |
| 2796 | 2780 | try self.asmRegisterMemory( |
| 2797 | 2781 | .{ .p_, .@"and" }, |
| 2798 | 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 | 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 | 2803 | |
| 2820 | 2804 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 2821 | 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 | 2808 | const operand = try self.resolveInst(un_op); |
| 2825 | 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 | 2815 | } |
| 2832 | 2816 | |
| 2833 | 2817 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2818 | const mod = self.bin_file.options.module.?; | |
| 2834 | 2819 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2835 | 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 | 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 | 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 | 2829 | try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr); |
| 2845 | 2830 | try self.genSetMem( |
| 2846 | 2831 | .{ .frame = frame_index }, |
| 2847 | @intCast(i32, ptr_ty.abiSize(self.target.*)), | |
| 2832 | @intCast(i32, ptr_ty.abiSize(mod)), | |
| 2848 | 2833 | len_ty, |
| 2849 | 2834 | len, |
| 2850 | 2835 | ); |
| ... | ... | @@ -2873,23 +2858,24 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 2873 | 2858 | } |
| 2874 | 2859 | |
| 2875 | 2860 | fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| 2861 | const mod = self.bin_file.options.module.?; | |
| 2876 | 2862 | const air_tag = self.air.instructions.items(.tag); |
| 2877 | 2863 | const air_data = self.air.instructions.items(.data); |
| 2878 | 2864 | |
| 2879 | const dst_ty = self.air.typeOf(dst_air); | |
| 2880 | const dst_info = dst_ty.intInfo(self.target.*); | |
| 2865 | const dst_ty = self.typeOf(dst_air); | |
| 2866 | const dst_info = dst_ty.intInfo(mod); | |
| 2881 | 2867 | if (Air.refToIndex(dst_air)) |inst| { |
| 2882 | 2868 | switch (air_tag[inst]) { |
| 2883 | .constant => { | |
| 2884 | const src_val = self.air.values[air_data[inst].ty_pl.payload]; | |
| 2869 | .interned => { | |
| 2870 | const src_val = air_data[inst].interned.toValue(); | |
| 2885 | 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 | 2873 | return @intCast(u16, src_int.bitCountTwosComp()) + |
| 2888 | 2874 | @boolToInt(src_int.positive and dst_info.signedness == .signed); |
| 2889 | 2875 | }, |
| 2890 | 2876 | .intcast => { |
| 2891 | const src_ty = self.air.typeOf(air_data[inst].ty_op.operand); | |
| 2892 | const src_info = src_ty.intInfo(self.target.*); | |
| 2877 | const src_ty = self.typeOf(air_data[inst].ty_op.operand); | |
| 2878 | const src_info = src_ty.intInfo(mod); | |
| 2893 | 2879 | return @min(switch (src_info.signedness) { |
| 2894 | 2880 | .signed => switch (dst_info.signedness) { |
| 2895 | 2881 | .signed => src_info.bits, |
| ... | ... | @@ -2908,20 +2894,18 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| 2908 | 2894 | } |
| 2909 | 2895 | |
| 2910 | 2896 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2897 | const mod = self.bin_file.options.module.?; | |
| 2911 | 2898 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2912 | 2899 | const result = result: { |
| 2913 | 2900 | const tag = self.air.instructions.items(.tag)[inst]; |
| 2914 | const dst_ty = self.air.typeOfIndex(inst); | |
| 2915 | switch (dst_ty.zigTypeTag()) { | |
| 2901 | const dst_ty = self.typeOfIndex(inst); | |
| 2902 | switch (dst_ty.zigTypeTag(mod)) { | |
| 2916 | 2903 | .Float, .Vector => break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs), |
| 2917 | 2904 | else => {}, |
| 2918 | 2905 | } |
| 2919 | 2906 | |
| 2920 | const dst_info = dst_ty.intInfo(self.target.*); | |
| 2921 | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { | |
| 2922 | .signed => .int_signed, | |
| 2923 | .unsigned => .int_unsigned, | |
| 2924 | } }, .data = switch (tag) { | |
| 2907 | const dst_info = dst_ty.intInfo(mod); | |
| 2908 | const src_ty = try mod.intType(dst_info.signedness, switch (tag) { | |
| 2925 | 2909 | else => unreachable, |
| 2926 | 2910 | .mul, .mulwrap => math.max3( |
| 2927 | 2911 | self.activeIntBits(bin_op.lhs), |
| ... | ... | @@ -2929,8 +2913,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2929 | 2913 | dst_info.bits / 2, |
| 2930 | 2914 | ), |
| 2931 | 2915 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_info.bits, |
| 2932 | } }; | |
| 2933 | const src_ty = Type.initPayload(&src_pl.base); | |
| 2916 | }); | |
| 2934 | 2917 | |
| 2935 | 2918 | try self.spillEflagsIfOccupied(); |
| 2936 | 2919 | try self.spillRegisters(&.{ .rax, .rdx }); |
| ... | ... | @@ -2942,8 +2925,9 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2942 | 2925 | } |
| 2943 | 2926 | |
| 2944 | 2927 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2928 | const mod = self.bin_file.options.module.?; | |
| 2945 | 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 | 2932 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 2949 | 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 | 2952 | |
| 2969 | 2953 | const reg_bits = self.regBitSize(ty); |
| 2970 | 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 | 2956 | if (reg_extra_bits > 0) { |
| 2973 | 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 | 2978 | break :cc .o; |
| 2995 | 2979 | } else cc: { |
| 2996 | 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 | 2984 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv); |
| ... | ... | @@ -3005,14 +2989,14 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3005 | 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 | 2993 | try self.asmCmovccRegisterRegister( |
| 3010 | 2994 | registerAlias(dst_reg, cmov_abi_size), |
| 3011 | 2995 | registerAlias(limit_reg, cmov_abi_size), |
| 3012 | 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 | 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 | 3004 | } |
| 3021 | 3005 | |
| 3022 | 3006 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3007 | const mod = self.bin_file.options.module.?; | |
| 3023 | 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 | 3011 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 3027 | 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 | 3031 | |
| 3047 | 3032 | const reg_bits = self.regBitSize(ty); |
| 3048 | 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 | 3035 | if (reg_extra_bits > 0) { |
| 3051 | 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 | 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 | 3065 | try self.asmCmovccRegisterRegister( |
| 3081 | 3066 | registerAlias(dst_reg, cmov_abi_size), |
| 3082 | 3067 | registerAlias(limit_reg, cmov_abi_size), |
| 3083 | 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 | 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 | 3076 | } |
| 3092 | 3077 | |
| 3093 | 3078 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3079 | const mod = self.bin_file.options.module.?; | |
| 3094 | 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 | 3083 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 3098 | 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 | 3104 | defer self.register_manager.unlockReg(limit_lock); |
| 3119 | 3105 | |
| 3120 | 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 | 3108 | try self.genSetReg(limit_reg, ty, lhs_mcv); |
| 3123 | 3109 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv); |
| 3124 | 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 | 3120 | }; |
| 3135 | 3121 | |
| 3136 | 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 | 3124 | try self.asmCmovccRegisterRegister( |
| 3139 | 3125 | registerAlias(dst_mcv.register, cmov_abi_size), |
| 3140 | 3126 | registerAlias(limit_reg, cmov_abi_size), |
| ... | ... | @@ -3145,12 +3131,13 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3145 | 3131 | } |
| 3146 | 3132 | |
| 3147 | 3133 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3134 | const mod = self.bin_file.options.module.?; | |
| 3148 | 3135 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3149 | 3136 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3150 | 3137 | const result: MCValue = result: { |
| 3151 | 3138 | const tag = self.air.instructions.items(.tag)[inst]; |
| 3152 | const ty = self.air.typeOf(bin_op.lhs); | |
| 3153 | switch (ty.zigTypeTag()) { | |
| 3139 | const ty = self.typeOf(bin_op.lhs); | |
| 3140 | switch (ty.zigTypeTag(mod)) { | |
| 3154 | 3141 | .Vector => return self.fail("TODO implement add/sub with overflow for Vector type", .{}), |
| 3155 | 3142 | .Int => { |
| 3156 | 3143 | try self.spillEflagsIfOccupied(); |
| ... | ... | @@ -3160,13 +3147,13 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3160 | 3147 | .sub_with_overflow => .sub, |
| 3161 | 3148 | else => unreachable, |
| 3162 | 3149 | }, bin_op.lhs, bin_op.rhs); |
| 3163 | const int_info = ty.intInfo(self.target.*); | |
| 3150 | const int_info = ty.intInfo(mod); | |
| 3164 | 3151 | const cc: Condition = switch (int_info.signedness) { |
| 3165 | 3152 | .unsigned => .c, |
| 3166 | 3153 | .signed => .o, |
| 3167 | 3154 | }; |
| 3168 | 3155 | |
| 3169 | const tuple_ty = self.air.typeOfIndex(inst); | |
| 3156 | const tuple_ty = self.typeOfIndex(inst); | |
| 3170 | 3157 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 3171 | 3158 | switch (partial_mcv) { |
| 3172 | 3159 | .register => |reg| { |
| ... | ... | @@ -3177,16 +3164,16 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3177 | 3164 | } |
| 3178 | 3165 | |
| 3179 | 3166 | const frame_index = |
| 3180 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | |
| 3167 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); | |
| 3181 | 3168 | try self.genSetMem( |
| 3182 | 3169 | .{ .frame = frame_index }, |
| 3183 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | |
| 3170 | @intCast(i32, tuple_ty.structFieldOffset(1, mod)), | |
| 3184 | 3171 | Type.u1, |
| 3185 | 3172 | .{ .eflags = cc }, |
| 3186 | 3173 | ); |
| 3187 | 3174 | try self.genSetMem( |
| 3188 | 3175 | .{ .frame = frame_index }, |
| 3189 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), | |
| 3176 | @intCast(i32, tuple_ty.structFieldOffset(0, mod)), | |
| 3190 | 3177 | ty, |
| 3191 | 3178 | partial_mcv, |
| 3192 | 3179 | ); |
| ... | ... | @@ -3194,7 +3181,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3194 | 3181 | } |
| 3195 | 3182 | |
| 3196 | 3183 | const frame_index = |
| 3197 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | |
| 3184 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); | |
| 3198 | 3185 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 3199 | 3186 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3200 | 3187 | }, |
| ... | ... | @@ -3205,12 +3192,13 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3205 | 3192 | } |
| 3206 | 3193 | |
| 3207 | 3194 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3195 | const mod = self.bin_file.options.module.?; | |
| 3208 | 3196 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3209 | 3197 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3210 | 3198 | const result: MCValue = result: { |
| 3211 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 3212 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 3213 | switch (lhs_ty.zigTypeTag()) { | |
| 3199 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 3200 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 3201 | switch (lhs_ty.zigTypeTag(mod)) { | |
| 3214 | 3202 | .Vector => return self.fail("TODO implement shl with overflow for Vector type", .{}), |
| 3215 | 3203 | .Int => { |
| 3216 | 3204 | try self.spillEflagsIfOccupied(); |
| ... | ... | @@ -3219,7 +3207,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3219 | 3207 | const lhs = try self.resolveInst(bin_op.lhs); |
| 3220 | 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 | 3212 | const partial_mcv = try self.genShiftBinOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty); |
| 3225 | 3213 | const partial_lock = switch (partial_mcv) { |
| ... | ... | @@ -3238,7 +3226,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3238 | 3226 | try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, tmp_mcv, lhs); |
| 3239 | 3227 | const cc = Condition.ne; |
| 3240 | 3228 | |
| 3241 | const tuple_ty = self.air.typeOfIndex(inst); | |
| 3229 | const tuple_ty = self.typeOfIndex(inst); | |
| 3242 | 3230 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 3243 | 3231 | switch (partial_mcv) { |
| 3244 | 3232 | .register => |reg| { |
| ... | ... | @@ -3249,24 +3237,24 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3249 | 3237 | } |
| 3250 | 3238 | |
| 3251 | 3239 | const frame_index = |
| 3252 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | |
| 3240 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); | |
| 3253 | 3241 | try self.genSetMem( |
| 3254 | 3242 | .{ .frame = frame_index }, |
| 3255 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | |
| 3256 | tuple_ty.structFieldType(1), | |
| 3243 | @intCast(i32, tuple_ty.structFieldOffset(1, mod)), | |
| 3244 | tuple_ty.structFieldType(1, mod), | |
| 3257 | 3245 | .{ .eflags = cc }, |
| 3258 | 3246 | ); |
| 3259 | 3247 | try self.genSetMem( |
| 3260 | 3248 | .{ .frame = frame_index }, |
| 3261 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), | |
| 3262 | tuple_ty.structFieldType(0), | |
| 3249 | @intCast(i32, tuple_ty.structFieldOffset(0, mod)), | |
| 3250 | tuple_ty.structFieldType(0, mod), | |
| 3263 | 3251 | partial_mcv, |
| 3264 | 3252 | ); |
| 3265 | 3253 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3266 | 3254 | } |
| 3267 | 3255 | |
| 3268 | 3256 | const frame_index = |
| 3269 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | |
| 3257 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); | |
| 3270 | 3258 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 3271 | 3259 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3272 | 3260 | }, |
| ... | ... | @@ -3283,29 +3271,20 @@ fn genSetFrameTruncatedOverflowCompare( |
| 3283 | 3271 | src_mcv: MCValue, |
| 3284 | 3272 | overflow_cc: ?Condition, |
| 3285 | 3273 | ) !void { |
| 3274 | const mod = self.bin_file.options.module.?; | |
| 3286 | 3275 | const src_lock = switch (src_mcv) { |
| 3287 | 3276 | .register => |reg| self.register_manager.lockReg(reg), |
| 3288 | 3277 | else => null, |
| 3289 | 3278 | }; |
| 3290 | 3279 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 3291 | 3280 | |
| 3292 | const ty = tuple_ty.structFieldType(0); | |
| 3293 | const int_info = ty.intInfo(self.target.*); | |
| 3281 | const ty = tuple_ty.structFieldType(0, mod); | |
| 3282 | const int_info = ty.intInfo(mod); | |
| 3294 | 3283 | |
| 3295 | var hi_limb_pl = Type.Payload.Bits{ | |
| 3296 | .base = .{ .tag = switch (int_info.signedness) { | |
| 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); | |
| 3284 | const hi_limb_bits = (int_info.bits - 1) % 64 + 1; | |
| 3285 | const hi_limb_ty = try mod.intType(int_info.signedness, hi_limb_bits); | |
| 3303 | 3286 | |
| 3304 | var rest_pl = Type.Payload.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); | |
| 3287 | const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_limb_bits); | |
| 3309 | 3288 | |
| 3310 | 3289 | const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp); |
| 3311 | 3290 | const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); |
| ... | ... | @@ -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 | 3318 | if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv); |
| 3340 | 3319 | try self.genSetMem( |
| 3341 | 3320 | .{ .frame = frame_index }, |
| ... | ... | @@ -3345,23 +3324,24 @@ fn genSetFrameTruncatedOverflowCompare( |
| 3345 | 3324 | ); |
| 3346 | 3325 | try self.genSetMem( |
| 3347 | 3326 | .{ .frame = frame_index }, |
| 3348 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | |
| 3349 | tuple_ty.structFieldType(1), | |
| 3327 | @intCast(i32, tuple_ty.structFieldOffset(1, mod)), | |
| 3328 | tuple_ty.structFieldType(1, mod), | |
| 3350 | 3329 | if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne }, |
| 3351 | 3330 | ); |
| 3352 | 3331 | } |
| 3353 | 3332 | |
| 3354 | 3333 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3334 | const mod = self.bin_file.options.module.?; | |
| 3355 | 3335 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3356 | 3336 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3357 | const dst_ty = self.air.typeOf(bin_op.lhs); | |
| 3358 | const result: MCValue = switch (dst_ty.zigTypeTag()) { | |
| 3337 | const dst_ty = self.typeOf(bin_op.lhs); | |
| 3338 | const result: MCValue = switch (dst_ty.zigTypeTag(mod)) { | |
| 3359 | 3339 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 3360 | 3340 | .Int => result: { |
| 3361 | 3341 | try self.spillEflagsIfOccupied(); |
| 3362 | 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 | 3345 | const cc: Condition = switch (dst_info.signedness) { |
| 3366 | 3346 | .unsigned => .c, |
| 3367 | 3347 | .signed => .o, |
| ... | ... | @@ -3369,16 +3349,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3369 | 3349 | |
| 3370 | 3350 | const lhs_active_bits = self.activeIntBits(bin_op.lhs); |
| 3371 | 3351 | const rhs_active_bits = self.activeIntBits(bin_op.rhs); |
| 3372 | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { | |
| 3373 | .signed => .int_signed, | |
| 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); | |
| 3352 | const src_bits = math.max3(lhs_active_bits, rhs_active_bits, dst_info.bits / 2); | |
| 3353 | const src_ty = try mod.intType(dst_info.signedness, src_bits); | |
| 3377 | 3354 | |
| 3378 | 3355 | const lhs = try self.resolveInst(bin_op.lhs); |
| 3379 | 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 | 3359 | const extra_bits = if (dst_info.bits <= 64) |
| 3383 | 3360 | self.regExtraBits(dst_ty) |
| 3384 | 3361 | else |
| ... | ... | @@ -3391,27 +3368,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3391 | 3368 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; |
| 3392 | 3369 | } else { |
| 3393 | 3370 | const frame_index = |
| 3394 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | |
| 3371 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); | |
| 3395 | 3372 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 3396 | 3373 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3397 | 3374 | }, |
| 3398 | 3375 | else => { |
| 3399 | 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 | 3379 | const frame_index = |
| 3403 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | |
| 3380 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); | |
| 3404 | 3381 | if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { |
| 3405 | 3382 | try self.genSetMem( |
| 3406 | 3383 | .{ .frame = frame_index }, |
| 3407 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), | |
| 3408 | tuple_ty.structFieldType(0), | |
| 3384 | @intCast(i32, tuple_ty.structFieldOffset(0, mod)), | |
| 3385 | tuple_ty.structFieldType(0, mod), | |
| 3409 | 3386 | partial_mcv, |
| 3410 | 3387 | ); |
| 3411 | 3388 | try self.genSetMem( |
| 3412 | 3389 | .{ .frame = frame_index }, |
| 3413 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | |
| 3414 | tuple_ty.structFieldType(1), | |
| 3390 | @intCast(i32, tuple_ty.structFieldOffset(1, mod)), | |
| 3391 | tuple_ty.structFieldType(1, mod), | |
| 3415 | 3392 | .{ .immediate = 0 }, // cc being set is impossible |
| 3416 | 3393 | ); |
| 3417 | 3394 | } else try self.genSetFrameTruncatedOverflowCompare( |
| ... | ... | @@ -3433,7 +3410,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3433 | 3410 | /// Clobbers .rax and .rdx registers. |
| 3434 | 3411 | /// Quotient is saved in .rax and remainder in .rdx. |
| 3435 | 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 | 3415 | if (abi_size > 8) { |
| 3438 | 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 | 3450 | /// Always returns a register. |
| 3473 | 3451 | /// Clobbers .rax and .rdx registers. |
| 3474 | 3452 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 3475 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | |
| 3476 | const int_info = ty.intInfo(self.target.*); | |
| 3453 | const mod = self.bin_file.options.module.?; | |
| 3454 | const abi_size = @intCast(u32, ty.abiSize(mod)); | |
| 3455 | const int_info = ty.intInfo(mod); | |
| 3477 | 3456 | const dividend: Register = switch (lhs) { |
| 3478 | 3457 | .register => |reg| reg, |
| 3479 | 3458 | else => try self.copyToTmpRegister(ty, lhs), |
| ... | ... | @@ -3531,8 +3510,8 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3531 | 3510 | try self.register_manager.getReg(.rcx, null); |
| 3532 | 3511 | const lhs = try self.resolveInst(bin_op.lhs); |
| 3533 | 3512 | const rhs = try self.resolveInst(bin_op.rhs); |
| 3534 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 3535 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 3513 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 3514 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 3536 | 3515 | |
| 3537 | 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 | 3528 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3550 | 3529 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3551 | 3530 | const result: MCValue = result: { |
| 3552 | const pl_ty = self.air.typeOfIndex(inst); | |
| 3531 | const pl_ty = self.typeOfIndex(inst); | |
| 3553 | 3532 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 3554 | 3533 | |
| 3555 | 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 | 3553 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3575 | 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 | 3557 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 3579 | 3558 | |
| 3580 | 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 | 3564 | } |
| 3586 | 3565 | |
| 3587 | 3566 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3567 | const mod = self.bin_file.options.module.?; | |
| 3588 | 3568 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3589 | 3569 | const result = result: { |
| 3590 | const dst_ty = self.air.typeOfIndex(inst); | |
| 3591 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 3592 | const opt_ty = src_ty.childType(); | |
| 3570 | const dst_ty = self.typeOfIndex(inst); | |
| 3571 | const src_ty = self.typeOf(ty_op.operand); | |
| 3572 | const opt_ty = src_ty.childType(mod); | |
| 3593 | 3573 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3594 | 3574 | |
| 3595 | if (opt_ty.optionalReprIsPayload()) { | |
| 3575 | if (opt_ty.optionalReprIsPayload(mod)) { | |
| 3596 | 3576 | break :result if (self.liveness.isUnused(inst)) |
| 3597 | 3577 | .unreach |
| 3598 | 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 | 3589 | else |
| 3610 | 3590 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 3611 | 3591 | |
| 3612 | const pl_ty = dst_ty.childType(); | |
| 3613 | const pl_abi_size = @intCast(i32, pl_ty.abiSize(self.target.*)); | |
| 3592 | const pl_ty = dst_ty.childType(mod); | |
| 3593 | const pl_abi_size = @intCast(i32, pl_ty.abiSize(mod)); | |
| 3614 | 3594 | try self.genSetMem(.{ .reg = dst_mcv.getReg().? }, pl_abi_size, Type.bool, .{ .immediate = 1 }); |
| 3615 | 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 | 3598 | } |
| 3619 | 3599 | |
| 3620 | 3600 | fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3601 | const mod = self.bin_file.options.module.?; | |
| 3621 | 3602 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3622 | const err_union_ty = self.air.typeOf(ty_op.operand); | |
| 3623 | const err_ty = err_union_ty.errorUnionSet(); | |
| 3624 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 3603 | const err_union_ty = self.typeOf(ty_op.operand); | |
| 3604 | const err_ty = err_union_ty.errorUnionSet(mod); | |
| 3605 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 3625 | 3606 | const operand = try self.resolveInst(ty_op.operand); |
| 3626 | 3607 | |
| 3627 | 3608 | const result: MCValue = result: { |
| 3628 | if (err_ty.errorSetIsEmpty()) { | |
| 3609 | if (err_ty.errorSetIsEmpty(mod)) { | |
| 3629 | 3610 | break :result MCValue{ .immediate = 0 }; |
| 3630 | 3611 | } |
| 3631 | 3612 | |
| 3632 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3613 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3633 | 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 | 3618 | switch (operand) { |
| 3638 | 3619 | .register => |reg| { |
| 3639 | 3620 | // TODO reuse operand |
| ... | ... | @@ -3666,7 +3647,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3666 | 3647 | |
| 3667 | 3648 | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3668 | 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 | 3651 | const operand = try self.resolveInst(ty_op.operand); |
| 3671 | 3652 | const result = try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, operand); |
| 3672 | 3653 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | ... | @@ -3678,12 +3659,13 @@ fn genUnwrapErrorUnionPayloadMir( |
| 3678 | 3659 | err_union_ty: Type, |
| 3679 | 3660 | err_union: MCValue, |
| 3680 | 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 | 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 | 3669 | switch (err_union) { |
| 3688 | 3670 | .load_frame => |frame_addr| break :result .{ .load_frame = .{ |
| 3689 | 3671 | .index = frame_addr.index, |
| ... | ... | @@ -3720,9 +3702,10 @@ fn genUnwrapErrorUnionPayloadMir( |
| 3720 | 3702 | |
| 3721 | 3703 | // *(E!T) -> E |
| 3722 | 3704 | fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3705 | const mod = self.bin_file.options.module.?; | |
| 3723 | 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 | 3709 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3727 | 3710 | const src_reg = switch (src_mcv) { |
| 3728 | 3711 | .register => |reg| reg, |
| ... | ... | @@ -3736,11 +3719,11 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3736 | 3719 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 3737 | 3720 | defer self.register_manager.unlockReg(dst_lock); |
| 3738 | 3721 | |
| 3739 | const eu_ty = src_ty.childType(); | |
| 3740 | const pl_ty = eu_ty.errorUnionPayload(); | |
| 3741 | const err_ty = eu_ty.errorUnionSet(); | |
| 3742 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | |
| 3743 | const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); | |
| 3722 | const eu_ty = src_ty.childType(mod); | |
| 3723 | const pl_ty = eu_ty.errorUnionPayload(mod); | |
| 3724 | const err_ty = eu_ty.errorUnionSet(mod); | |
| 3725 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); | |
| 3726 | const err_abi_size = @intCast(u32, err_ty.abiSize(mod)); | |
| 3744 | 3727 | try self.asmRegisterMemory( |
| 3745 | 3728 | .{ ._, .mov }, |
| 3746 | 3729 | registerAlias(dst_reg, err_abi_size), |
| ... | ... | @@ -3755,9 +3738,10 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3755 | 3738 | |
| 3756 | 3739 | // *(E!T) -> *T |
| 3757 | 3740 | fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3741 | const mod = self.bin_file.options.module.?; | |
| 3758 | 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 | 3745 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3762 | 3746 | const src_reg = switch (src_mcv) { |
| 3763 | 3747 | .register => |reg| reg, |
| ... | ... | @@ -3766,7 +3750,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3766 | 3750 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 3767 | 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 | 3754 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3771 | 3755 | src_reg |
| 3772 | 3756 | else |
| ... | ... | @@ -3775,10 +3759,10 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3775 | 3759 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 3776 | 3760 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 3777 | 3761 | |
| 3778 | const eu_ty = src_ty.childType(); | |
| 3779 | const pl_ty = eu_ty.errorUnionPayload(); | |
| 3780 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | |
| 3781 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | |
| 3762 | const eu_ty = src_ty.childType(mod); | |
| 3763 | const pl_ty = eu_ty.errorUnionPayload(mod); | |
| 3764 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); | |
| 3765 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); | |
| 3782 | 3766 | try self.asmRegisterMemory( |
| 3783 | 3767 | .{ ._, .lea }, |
| 3784 | 3768 | registerAlias(dst_reg, dst_abi_size), |
| ... | ... | @@ -3789,9 +3773,10 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3789 | 3773 | } |
| 3790 | 3774 | |
| 3791 | 3775 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3776 | const mod = self.bin_file.options.module.?; | |
| 3792 | 3777 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3793 | 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 | 3780 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3796 | 3781 | const src_reg = switch (src_mcv) { |
| 3797 | 3782 | .register => |reg| reg, |
| ... | ... | @@ -3800,11 +3785,11 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3800 | 3785 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 3801 | 3786 | defer self.register_manager.unlockReg(src_lock); |
| 3802 | 3787 | |
| 3803 | const eu_ty = src_ty.childType(); | |
| 3804 | const pl_ty = eu_ty.errorUnionPayload(); | |
| 3805 | const err_ty = eu_ty.errorUnionSet(); | |
| 3806 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | |
| 3807 | const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); | |
| 3788 | const eu_ty = src_ty.childType(mod); | |
| 3789 | const pl_ty = eu_ty.errorUnionPayload(mod); | |
| 3790 | const err_ty = eu_ty.errorUnionSet(mod); | |
| 3791 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); | |
| 3792 | const err_abi_size = @intCast(u32, err_ty.abiSize(mod)); | |
| 3808 | 3793 | try self.asmMemoryImmediate( |
| 3809 | 3794 | .{ ._, .mov }, |
| 3810 | 3795 | Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ |
| ... | ... | @@ -3816,7 +3801,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3816 | 3801 | |
| 3817 | 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 | 3805 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3821 | 3806 | src_reg |
| 3822 | 3807 | else |
| ... | ... | @@ -3824,8 +3809,8 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3824 | 3809 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 3825 | 3810 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 3826 | 3811 | |
| 3827 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | |
| 3828 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | |
| 3812 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); | |
| 3813 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); | |
| 3829 | 3814 | try self.asmRegisterMemory( |
| 3830 | 3815 | .{ ._, .lea }, |
| 3831 | 3816 | registerAlias(dst_reg, dst_abi_size), |
| ... | ... | @@ -3853,14 +3838,15 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 3853 | 3838 | } |
| 3854 | 3839 | |
| 3855 | 3840 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3841 | const mod = self.bin_file.options.module.?; | |
| 3856 | 3842 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3857 | 3843 | const result: MCValue = result: { |
| 3858 | const pl_ty = self.air.typeOf(ty_op.operand); | |
| 3859 | if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 }; | |
| 3844 | const pl_ty = self.typeOf(ty_op.operand); | |
| 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 | 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 | 3850 | if (same_repr and self.reuseOperand(inst, ty_op.operand, 0, pl_mcv)) break :result pl_mcv; |
| 3865 | 3851 | |
| 3866 | 3852 | const pl_lock: ?RegisterLock = switch (pl_mcv) { |
| ... | ... | @@ -3873,7 +3859,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3873 | 3859 | try self.genCopy(pl_ty, opt_mcv, pl_mcv); |
| 3874 | 3860 | |
| 3875 | 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 | 3863 | switch (opt_mcv) { |
| 3878 | 3864 | else => unreachable, |
| 3879 | 3865 | |
| ... | ... | @@ -3900,19 +3886,20 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3900 | 3886 | |
| 3901 | 3887 | /// T to E!T |
| 3902 | 3888 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3889 | const mod = self.bin_file.options.module.?; | |
| 3903 | 3890 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3904 | 3891 | |
| 3905 | 3892 | const eu_ty = self.air.getRefType(ty_op.ty); |
| 3906 | const pl_ty = eu_ty.errorUnionPayload(); | |
| 3907 | const err_ty = eu_ty.errorUnionSet(); | |
| 3893 | const pl_ty = eu_ty.errorUnionPayload(mod); | |
| 3894 | const err_ty = eu_ty.errorUnionSet(mod); | |
| 3908 | 3895 | const operand = try self.resolveInst(ty_op.operand); |
| 3909 | 3896 | |
| 3910 | 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.*)); | |
| 3914 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | |
| 3915 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | |
| 3900 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(eu_ty, mod)); | |
| 3901 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); | |
| 3902 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); | |
| 3916 | 3903 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, operand); |
| 3917 | 3904 | try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, .{ .immediate = 0 }); |
| 3918 | 3905 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| ... | ... | @@ -3922,18 +3909,19 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3922 | 3909 | |
| 3923 | 3910 | /// E to E!T |
| 3924 | 3911 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3912 | const mod = self.bin_file.options.module.?; | |
| 3925 | 3913 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3926 | 3914 | |
| 3927 | 3915 | const eu_ty = self.air.getRefType(ty_op.ty); |
| 3928 | const pl_ty = eu_ty.errorUnionPayload(); | |
| 3929 | const err_ty = eu_ty.errorUnionSet(); | |
| 3916 | const pl_ty = eu_ty.errorUnionPayload(mod); | |
| 3917 | const err_ty = eu_ty.errorUnionSet(mod); | |
| 3930 | 3918 | |
| 3931 | 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.*)); | |
| 3935 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | |
| 3936 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | |
| 3922 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(eu_ty, mod)); | |
| 3923 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); | |
| 3924 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); | |
| 3937 | 3925 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef); |
| 3938 | 3926 | const operand = try self.resolveInst(ty_op.operand); |
| 3939 | 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 | 3937 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 3950 | 3938 | |
| 3951 | 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 | 3941 | try self.genCopy(dst_ty, dst_mcv, src_mcv); |
| 3954 | 3942 | break :result dst_mcv; |
| 3955 | 3943 | }; |
| ... | ... | @@ -3974,9 +3962,10 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 3974 | 3962 | } |
| 3975 | 3963 | |
| 3976 | 3964 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3965 | const mod = self.bin_file.options.module.?; | |
| 3977 | 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 | 3969 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3981 | 3970 | const src_reg = switch (src_mcv) { |
| 3982 | 3971 | .register => |reg| reg, |
| ... | ... | @@ -3985,7 +3974,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3985 | 3974 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 3986 | 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 | 3978 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3990 | 3979 | src_reg |
| 3991 | 3980 | else |
| ... | ... | @@ -3994,7 +3983,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3994 | 3983 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 3995 | 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 | 3987 | try self.asmRegisterMemory( |
| 3999 | 3988 | .{ ._, .lea }, |
| 4000 | 3989 | registerAlias(dst_reg, dst_abi_size), |
| ... | ... | @@ -4010,7 +3999,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4010 | 3999 | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4011 | 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 | 4003 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 4015 | 4004 | |
| 4016 | 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 | 4030 | } |
| 4042 | 4031 | |
| 4043 | 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 | 4035 | const slice_mcv = try self.resolveInst(lhs); |
| 4046 | 4036 | const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) { |
| 4047 | 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 | 4039 | }; |
| 4050 | 4040 | defer if (slice_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 4051 | 4041 | |
| 4052 | const elem_ty = slice_ty.childType(); | |
| 4053 | const elem_size = elem_ty.abiSize(self.target.*); | |
| 4054 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 4055 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | |
| 4042 | const elem_ty = slice_ty.childType(mod); | |
| 4043 | const elem_size = elem_ty.abiSize(mod); | |
| 4044 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod); | |
| 4056 | 4045 | |
| 4057 | const index_ty = self.air.typeOf(rhs); | |
| 4046 | const index_ty = self.typeOf(rhs); | |
| 4058 | 4047 | const index_mcv = try self.resolveInst(rhs); |
| 4059 | 4048 | const index_mcv_lock: ?RegisterLock = switch (index_mcv) { |
| 4060 | 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 | 4066 | } |
| 4078 | 4067 | |
| 4079 | 4068 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4069 | const mod = self.bin_file.options.module.?; | |
| 4080 | 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; | |
| 4084 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | |
| 4073 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod); | |
| 4085 | 4074 | const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs); |
| 4086 | 4075 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 4087 | 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 | 4086 | } |
| 4098 | 4087 | |
| 4099 | 4088 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4089 | const mod = self.bin_file.options.module.?; | |
| 4100 | 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 | 4093 | const array = try self.resolveInst(bin_op.lhs); |
| 4104 | 4094 | const array_lock: ?RegisterLock = switch (array) { |
| 4105 | 4095 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -4107,10 +4097,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4107 | 4097 | }; |
| 4108 | 4098 | defer if (array_lock) |lock| self.register_manager.unlockReg(lock); |
| 4109 | 4099 | |
| 4110 | const elem_ty = array_ty.childType(); | |
| 4111 | const elem_abi_size = elem_ty.abiSize(self.target.*); | |
| 4100 | const elem_ty = array_ty.childType(mod); | |
| 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 | 4104 | const index = try self.resolveInst(bin_op.rhs); |
| 4115 | 4105 | const index_lock: ?RegisterLock = switch (index) { |
| 4116 | 4106 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -4125,7 +4115,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4125 | 4115 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 4126 | 4116 | switch (array) { |
| 4127 | 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 | 4119 | try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array); |
| 4130 | 4120 | try self.asmRegisterMemory( |
| 4131 | 4121 | .{ ._, .lea }, |
| ... | ... | @@ -4162,15 +4152,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4162 | 4152 | } |
| 4163 | 4153 | |
| 4164 | 4154 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4155 | const mod = self.bin_file.options.module.?; | |
| 4165 | 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 | 4159 | // this is identical to the `airPtrElemPtr` codegen expect here an |
| 4169 | 4160 | // additional `mov` is needed at the end to get the actual value |
| 4170 | 4161 | |
| 4171 | const elem_ty = ptr_ty.elemType2(); | |
| 4172 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | |
| 4173 | const index_ty = self.air.typeOf(bin_op.rhs); | |
| 4162 | const elem_ty = ptr_ty.elemType2(mod); | |
| 4163 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(mod)); | |
| 4164 | const index_ty = self.typeOf(bin_op.rhs); | |
| 4174 | 4165 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 4175 | 4166 | const index_lock = switch (index_mcv) { |
| 4176 | 4167 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -4207,10 +4198,11 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4207 | 4198 | } |
| 4208 | 4199 | |
| 4209 | 4200 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4201 | const mod = self.bin_file.options.module.?; | |
| 4210 | 4202 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4211 | 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 | 4206 | const ptr = try self.resolveInst(extra.lhs); |
| 4215 | 4207 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| 4216 | 4208 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -4218,9 +4210,9 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4218 | 4210 | }; |
| 4219 | 4211 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4220 | 4212 | |
| 4221 | const elem_ty = ptr_ty.elemType2(); | |
| 4222 | const elem_abi_size = elem_ty.abiSize(self.target.*); | |
| 4223 | const index_ty = self.air.typeOf(extra.rhs); | |
| 4213 | const elem_ty = ptr_ty.elemType2(mod); | |
| 4214 | const elem_abi_size = elem_ty.abiSize(mod); | |
| 4215 | const index_ty = self.typeOf(extra.rhs); | |
| 4224 | 4216 | const index = try self.resolveInst(extra.rhs); |
| 4225 | 4217 | const index_lock: ?RegisterLock = switch (index) { |
| 4226 | 4218 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -4239,11 +4231,12 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4239 | 4231 | } |
| 4240 | 4232 | |
| 4241 | 4233 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4234 | const mod = self.bin_file.options.module.?; | |
| 4242 | 4235 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4243 | const ptr_union_ty = self.air.typeOf(bin_op.lhs); | |
| 4244 | const union_ty = ptr_union_ty.childType(); | |
| 4245 | const tag_ty = self.air.typeOf(bin_op.rhs); | |
| 4246 | const layout = union_ty.unionGetLayout(self.target.*); | |
| 4236 | const ptr_union_ty = self.typeOf(bin_op.lhs); | |
| 4237 | const union_ty = ptr_union_ty.childType(mod); | |
| 4238 | const tag_ty = self.typeOf(bin_op.rhs); | |
| 4239 | const layout = union_ty.unionGetLayout(mod); | |
| 4247 | 4240 | |
| 4248 | 4241 | if (layout.tag_size == 0) { |
| 4249 | 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 | 4268 | break :blk MCValue{ .register = reg }; |
| 4276 | 4269 | } else ptr; |
| 4277 | 4270 | |
| 4278 | var ptr_tag_pl = ptr_union_ty.ptrInfo(); | |
| 4279 | ptr_tag_pl.data.pointee_type = tag_ty; | |
| 4280 | const ptr_tag_ty = Type.initPayload(&ptr_tag_pl.base); | |
| 4271 | const ptr_tag_ty = try mod.adjustPtrTypeChild(ptr_union_ty, tag_ty); | |
| 4281 | 4272 | try self.store(ptr_tag_ty, adjusted_ptr, tag); |
| 4282 | 4273 | |
| 4283 | 4274 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 4284 | 4275 | } |
| 4285 | 4276 | |
| 4286 | 4277 | fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4278 | const mod = self.bin_file.options.module.?; | |
| 4287 | 4279 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4288 | 4280 | |
| 4289 | const tag_ty = self.air.typeOfIndex(inst); | |
| 4290 | const union_ty = self.air.typeOf(ty_op.operand); | |
| 4291 | const layout = union_ty.unionGetLayout(self.target.*); | |
| 4281 | const tag_ty = self.typeOfIndex(inst); | |
| 4282 | const union_ty = self.typeOf(ty_op.operand); | |
| 4283 | const layout = union_ty.unionGetLayout(mod); | |
| 4292 | 4284 | |
| 4293 | 4285 | if (layout.tag_size == 0) { |
| 4294 | 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 | 4294 | }; |
| 4303 | 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 | 4298 | const dst_mcv: MCValue = blk: { |
| 4307 | 4299 | switch (operand) { |
| 4308 | 4300 | .load_frame => |frame_addr| { |
| ... | ... | @@ -4337,10 +4329,11 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4337 | 4329 | } |
| 4338 | 4330 | |
| 4339 | 4331 | fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4332 | const mod = self.bin_file.options.module.?; | |
| 4340 | 4333 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4341 | 4334 | const result = result: { |
| 4342 | const dst_ty = self.air.typeOfIndex(inst); | |
| 4343 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 4335 | const dst_ty = self.typeOfIndex(inst); | |
| 4336 | const src_ty = self.typeOf(ty_op.operand); | |
| 4344 | 4337 | |
| 4345 | 4338 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4346 | 4339 | const mat_src_mcv = switch (src_mcv) { |
| ... | ... | @@ -4358,7 +4351,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4358 | 4351 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 4359 | 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 | 4355 | if (self.hasFeature(.lzcnt)) { |
| 4363 | 4356 | if (src_bits <= 8) { |
| 4364 | 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 | 4398 | } |
| 4406 | 4399 | |
| 4407 | 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 | 4402 | if (math.isPowerOfTwo(src_bits)) { |
| 4410 | 4403 | const imm_reg = try self.copyToTmpRegister(dst_ty, .{ |
| 4411 | 4404 | .immediate = src_bits ^ (src_bits - 1), |
| ... | ... | @@ -4422,7 +4415,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4422 | 4415 | try self.genBinOpMir(.{ ._, .bsr }, Type.u16, dst_mcv, .{ .register = wide_reg }); |
| 4423 | 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 | 4419 | try self.asmCmovccRegisterRegister( |
| 4427 | 4420 | registerAlias(dst_reg, cmov_abi_size), |
| 4428 | 4421 | registerAlias(imm_reg, cmov_abi_size), |
| ... | ... | @@ -4449,7 +4442,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4449 | 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 | 4446 | try self.asmCmovccRegisterRegister( |
| 4454 | 4447 | registerAlias(imm_reg, cmov_abi_size), |
| 4455 | 4448 | registerAlias(dst_reg, cmov_abi_size), |
| ... | ... | @@ -4465,11 +4458,12 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4465 | 4458 | } |
| 4466 | 4459 | |
| 4467 | 4460 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 4461 | const mod = self.bin_file.options.module.?; | |
| 4468 | 4462 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4469 | 4463 | const result = result: { |
| 4470 | const dst_ty = self.air.typeOfIndex(inst); | |
| 4471 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 4472 | const src_bits = src_ty.bitSize(self.target.*); | |
| 4464 | const dst_ty = self.typeOfIndex(inst); | |
| 4465 | const src_ty = self.typeOf(ty_op.operand); | |
| 4466 | const src_bits = src_ty.bitSize(mod); | |
| 4473 | 4467 | |
| 4474 | 4468 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4475 | 4469 | const mat_src_mcv = switch (src_mcv) { |
| ... | ... | @@ -4548,7 +4542,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 4548 | 4542 | try self.genBinOpMir(.{ ._, .bsf }, Type.u16, dst_mcv, .{ .register = wide_reg }); |
| 4549 | 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 | 4546 | try self.asmCmovccRegisterRegister( |
| 4553 | 4547 | registerAlias(dst_reg, cmov_abi_size), |
| 4554 | 4548 | registerAlias(width_reg, cmov_abi_size), |
| ... | ... | @@ -4560,10 +4554,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 4560 | 4554 | } |
| 4561 | 4555 | |
| 4562 | 4556 | fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 4557 | const mod = self.bin_file.options.module.?; | |
| 4563 | 4558 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4564 | 4559 | const result: MCValue = result: { |
| 4565 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 4566 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | |
| 4560 | const src_ty = self.typeOf(ty_op.operand); | |
| 4561 | const src_abi_size = @intCast(u32, src_ty.abiSize(mod)); | |
| 4567 | 4562 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4568 | 4563 | |
| 4569 | 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 | 4724 | } |
| 4730 | 4725 | |
| 4731 | 4726 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 4727 | const mod = self.bin_file.options.module.?; | |
| 4732 | 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 | 4731 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4736 | 4732 | |
| 4737 | 4733 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true); |
| 4738 | 4734 | switch (self.regExtraBits(src_ty)) { |
| 4739 | 4735 | 0 => {}, |
| 4740 | 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 | 4738 | src_ty, |
| 4743 | 4739 | dst_mcv, |
| 4744 | 4740 | .{ .immediate = extra }, |
| ... | ... | @@ -4749,10 +4745,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 4749 | 4745 | } |
| 4750 | 4746 | |
| 4751 | 4747 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 4748 | const mod = self.bin_file.options.module.?; | |
| 4752 | 4749 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4753 | 4750 | |
| 4754 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 4755 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | |
| 4751 | const src_ty = self.typeOf(ty_op.operand); | |
| 4752 | const src_abi_size = @intCast(u32, src_ty.abiSize(mod)); | |
| 4756 | 4753 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4757 | 4754 | |
| 4758 | 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 | 4844 | switch (self.regExtraBits(src_ty)) { |
| 4848 | 4845 | 0 => {}, |
| 4849 | 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 | 4848 | src_ty, |
| 4852 | 4849 | dst_mcv, |
| 4853 | 4850 | .{ .immediate = extra }, |
| ... | ... | @@ -4858,17 +4855,18 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 4858 | 4855 | } |
| 4859 | 4856 | |
| 4860 | 4857 | fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4858 | const mod = self.bin_file.options.module.?; | |
| 4861 | 4859 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4862 | 4860 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4863 | const ty = self.air.typeOf(un_op); | |
| 4864 | const abi_size: u32 = switch (ty.abiSize(self.target.*)) { | |
| 4861 | const ty = self.typeOf(un_op); | |
| 4862 | const abi_size: u32 = switch (ty.abiSize(mod)) { | |
| 4865 | 4863 | 1...16 => 16, |
| 4866 | 4864 | 17...32 => 32, |
| 4867 | 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 | 4871 | const src_mcv = try self.resolveInst(un_op); |
| 4874 | 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 | 4882 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 4885 | 4883 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 4886 | 4884 | |
| 4887 | var arena = std.heap.ArenaAllocator.init(self.gpa); | |
| 4888 | defer arena.deinit(); | |
| 4889 | ||
| 4890 | const ExpectedContents = struct { | |
| 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()); | |
| 4885 | const vec_ty = try mod.vectorType(.{ | |
| 4886 | .len = @divExact(abi_size * 8, scalar_bits), | |
| 4887 | .child = (try mod.intType(.signed, scalar_bits)).ip_index, | |
| 4888 | }); | |
| 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 | 4890 | const sign_val = switch (tag) { |
| 4921 | .neg => try vec_ty.minInt(stack.get(), self.target.*), | |
| 4922 | .fabs => try vec_ty.maxInt(stack.get(), self.target.*), | |
| 4891 | .neg => try vec_ty.minInt(mod, vec_ty), | |
| 4892 | .fabs => try vec_ty.maxInt(mod, vec_ty), | |
| 4923 | 4893 | else => unreachable, |
| 4924 | 4894 | }; |
| 4925 | 4895 | |
| ... | ... | @@ -4993,7 +4963,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4993 | 4963 | |
| 4994 | 4964 | fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void { |
| 4995 | 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 | 4968 | const src_mcv = try self.resolveInst(un_op); |
| 4999 | 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 | 4978 | } |
| 5009 | 4979 | |
| 5010 | 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 | 4982 | if (!self.hasFeature(.sse4_1)) |
| 5012 | 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 | 4986 | .Float => switch (ty.floatBits(self.target.*)) { |
| 5016 | 4987 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, |
| 5017 | 4988 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round }, |
| 5018 | 4989 | 16, 80, 128 => null, |
| 5019 | 4990 | else => unreachable, |
| 5020 | 4991 | }, |
| 5021 | .Vector => switch (ty.childType().zigTypeTag()) { | |
| 5022 | .Float => switch (ty.childType().floatBits(self.target.*)) { | |
| 5023 | 32 => switch (ty.vectorLen()) { | |
| 4992 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { | |
| 4993 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { | |
| 4994 | 32 => switch (ty.vectorLen(mod)) { | |
| 5024 | 4995 | 1 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, |
| 5025 | 4996 | 2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else .{ ._ps, .round }, |
| 5026 | 4997 | 5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else null, |
| 5027 | 4998 | else => null, |
| 5028 | 4999 | }, |
| 5029 | 64 => switch (ty.vectorLen()) { | |
| 5000 | 64 => switch (ty.vectorLen(mod)) { | |
| 5030 | 5001 | 1 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round }, |
| 5031 | 5002 | 2 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else .{ ._pd, .round }, |
| 5032 | 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 | 5012 | })) |tag| tag else return self.fail("TODO implement genRound for {}", .{ |
| 5042 | 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 | 5016 | const dst_alias = registerAlias(dst_reg, abi_size); |
| 5046 | 5017 | switch (mir_tag[0]) { |
| 5047 | 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 | 5049 | } |
| 5079 | 5050 | |
| 5080 | 5051 | fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5052 | const mod = self.bin_file.options.module.?; | |
| 5081 | 5053 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5082 | const ty = self.air.typeOf(un_op); | |
| 5083 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | |
| 5054 | const ty = self.typeOf(un_op); | |
| 5055 | const abi_size = @intCast(u32, ty.abiSize(mod)); | |
| 5084 | 5056 | |
| 5085 | 5057 | const src_mcv = try self.resolveInst(un_op); |
| 5086 | 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 | 5064 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5093 | 5065 | |
| 5094 | 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 | 5068 | .Float => switch (ty.floatBits(self.target.*)) { |
| 5097 | 5069 | 16 => if (self.hasFeature(.f16c)) { |
| 5098 | 5070 | const mat_src_reg = if (src_mcv.isRegister()) |
| ... | ... | @@ -5114,9 +5086,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5114 | 5086 | 80, 128 => null, |
| 5115 | 5087 | else => unreachable, |
| 5116 | 5088 | }, |
| 5117 | .Vector => switch (ty.childType().zigTypeTag()) { | |
| 5118 | .Float => switch (ty.childType().floatBits(self.target.*)) { | |
| 5119 | 16 => if (self.hasFeature(.f16c)) switch (ty.vectorLen()) { | |
| 5089 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { | |
| 5090 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { | |
| 5091 | 16 => if (self.hasFeature(.f16c)) switch (ty.vectorLen(mod)) { | |
| 5120 | 5092 | 1 => { |
| 5121 | 5093 | try self.asmRegisterRegister( |
| 5122 | 5094 | .{ .v_ps, .cvtph2 }, |
| ... | ... | @@ -5167,13 +5139,13 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5167 | 5139 | }, |
| 5168 | 5140 | else => null, |
| 5169 | 5141 | } else null, |
| 5170 | 32 => switch (ty.vectorLen()) { | |
| 5142 | 32 => switch (ty.vectorLen(mod)) { | |
| 5171 | 5143 | 1 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt }, |
| 5172 | 5144 | 2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else .{ ._ps, .sqrt }, |
| 5173 | 5145 | 5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else null, |
| 5174 | 5146 | else => null, |
| 5175 | 5147 | }, |
| 5176 | 64 => switch (ty.vectorLen()) { | |
| 5148 | 64 => switch (ty.vectorLen(mod)) { | |
| 5177 | 5149 | 1 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt }, |
| 5178 | 5150 | 2 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else .{ ._pd, .sqrt }, |
| 5179 | 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 | 5158 | }, |
| 5187 | 5159 | else => unreachable, |
| 5188 | 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 | 5163 | switch (mir_tag[0]) { |
| 5192 | 5164 | .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| ... | ... | @@ -5274,10 +5246,11 @@ fn reuseOperandAdvanced( |
| 5274 | 5246 | } |
| 5275 | 5247 | |
| 5276 | 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 | 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 | 5254 | const limb_abi_size: u32 = @min(val_abi_size, 8); |
| 5282 | 5255 | const limb_abi_bits = limb_abi_size * 8; |
| 5283 | 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 | 5320 | } |
| 5348 | 5321 | |
| 5349 | 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 | 5325 | switch (ptr_mcv) { |
| 5352 | 5326 | .none, |
| 5353 | 5327 | .unreach, |
| ... | ... | @@ -5382,20 +5356,21 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 5382 | 5356 | } |
| 5383 | 5357 | |
| 5384 | 5358 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5359 | const mod = self.bin_file.options.module.?; | |
| 5385 | 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 | 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 | 5365 | try self.spillRegisters(&.{ .rdi, .rsi, .rcx }); |
| 5391 | 5366 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx }); |
| 5392 | 5367 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 5393 | 5368 | |
| 5394 | const ptr_ty = self.air.typeOf(ty_op.operand); | |
| 5395 | const elem_size = elem_ty.abiSize(self.target.*); | |
| 5369 | const ptr_ty = self.typeOf(ty_op.operand); | |
| 5370 | const elem_size = elem_ty.abiSize(mod); | |
| 5396 | 5371 | |
| 5397 | const elem_rc = regClassForType(elem_ty); | |
| 5398 | const ptr_rc = regClassForType(ptr_ty); | |
| 5372 | const elem_rc = regClassForType(elem_ty, mod); | |
| 5373 | const ptr_rc = regClassForType(ptr_ty, mod); | |
| 5399 | 5374 | |
| 5400 | 5375 | const ptr_mcv = try self.resolveInst(ty_op.operand); |
| 5401 | 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 | 5380 | else |
| 5406 | 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 | 5384 | try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv); |
| 5410 | 5385 | } else { |
| 5411 | 5386 | try self.load(dst_mcv, ptr_ty, ptr_mcv); |
| ... | ... | @@ -5416,13 +5391,14 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5416 | 5391 | } |
| 5417 | 5392 | |
| 5418 | 5393 | fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 5419 | const ptr_info = ptr_ty.ptrInfo().data; | |
| 5420 | const src_ty = ptr_ty.childType(); | |
| 5394 | const mod = self.bin_file.options.module.?; | |
| 5395 | const ptr_info = ptr_ty.ptrInfo(mod); | |
| 5396 | const src_ty = ptr_ty.childType(mod); | |
| 5421 | 5397 | |
| 5422 | 5398 | const limb_abi_size: u16 = @min(ptr_info.host_size, 8); |
| 5423 | 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 | 5402 | const src_byte_off = @intCast(i32, ptr_info.bit_offset / limb_abi_bits * limb_abi_size); |
| 5427 | 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 | 5465 | } |
| 5490 | 5466 | |
| 5491 | 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 | 5470 | switch (ptr_mcv) { |
| 5494 | 5471 | .none, |
| 5495 | 5472 | .unreach, |
| ... | ... | @@ -5524,6 +5501,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 5524 | 5501 | } |
| 5525 | 5502 | |
| 5526 | 5503 | fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 5504 | const mod = self.bin_file.options.module.?; | |
| 5527 | 5505 | if (safety) { |
| 5528 | 5506 | // TODO if the value is undef, write 0xaa bytes to dest |
| 5529 | 5507 | } else { |
| ... | ... | @@ -5531,9 +5509,9 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 5531 | 5509 | } |
| 5532 | 5510 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5533 | 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 | 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 | 5515 | try self.packedStore(ptr_ty, ptr_mcv, src_mcv); |
| 5538 | 5516 | } else { |
| 5539 | 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 | 5533 | } |
| 5556 | 5534 | |
| 5557 | 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); | |
| 5559 | const ptr_container_ty = self.air.typeOf(operand); | |
| 5560 | const container_ty = ptr_container_ty.childType(); | |
| 5561 | const field_offset = @intCast(i32, switch (container_ty.containerLayout()) { | |
| 5562 | .Auto, .Extern => container_ty.structFieldOffset(index, self.target.*), | |
| 5563 | .Packed => if (container_ty.zigTypeTag() == .Struct and | |
| 5564 | ptr_field_ty.ptrInfo().data.host_size == 0) | |
| 5565 | container_ty.packedStructFieldByteOffset(index, self.target.*) | |
| 5536 | const mod = self.bin_file.options.module.?; | |
| 5537 | const ptr_field_ty = self.typeOfIndex(inst); | |
| 5538 | const ptr_container_ty = self.typeOf(operand); | |
| 5539 | const container_ty = ptr_container_ty.childType(mod); | |
| 5540 | const field_offset = @intCast(i32, switch (container_ty.containerLayout(mod)) { | |
| 5541 | .Auto, .Extern => container_ty.structFieldOffset(index, mod), | |
| 5542 | .Packed => if (container_ty.zigTypeTag(mod) == .Struct and | |
| 5543 | ptr_field_ty.ptrInfo(mod).host_size == 0) | |
| 5544 | container_ty.packedStructFieldByteOffset(index, mod) | |
| 5566 | 5545 | else |
| 5567 | 5546 | 0, |
| 5568 | 5547 | }); |
| ... | ... | @@ -5577,24 +5556,25 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 |
| 5577 | 5556 | } |
| 5578 | 5557 | |
| 5579 | 5558 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5559 | const mod = self.bin_file.options.module.?; | |
| 5580 | 5560 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5581 | 5561 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 5582 | 5562 | const result: MCValue = result: { |
| 5583 | 5563 | const operand = extra.struct_operand; |
| 5584 | 5564 | const index = extra.field_index; |
| 5585 | 5565 | |
| 5586 | const container_ty = self.air.typeOf(operand); | |
| 5587 | const container_rc = regClassForType(container_ty); | |
| 5588 | const field_ty = container_ty.structFieldType(index); | |
| 5589 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; | |
| 5590 | const field_rc = regClassForType(field_ty); | |
| 5566 | const container_ty = self.typeOf(operand); | |
| 5567 | const container_rc = regClassForType(container_ty, mod); | |
| 5568 | const field_ty = container_ty.structFieldType(index, mod); | |
| 5569 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none; | |
| 5570 | const field_rc = regClassForType(field_ty, mod); | |
| 5591 | 5571 | const field_is_gp = field_rc.supersetOf(gp); |
| 5592 | 5572 | |
| 5593 | 5573 | const src_mcv = try self.resolveInst(operand); |
| 5594 | const field_off = switch (container_ty.containerLayout()) { | |
| 5595 | .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8), | |
| 5596 | .Packed => if (container_ty.castTag(.@"struct")) |struct_obj| | |
| 5597 | struct_obj.data.packedFieldBitOffset(self.target.*, index) | |
| 5574 | const field_off = switch (container_ty.containerLayout(mod)) { | |
| 5575 | .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, mod) * 8), | |
| 5576 | .Packed => if (mod.typeToStruct(container_ty)) |struct_obj| | |
| 5577 | struct_obj.packedFieldBitOffset(mod, index) | |
| 5598 | 5578 | else |
| 5599 | 5579 | 0, |
| 5600 | 5580 | }; |
| ... | ... | @@ -5611,7 +5591,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5611 | 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 | 5595 | const limb_abi_size: u32 = @min(field_abi_size, 8); |
| 5616 | 5596 | const limb_abi_bits = limb_abi_size * 8; |
| 5617 | 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 | 5713 | } |
| 5734 | 5714 | |
| 5735 | 5715 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5716 | const mod = self.bin_file.options.module.?; | |
| 5736 | 5717 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5737 | 5718 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 5738 | 5719 | |
| 5739 | const inst_ty = self.air.typeOfIndex(inst); | |
| 5740 | const parent_ty = inst_ty.childType(); | |
| 5741 | const field_offset = @intCast(i32, parent_ty.structFieldOffset(extra.field_index, self.target.*)); | |
| 5720 | const inst_ty = self.typeOfIndex(inst); | |
| 5721 | const parent_ty = inst_ty.childType(mod); | |
| 5722 | const field_offset = @intCast(i32, parent_ty.structFieldOffset(extra.field_index, mod)); | |
| 5742 | 5723 | |
| 5743 | 5724 | const src_mcv = try self.resolveInst(extra.field_ptr); |
| 5744 | 5725 | const dst_mcv = if (src_mcv.isRegisterOffset() and |
| ... | ... | @@ -5751,9 +5732,10 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5751 | 5732 | } |
| 5752 | 5733 | |
| 5753 | 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 | 5737 | const src_mcv = try self.resolveInst(src_air); |
| 5756 | if (src_ty.zigTypeTag() == .Vector) { | |
| 5738 | if (src_ty.zigTypeTag(mod) == .Vector) { | |
| 5757 | 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 | 5768 | |
| 5787 | 5769 | switch (tag) { |
| 5788 | 5770 | .not => { |
| 5789 | const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(self.target.*), 8)); | |
| 5790 | const int_info = if (src_ty.tag() == .bool) | |
| 5771 | const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(mod), 8)); | |
| 5772 | const int_info = if (src_ty.ip_index == .bool_type) | |
| 5791 | 5773 | std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } |
| 5792 | 5774 | else |
| 5793 | src_ty.intInfo(self.target.*); | |
| 5775 | src_ty.intInfo(mod); | |
| 5794 | 5776 | var byte_off: i32 = 0; |
| 5795 | 5777 | while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) { |
| 5796 | var limb_pl = Type.Payload.Bits{ | |
| 5797 | .base = .{ .tag = switch (int_info.signedness) { | |
| 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); | |
| 5778 | const limb_bits = @intCast(u16, @min(int_info.bits - byte_off * 8, limb_abi_size * 8)); | |
| 5779 | const limb_ty = try mod.intType(int_info.signedness, limb_bits); | |
| 5804 | 5780 | const limb_mcv = switch (byte_off) { |
| 5805 | 5781 | 0 => dst_mcv, |
| 5806 | 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) { | |
| 5810 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data); | |
| 5785 | if (int_info.signedness == .unsigned and self.regExtraBits(limb_ty) > 0) { | |
| 5786 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_bits); | |
| 5811 | 5787 | try self.genBinOpMir(.{ ._, .xor }, limb_ty, limb_mcv, .{ .immediate = mask }); |
| 5812 | 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 | 5795 | } |
| 5820 | 5796 | |
| 5821 | 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 | 5800 | if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ |
| 5824 | 5801 | mir_tag, |
| 5825 | 5802 | dst_ty.fmt(self.bin_file.options.module.?), |
| ... | ... | @@ -5866,6 +5843,7 @@ fn genShiftBinOpMir( |
| 5866 | 5843 | lhs_mcv: MCValue, |
| 5867 | 5844 | shift_mcv: MCValue, |
| 5868 | 5845 | ) !void { |
| 5846 | const mod = self.bin_file.options.module.?; | |
| 5869 | 5847 | const rhs_mcv: MCValue = rhs: { |
| 5870 | 5848 | switch (shift_mcv) { |
| 5871 | 5849 | .immediate => |imm| switch (imm) { |
| ... | ... | @@ -5880,7 +5858,7 @@ fn genShiftBinOpMir( |
| 5880 | 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 | 5862 | if (abi_size <= 8) { |
| 5885 | 5863 | switch (lhs_mcv) { |
| 5886 | 5864 | .register => |lhs_reg| switch (rhs_mcv) { |
| ... | ... | @@ -6099,13 +6077,14 @@ fn genShiftBinOp( |
| 6099 | 6077 | lhs_ty: Type, |
| 6100 | 6078 | rhs_ty: Type, |
| 6101 | 6079 | ) !MCValue { |
| 6102 | if (lhs_ty.zigTypeTag() == .Vector) { | |
| 6080 | const mod = self.bin_file.options.module.?; | |
| 6081 | if (lhs_ty.zigTypeTag(mod) == .Vector) { | |
| 6103 | 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 | 6088 | if (lhs_abi_size > 16) { |
| 6110 | 6089 | return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 6111 | 6090 | } |
| ... | ... | @@ -6136,7 +6115,7 @@ fn genShiftBinOp( |
| 6136 | 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 | 6119 | try self.genShiftBinOpMir(switch (air_tag) { |
| 6141 | 6120 | .shl, .shl_exact => switch (signedness) { |
| 6142 | 6121 | .signed => .{ ._l, .sa }, |
| ... | ... | @@ -6163,11 +6142,12 @@ fn genMulDivBinOp( |
| 6163 | 6142 | lhs: MCValue, |
| 6164 | 6143 | rhs: MCValue, |
| 6165 | 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 | 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.*)); | |
| 6170 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | |
| 6149 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); | |
| 6150 | const src_abi_size = @intCast(u32, src_ty.abiSize(mod)); | |
| 6171 | 6151 | if (switch (tag) { |
| 6172 | 6152 | else => unreachable, |
| 6173 | 6153 | .mul, .mulwrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, |
| ... | ... | @@ -6184,7 +6164,7 @@ fn genMulDivBinOp( |
| 6184 | 6164 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 6185 | 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 | 6168 | switch (tag) { |
| 6189 | 6169 | .mul, |
| 6190 | 6170 | .mulwrap, |
| ... | ... | @@ -6338,13 +6318,14 @@ fn genBinOp( |
| 6338 | 6318 | lhs_air: Air.Inst.Ref, |
| 6339 | 6319 | rhs_air: Air.Inst.Ref, |
| 6340 | 6320 | ) !MCValue { |
| 6341 | const lhs_ty = self.air.typeOf(lhs_air); | |
| 6342 | const rhs_ty = self.air.typeOf(rhs_air); | |
| 6343 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); | |
| 6321 | const mod = self.bin_file.options.module.?; | |
| 6322 | const lhs_ty = self.typeOf(lhs_air); | |
| 6323 | const rhs_ty = self.typeOf(rhs_air); | |
| 6324 | const abi_size = @intCast(u32, lhs_ty.abiSize(mod)); | |
| 6344 | 6325 | |
| 6345 | 6326 | const maybe_mask_reg = switch (air_tag) { |
| 6346 | 6327 | else => null, |
| 6347 | .max, .min => if (lhs_ty.scalarType().isRuntimeFloat()) registerAlias( | |
| 6328 | .max, .min => if (lhs_ty.scalarType(mod).isRuntimeFloat()) registerAlias( | |
| 6348 | 6329 | if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: { |
| 6349 | 6330 | try self.register_manager.getReg(.xmm0, null); |
| 6350 | 6331 | break :mask .xmm0; |
| ... | ... | @@ -6384,7 +6365,7 @@ fn genBinOp( |
| 6384 | 6365 | |
| 6385 | 6366 | else => false, |
| 6386 | 6367 | }; |
| 6387 | const vec_op = switch (lhs_ty.zigTypeTag()) { | |
| 6368 | const vec_op = switch (lhs_ty.zigTypeTag(mod)) { | |
| 6388 | 6369 | else => false, |
| 6389 | 6370 | .Float, .Vector => true, |
| 6390 | 6371 | }; |
| ... | ... | @@ -6456,7 +6437,7 @@ fn genBinOp( |
| 6456 | 6437 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 6457 | 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 | 6441 | try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size }); |
| 6461 | 6442 | try self.genBinOpMir( |
| 6462 | 6443 | switch (air_tag) { |
| ... | ... | @@ -6506,7 +6487,7 @@ fn genBinOp( |
| 6506 | 6487 | |
| 6507 | 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 | 6491 | const cc: Condition = switch (int_info.signedness) { |
| 6511 | 6492 | .unsigned => switch (air_tag) { |
| 6512 | 6493 | .min => .a, |
| ... | ... | @@ -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 | 6505 | const tmp_reg = switch (dst_mcv) { |
| 6525 | 6506 | .register => |reg| reg, |
| 6526 | 6507 | else => try self.copyToTmpRegister(lhs_ty, dst_mcv), |
| ... | ... | @@ -6581,7 +6562,7 @@ fn genBinOp( |
| 6581 | 6562 | } |
| 6582 | 6563 | |
| 6583 | 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 | 6566 | else => unreachable, |
| 6586 | 6567 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 6587 | 6568 | 16 => if (self.hasFeature(.f16c)) { |
| ... | ... | @@ -6657,10 +6638,10 @@ fn genBinOp( |
| 6657 | 6638 | 80, 128 => null, |
| 6658 | 6639 | else => unreachable, |
| 6659 | 6640 | }, |
| 6660 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | |
| 6641 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { | |
| 6661 | 6642 | else => null, |
| 6662 | .Int => switch (lhs_ty.childType().intInfo(self.target.*).bits) { | |
| 6663 | 8 => switch (lhs_ty.vectorLen()) { | |
| 6643 | .Int => switch (lhs_ty.childType(mod).intInfo(mod).bits) { | |
| 6644 | 8 => switch (lhs_ty.vectorLen(mod)) { | |
| 6664 | 6645 | 1...16 => switch (air_tag) { |
| 6665 | 6646 | .add, |
| 6666 | 6647 | .addwrap, |
| ... | ... | @@ -6671,7 +6652,7 @@ fn genBinOp( |
| 6671 | 6652 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, |
| 6672 | 6653 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, |
| 6673 | 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 | 6656 | .signed => if (self.hasFeature(.avx)) |
| 6676 | 6657 | .{ .vp_b, .mins } |
| 6677 | 6658 | else if (self.hasFeature(.sse4_1)) |
| ... | ... | @@ -6685,7 +6666,7 @@ fn genBinOp( |
| 6685 | 6666 | else |
| 6686 | 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 | 6670 | .signed => if (self.hasFeature(.avx)) |
| 6690 | 6671 | .{ .vp_b, .maxs } |
| 6691 | 6672 | else if (self.hasFeature(.sse4_1)) |
| ... | ... | @@ -6711,11 +6692,11 @@ fn genBinOp( |
| 6711 | 6692 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, |
| 6712 | 6693 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, |
| 6713 | 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 | 6696 | .signed => if (self.hasFeature(.avx2)) .{ .vp_b, .mins } else null, |
| 6716 | 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 | 6700 | .signed => if (self.hasFeature(.avx2)) .{ .vp_b, .maxs } else null, |
| 6720 | 6701 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_b, .maxu } else null, |
| 6721 | 6702 | }, |
| ... | ... | @@ -6723,7 +6704,7 @@ fn genBinOp( |
| 6723 | 6704 | }, |
| 6724 | 6705 | else => null, |
| 6725 | 6706 | }, |
| 6726 | 16 => switch (lhs_ty.vectorLen()) { | |
| 6707 | 16 => switch (lhs_ty.vectorLen(mod)) { | |
| 6727 | 6708 | 1...8 => switch (air_tag) { |
| 6728 | 6709 | .add, |
| 6729 | 6710 | .addwrap, |
| ... | ... | @@ -6737,7 +6718,7 @@ fn genBinOp( |
| 6737 | 6718 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, |
| 6738 | 6719 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, |
| 6739 | 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 | 6722 | .signed => if (self.hasFeature(.avx)) |
| 6742 | 6723 | .{ .vp_w, .mins } |
| 6743 | 6724 | else |
| ... | ... | @@ -6747,7 +6728,7 @@ fn genBinOp( |
| 6747 | 6728 | else |
| 6748 | 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 | 6732 | .signed => if (self.hasFeature(.avx)) |
| 6752 | 6733 | .{ .vp_w, .maxs } |
| 6753 | 6734 | else |
| ... | ... | @@ -6772,11 +6753,11 @@ fn genBinOp( |
| 6772 | 6753 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, |
| 6773 | 6754 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, |
| 6774 | 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 | 6757 | .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .mins } else null, |
| 6777 | 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 | 6761 | .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .maxs } else null, |
| 6781 | 6762 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_w, .maxu } else null, |
| 6782 | 6763 | }, |
| ... | ... | @@ -6784,7 +6765,7 @@ fn genBinOp( |
| 6784 | 6765 | }, |
| 6785 | 6766 | else => null, |
| 6786 | 6767 | }, |
| 6787 | 32 => switch (lhs_ty.vectorLen()) { | |
| 6768 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 6788 | 6769 | 1...4 => switch (air_tag) { |
| 6789 | 6770 | .add, |
| 6790 | 6771 | .addwrap, |
| ... | ... | @@ -6803,7 +6784,7 @@ fn genBinOp( |
| 6803 | 6784 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, |
| 6804 | 6785 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, |
| 6805 | 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 | 6788 | .signed => if (self.hasFeature(.avx)) |
| 6808 | 6789 | .{ .vp_d, .mins } |
| 6809 | 6790 | else if (self.hasFeature(.sse4_1)) |
| ... | ... | @@ -6817,7 +6798,7 @@ fn genBinOp( |
| 6817 | 6798 | else |
| 6818 | 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 | 6802 | .signed => if (self.hasFeature(.avx)) |
| 6822 | 6803 | .{ .vp_d, .maxs } |
| 6823 | 6804 | else if (self.hasFeature(.sse4_1)) |
| ... | ... | @@ -6846,11 +6827,11 @@ fn genBinOp( |
| 6846 | 6827 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, |
| 6847 | 6828 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, |
| 6848 | 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 | 6831 | .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .mins } else null, |
| 6851 | 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 | 6835 | .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .maxs } else null, |
| 6855 | 6836 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_d, .maxu } else null, |
| 6856 | 6837 | }, |
| ... | ... | @@ -6858,7 +6839,7 @@ fn genBinOp( |
| 6858 | 6839 | }, |
| 6859 | 6840 | else => null, |
| 6860 | 6841 | }, |
| 6861 | 64 => switch (lhs_ty.vectorLen()) { | |
| 6842 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 6862 | 6843 | 1...2 => switch (air_tag) { |
| 6863 | 6844 | .add, |
| 6864 | 6845 | .addwrap, |
| ... | ... | @@ -6887,8 +6868,8 @@ fn genBinOp( |
| 6887 | 6868 | }, |
| 6888 | 6869 | else => null, |
| 6889 | 6870 | }, |
| 6890 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | |
| 6891 | 16 => if (self.hasFeature(.f16c)) switch (lhs_ty.vectorLen()) { | |
| 6871 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { | |
| 6872 | 16 => if (self.hasFeature(.f16c)) switch (lhs_ty.vectorLen(mod)) { | |
| 6892 | 6873 | 1 => { |
| 6893 | 6874 | const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128(); |
| 6894 | 6875 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| ... | ... | @@ -7063,7 +7044,7 @@ fn genBinOp( |
| 7063 | 7044 | }, |
| 7064 | 7045 | else => null, |
| 7065 | 7046 | } else null, |
| 7066 | 32 => switch (lhs_ty.vectorLen()) { | |
| 7047 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 7067 | 7048 | 1 => switch (air_tag) { |
| 7068 | 7049 | .add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add }, |
| 7069 | 7050 | .sub => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub }, |
| ... | ... | @@ -7101,7 +7082,7 @@ fn genBinOp( |
| 7101 | 7082 | } else null, |
| 7102 | 7083 | else => null, |
| 7103 | 7084 | }, |
| 7104 | 64 => switch (lhs_ty.vectorLen()) { | |
| 7085 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 7105 | 7086 | 1 => switch (air_tag) { |
| 7106 | 7087 | .add => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add }, |
| 7107 | 7088 | .sub => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub }, |
| ... | ... | @@ -7206,21 +7187,21 @@ fn genBinOp( |
| 7206 | 7187 | const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size); |
| 7207 | 7188 | |
| 7208 | 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 | 7191 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7211 | 7192 | 32 => .{ .v_ss, .cmp }, |
| 7212 | 7193 | 64 => .{ .v_sd, .cmp }, |
| 7213 | 7194 | 16, 80, 128 => null, |
| 7214 | 7195 | else => unreachable, |
| 7215 | 7196 | }, |
| 7216 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | |
| 7217 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | |
| 7218 | 32 => switch (lhs_ty.vectorLen()) { | |
| 7197 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { | |
| 7198 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { | |
| 7199 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 7219 | 7200 | 1 => .{ .v_ss, .cmp }, |
| 7220 | 7201 | 2...8 => .{ .v_ps, .cmp }, |
| 7221 | 7202 | else => null, |
| 7222 | 7203 | }, |
| 7223 | 64 => switch (lhs_ty.vectorLen()) { | |
| 7204 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 7224 | 7205 | 1 => .{ .v_sd, .cmp }, |
| 7225 | 7206 | 2...4 => .{ .v_pd, .cmp }, |
| 7226 | 7207 | else => null, |
| ... | ... | @@ -7240,20 +7221,20 @@ fn genBinOp( |
| 7240 | 7221 | Immediate.u(3), // unord |
| 7241 | 7222 | ); |
| 7242 | 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 | 7225 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7245 | 7226 | 32 => .{ .v_ps, .blendv }, |
| 7246 | 7227 | 64 => .{ .v_pd, .blendv }, |
| 7247 | 7228 | 16, 80, 128 => null, |
| 7248 | 7229 | else => unreachable, |
| 7249 | 7230 | }, |
| 7250 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | |
| 7251 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | |
| 7252 | 32 => switch (lhs_ty.vectorLen()) { | |
| 7231 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { | |
| 7232 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { | |
| 7233 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 7253 | 7234 | 1...8 => .{ .v_ps, .blendv }, |
| 7254 | 7235 | else => null, |
| 7255 | 7236 | }, |
| 7256 | 64 => switch (lhs_ty.vectorLen()) { | |
| 7237 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 7257 | 7238 | 1...4 => .{ .v_pd, .blendv }, |
| 7258 | 7239 | else => null, |
| 7259 | 7240 | }, |
| ... | ... | @@ -7274,21 +7255,21 @@ fn genBinOp( |
| 7274 | 7255 | } else { |
| 7275 | 7256 | const has_blend = self.hasFeature(.sse4_1); |
| 7276 | 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 | 7259 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7279 | 7260 | 32 => .{ ._ss, .cmp }, |
| 7280 | 7261 | 64 => .{ ._sd, .cmp }, |
| 7281 | 7262 | 16, 80, 128 => null, |
| 7282 | 7263 | else => unreachable, |
| 7283 | 7264 | }, |
| 7284 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | |
| 7285 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | |
| 7286 | 32 => switch (lhs_ty.vectorLen()) { | |
| 7265 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { | |
| 7266 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { | |
| 7267 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 7287 | 7268 | 1 => .{ ._ss, .cmp }, |
| 7288 | 7269 | 2...4 => .{ ._ps, .cmp }, |
| 7289 | 7270 | else => null, |
| 7290 | 7271 | }, |
| 7291 | 64 => switch (lhs_ty.vectorLen()) { | |
| 7272 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 7292 | 7273 | 1 => .{ ._sd, .cmp }, |
| 7293 | 7274 | 2 => .{ ._pd, .cmp }, |
| 7294 | 7275 | else => null, |
| ... | ... | @@ -7307,20 +7288,20 @@ fn genBinOp( |
| 7307 | 7288 | Immediate.u(if (has_blend) 3 else 7), // unord, ord |
| 7308 | 7289 | ); |
| 7309 | 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 | 7292 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7312 | 7293 | 32 => .{ ._ps, .blendv }, |
| 7313 | 7294 | 64 => .{ ._pd, .blendv }, |
| 7314 | 7295 | 16, 80, 128 => null, |
| 7315 | 7296 | else => unreachable, |
| 7316 | 7297 | }, |
| 7317 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | |
| 7318 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | |
| 7319 | 32 => switch (lhs_ty.vectorLen()) { | |
| 7298 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { | |
| 7299 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { | |
| 7300 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 7320 | 7301 | 1...4 => .{ ._ps, .blendv }, |
| 7321 | 7302 | else => null, |
| 7322 | 7303 | }, |
| 7323 | 64 => switch (lhs_ty.vectorLen()) { | |
| 7304 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 7324 | 7305 | 1...2 => .{ ._pd, .blendv }, |
| 7325 | 7306 | else => null, |
| 7326 | 7307 | }, |
| ... | ... | @@ -7338,20 +7319,20 @@ fn genBinOp( |
| 7338 | 7319 | mask_reg, |
| 7339 | 7320 | ) else { |
| 7340 | 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 | 7323 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7343 | 7324 | 32 => .{ ._ps, .@"and" }, |
| 7344 | 7325 | 64 => .{ ._pd, .@"and" }, |
| 7345 | 7326 | 16, 80, 128 => null, |
| 7346 | 7327 | else => unreachable, |
| 7347 | 7328 | }, |
| 7348 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | |
| 7349 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | |
| 7350 | 32 => switch (lhs_ty.vectorLen()) { | |
| 7329 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { | |
| 7330 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { | |
| 7331 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 7351 | 7332 | 1...4 => .{ ._ps, .@"and" }, |
| 7352 | 7333 | else => null, |
| 7353 | 7334 | }, |
| 7354 | 64 => switch (lhs_ty.vectorLen()) { | |
| 7335 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 7355 | 7336 | 1...2 => .{ ._pd, .@"and" }, |
| 7356 | 7337 | else => null, |
| 7357 | 7338 | }, |
| ... | ... | @@ -7368,20 +7349,20 @@ fn genBinOp( |
| 7368 | 7349 | mask_reg, |
| 7369 | 7350 | ); |
| 7370 | 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 | 7353 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7373 | 7354 | 32 => .{ ._ps, .andn }, |
| 7374 | 7355 | 64 => .{ ._pd, .andn }, |
| 7375 | 7356 | 16, 80, 128 => null, |
| 7376 | 7357 | else => unreachable, |
| 7377 | 7358 | }, |
| 7378 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | |
| 7379 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | |
| 7380 | 32 => switch (lhs_ty.vectorLen()) { | |
| 7359 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { | |
| 7360 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { | |
| 7361 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 7381 | 7362 | 1...4 => .{ ._ps, .andn }, |
| 7382 | 7363 | else => null, |
| 7383 | 7364 | }, |
| 7384 | 64 => switch (lhs_ty.vectorLen()) { | |
| 7365 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 7385 | 7366 | 1...2 => .{ ._pd, .andn }, |
| 7386 | 7367 | else => null, |
| 7387 | 7368 | }, |
| ... | ... | @@ -7398,20 +7379,20 @@ fn genBinOp( |
| 7398 | 7379 | lhs_copy_reg.?, |
| 7399 | 7380 | ); |
| 7400 | 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 | 7383 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7403 | 7384 | 32 => .{ ._ps, .@"or" }, |
| 7404 | 7385 | 64 => .{ ._pd, .@"or" }, |
| 7405 | 7386 | 16, 80, 128 => null, |
| 7406 | 7387 | else => unreachable, |
| 7407 | 7388 | }, |
| 7408 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | |
| 7409 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | |
| 7410 | 32 => switch (lhs_ty.vectorLen()) { | |
| 7389 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { | |
| 7390 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { | |
| 7391 | 32 => switch (lhs_ty.vectorLen(mod)) { | |
| 7411 | 7392 | 1...4 => .{ ._ps, .@"or" }, |
| 7412 | 7393 | else => null, |
| 7413 | 7394 | }, |
| 7414 | 64 => switch (lhs_ty.vectorLen()) { | |
| 7395 | 64 => switch (lhs_ty.vectorLen(mod)) { | |
| 7415 | 7396 | 1...2 => .{ ._pd, .@"or" }, |
| 7416 | 7397 | else => null, |
| 7417 | 7398 | }, |
| ... | ... | @@ -7442,7 +7423,8 @@ fn genBinOpMir( |
| 7442 | 7423 | dst_mcv: MCValue, |
| 7443 | 7424 | src_mcv: MCValue, |
| 7444 | 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 | 7428 | switch (dst_mcv) { |
| 7447 | 7429 | .none, |
| 7448 | 7430 | .unreach, |
| ... | ... | @@ -7562,11 +7544,7 @@ fn genBinOpMir( |
| 7562 | 7544 | .load_got, |
| 7563 | 7545 | .load_tlv, |
| 7564 | 7546 | => { |
| 7565 | var ptr_pl = Type.Payload.ElemType{ | |
| 7566 | .base = .{ .tag = .single_const_pointer }, | |
| 7567 | .data = ty, | |
| 7568 | }; | |
| 7569 | const ptr_ty = Type.initPayload(&ptr_pl.base); | |
| 7547 | const ptr_ty = try mod.singleConstPtrType(ty); | |
| 7570 | 7548 | const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address()); |
| 7571 | 7549 | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ |
| 7572 | 7550 | .indirect = .{ .reg = addr_reg }, |
| ... | ... | @@ -7640,7 +7618,7 @@ fn genBinOpMir( |
| 7640 | 7618 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); |
| 7641 | 7619 | |
| 7642 | 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 | 7622 | const limb_ty = if (abi_size <= 8) ty else switch (ty_signedness) { |
| 7645 | 7623 | .signed => Type.usize, |
| 7646 | 7624 | .unsigned => Type.isize, |
| ... | ... | @@ -7796,7 +7774,8 @@ fn genBinOpMir( |
| 7796 | 7774 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 7797 | 7775 | /// Does not support byte-size operands. |
| 7798 | 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 | 7779 | switch (dst_mcv) { |
| 7801 | 7780 | .none, |
| 7802 | 7781 | .unreach, |
| ... | ... | @@ -7896,6 +7875,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 7896 | 7875 | } |
| 7897 | 7876 | |
| 7898 | 7877 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 7878 | const mod = self.bin_file.options.module.?; | |
| 7899 | 7879 | // skip zero-bit arguments as they don't have a corresponding arg instruction |
| 7900 | 7880 | var arg_index = self.arg_index; |
| 7901 | 7881 | while (self.args[arg_index] == .none) arg_index += 1; |
| ... | ... | @@ -7909,9 +7889,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 7909 | 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 | 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 | 7895 | try self.genArgDbgInfo(ty, name, dst_mcv); |
| 7916 | 7896 | |
| 7917 | 7897 | break :result dst_mcv; |
| ... | ... | @@ -7920,6 +7900,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 7920 | 7900 | } |
| 7921 | 7901 | |
| 7922 | 7902 | fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 7903 | const mod = self.bin_file.options.module.?; | |
| 7923 | 7904 | switch (self.debug_output) { |
| 7924 | 7905 | .dwarf => |dw| { |
| 7925 | 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 | 7919 | // TODO: this might need adjusting like the linkers do. |
| 7939 | 7920 | // Instead of flattening the owner and passing Decl.Index here we may |
| 7940 | 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 | 7924 | .plan9 => {}, |
| 7944 | 7925 | .none => {}, |
| ... | ... | @@ -7952,6 +7933,7 @@ fn genVarDbgInfo( |
| 7952 | 7933 | mcv: MCValue, |
| 7953 | 7934 | name: [:0]const u8, |
| 7954 | 7935 | ) !void { |
| 7936 | const mod = self.bin_file.options.module.?; | |
| 7955 | 7937 | const is_ptr = switch (tag) { |
| 7956 | 7938 | .dbg_var_ptr => true, |
| 7957 | 7939 | .dbg_var_val => false, |
| ... | ... | @@ -7982,7 +7964,7 @@ fn genVarDbgInfo( |
| 7982 | 7964 | // TODO: this might need adjusting like the linkers do. |
| 7983 | 7965 | // Instead of flattening the owner and passing Decl.Index here we may |
| 7984 | 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 | 7969 | .plan9 => {}, |
| 7988 | 7970 | .none => {}, |
| ... | ... | @@ -8022,20 +8004,23 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void { |
| 8022 | 8004 | } |
| 8023 | 8005 | |
| 8024 | 8006 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 8007 | const mod = self.bin_file.options.module.?; | |
| 8025 | 8008 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{}); |
| 8026 | 8009 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8027 | 8010 | const callee = pl_op.operand; |
| 8028 | 8011 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 8029 | 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 | 8016 | .Fn => ty, |
| 8034 | .Pointer => ty.childType(), | |
| 8017 | .Pointer => ty.childType(mod), | |
| 8035 | 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 | 8024 | defer info.deinit(self); |
| 8040 | 8025 | |
| 8041 | 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 | 8047 | else => unreachable, |
| 8063 | 8048 | } |
| 8064 | 8049 | for (args, info.args) |arg, mc_arg| { |
| 8065 | const arg_ty = self.air.typeOf(arg); | |
| 8050 | const arg_ty = self.typeOf(arg); | |
| 8066 | 8051 | const arg_mcv = try self.resolveInst(arg); |
| 8067 | 8052 | switch (mc_arg) { |
| 8068 | 8053 | .none => {}, |
| ... | ... | @@ -8076,8 +8061,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8076 | 8061 | const ret_lock = switch (info.return_value.long) { |
| 8077 | 8062 | .none, .unreach => null, |
| 8078 | 8063 | .indirect => |reg_off| lock: { |
| 8079 | const ret_ty = fn_ty.fnReturnType(); | |
| 8080 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ret_ty, self.target.*)); | |
| 8064 | const ret_ty = fn_info.return_type.toType(); | |
| 8065 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ret_ty, mod)); | |
| 8081 | 8066 | try self.genSetReg(reg_off.reg, Type.usize, .{ |
| 8082 | 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 | 8074 | defer if (ret_lock) |lock| self.register_manager.unlockReg(lock); |
| 8090 | 8075 | |
| 8091 | 8076 | for (args, info.args) |arg, mc_arg| { |
| 8092 | const arg_ty = self.air.typeOf(arg); | |
| 8077 | const arg_ty = self.typeOf(arg); | |
| 8093 | 8078 | const arg_mcv = try self.resolveInst(arg); |
| 8094 | 8079 | switch (mc_arg) { |
| 8095 | 8080 | .none, .load_frame => {}, |
| ... | ... | @@ -8100,15 +8085,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8100 | 8085 | |
| 8101 | 8086 | // Due to incremental compilation, how function calls are generated depends |
| 8102 | 8087 | // on linking. |
| 8103 | const mod = self.bin_file.options.module.?; | |
| 8104 | if (self.air.value(callee)) |func_value| { | |
| 8105 | if (if (func_value.castTag(.function)) |func_payload| | |
| 8106 | func_payload.data.owner_decl | |
| 8107 | else if (func_value.castTag(.decl_ref)) |decl_ref_payload| | |
| 8108 | decl_ref_payload.data | |
| 8109 | else | |
| 8110 | null) |owner_decl| | |
| 8111 | { | |
| 8088 | if (try self.air.value(callee, mod)) |func_value| { | |
| 8089 | const func_key = mod.intern_pool.indexToKey(func_value.ip_index); | |
| 8090 | if (switch (func_key) { | |
| 8091 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 8092 | .ptr => |ptr| switch (ptr.addr) { | |
| 8093 | .decl => |decl| decl, | |
| 8094 | else => null, | |
| 8095 | }, | |
| 8096 | else => null, | |
| 8097 | }) |owner_decl| { | |
| 8112 | 8098 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8113 | 8099 | const atom_index = try elf_file.getOrCreateAtomForDecl(owner_decl); |
| 8114 | 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 | 8127 | .disp = @intCast(i32, fn_got_addr), |
| 8142 | 8128 | })); |
| 8143 | 8129 | } else unreachable; |
| 8144 | } else if (func_value.castTag(.extern_fn)) |func_payload| { | |
| 8145 | const extern_fn = func_payload.data; | |
| 8146 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); | |
| 8147 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | |
| 8130 | } else if (func_value.getExternFunc(mod)) |extern_func| { | |
| 8131 | const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name); | |
| 8132 | const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); | |
| 8148 | 8133 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 8149 | 8134 | const atom_index = try self.owner.getSymbolIndex(self); |
| 8150 | 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 | 8163 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 8179 | 8164 | } |
| 8180 | 8165 | } else { |
| 8181 | assert(ty.zigTypeTag() == .Pointer); | |
| 8166 | assert(ty.zigTypeTag(mod) == .Pointer); | |
| 8182 | 8167 | const mcv = try self.resolveInst(callee); |
| 8183 | 8168 | try self.genSetReg(.rax, Type.usize, mcv); |
| 8184 | 8169 | try self.asmRegister(.{ ._, .call }, .rax); |
| ... | ... | @@ -8193,9 +8178,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8193 | 8178 | } |
| 8194 | 8179 | |
| 8195 | 8180 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 8181 | const mod = self.bin_file.options.module.?; | |
| 8196 | 8182 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8197 | 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 | 8185 | switch (self.ret_mcv.short) { |
| 8200 | 8186 | .none => {}, |
| 8201 | 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 | 8205 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 8220 | 8206 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8221 | 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 | 8209 | switch (self.ret_mcv.short) { |
| 8224 | 8210 | .none => {}, |
| 8225 | 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 | 8220 | } |
| 8235 | 8221 | |
| 8236 | 8222 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8223 | const mod = self.bin_file.options.module.?; | |
| 8237 | 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 | 8227 | try self.spillEflagsIfOccupied(); |
| 8241 | 8228 | self.eflags_inst = inst; |
| ... | ... | @@ -8255,9 +8242,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8255 | 8242 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 8256 | 8243 | |
| 8257 | 8244 | const result = MCValue{ |
| 8258 | .eflags = switch (ty.zigTypeTag()) { | |
| 8245 | .eflags = switch (ty.zigTypeTag(mod)) { | |
| 8259 | 8246 | else => result: { |
| 8260 | const abi_size = @intCast(u16, ty.abiSize(self.target.*)); | |
| 8247 | const abi_size = @intCast(u16, ty.abiSize(mod)); | |
| 8261 | 8248 | const may_flip: enum { |
| 8262 | 8249 | may_flip, |
| 8263 | 8250 | must_flip, |
| ... | ... | @@ -8290,7 +8277,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8290 | 8277 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 8291 | 8278 | |
| 8292 | 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 | 8281 | result_op: { |
| 8295 | 8282 | const flipped_op = if (flipped) op.reverse() else op; |
| 8296 | 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 | 8391 | try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp2_reg, tmp1_reg); |
| 8405 | 8392 | try self.genBinOpMir(.{ ._ss, .ucomi }, ty, tmp1_mcv, tmp2_mcv); |
| 8406 | 8393 | } else return self.fail("TODO implement airCmp for {}", .{ |
| 8407 | ty.fmt(self.bin_file.options.module.?), | |
| 8394 | ty.fmt(mod), | |
| 8408 | 8395 | }), |
| 8409 | 8396 | 32 => try self.genBinOpMir( |
| 8410 | 8397 | .{ ._ss, .ucomi }, |
| ... | ... | @@ -8419,7 +8406,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8419 | 8406 | src_mcv, |
| 8420 | 8407 | ), |
| 8421 | 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 | 8440 | try self.spillEflagsIfOccupied(); |
| 8454 | 8441 | self.eflags_inst = inst; |
| 8455 | 8442 | |
| 8456 | const op_ty = self.air.typeOf(un_op); | |
| 8457 | const op_abi_size = @intCast(u32, op_ty.abiSize(self.target.*)); | |
| 8443 | const op_ty = self.typeOf(un_op); | |
| 8444 | const op_abi_size = @intCast(u32, op_ty.abiSize(mod)); | |
| 8458 | 8445 | const op_mcv = try self.resolveInst(un_op); |
| 8459 | 8446 | const dst_reg = switch (op_mcv) { |
| 8460 | 8447 | .register => |reg| reg, |
| ... | ... | @@ -8473,16 +8460,17 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 8473 | 8460 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8474 | 8461 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 8475 | 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 | 8464 | const result = try self.genTry(inst, pl_op.operand, body, err_union_ty, false); |
| 8478 | 8465 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 8479 | 8466 | } |
| 8480 | 8467 | |
| 8481 | 8468 | fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8469 | const mod = self.bin_file.options.module.?; | |
| 8482 | 8470 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 8483 | 8471 | const extra = self.air.extraData(Air.TryPtr, ty_pl.payload); |
| 8484 | 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 | 8474 | const result = try self.genTry(inst, extra.data.ptr, body, err_union_ty, true); |
| 8487 | 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 | 8534 | } |
| 8547 | 8535 | |
| 8548 | 8536 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 8549 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 8550 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 8537 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; | |
| 8538 | const mod = self.bin_file.options.module.?; | |
| 8539 | const function = mod.funcPtr(ty_fn.func); | |
| 8551 | 8540 | // TODO emit debug info for function change |
| 8552 | 8541 | _ = function; |
| 8553 | 8542 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); |
| ... | ... | @@ -8561,7 +8550,7 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 8561 | 8550 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 8562 | 8551 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8563 | 8552 | const operand = pl_op.operand; |
| 8564 | const ty = self.air.typeOf(operand); | |
| 8553 | const ty = self.typeOf(operand); | |
| 8565 | 8554 | const mcv = try self.resolveInst(operand); |
| 8566 | 8555 | |
| 8567 | 8556 | const name = self.air.nullTerminatedString(pl_op.payload); |
| ... | ... | @@ -8573,7 +8562,8 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 8573 | 8562 | } |
| 8574 | 8563 | |
| 8575 | 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 | 8567 | switch (mcv) { |
| 8578 | 8568 | .eflags => |cc| { |
| 8579 | 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 | 8592 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 8603 | 8593 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8604 | 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 | 8596 | const extra = self.air.extraData(Air.CondBr, pl_op.payload); |
| 8607 | 8597 | const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len]; |
| 8608 | 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 | 8636 | } |
| 8647 | 8637 | |
| 8648 | 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 | 8640 | switch (opt_mcv) { |
| 8650 | 8641 | .register_overflow => |ro| return .{ .eflags = ro.eflags.negate() }, |
| 8651 | 8642 | else => {}, |
| ... | ... | @@ -8654,14 +8645,12 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8654 | 8645 | try self.spillEflagsIfOccupied(); |
| 8655 | 8646 | self.eflags_inst = inst; |
| 8656 | 8647 | |
| 8657 | var pl_buf: Type.Payload.ElemType = undefined; | |
| 8658 | const pl_ty = opt_ty.optionalChild(&pl_buf); | |
| 8648 | const pl_ty = opt_ty.optionalChild(mod); | |
| 8659 | 8649 | |
| 8660 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 8661 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload()) | |
| 8662 | .{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty } | |
| 8650 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(mod)) | |
| 8651 | .{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(mod) else pl_ty } | |
| 8663 | 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 | 8655 | switch (opt_mcv) { |
| 8667 | 8656 | .none, |
| ... | ... | @@ -8681,14 +8670,14 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8681 | 8670 | |
| 8682 | 8671 | .register => |opt_reg| { |
| 8683 | 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 | 8674 | const alias_reg = registerAlias(opt_reg, some_abi_size); |
| 8686 | 8675 | assert(some_abi_size * 8 == alias_reg.bitSize()); |
| 8687 | 8676 | try self.asmRegisterRegister(.{ ._, .@"test" }, alias_reg, alias_reg); |
| 8688 | 8677 | return .{ .eflags = .z }; |
| 8689 | 8678 | } |
| 8690 | assert(some_info.ty.tag() == .bool); | |
| 8691 | const opt_abi_size = @intCast(u32, opt_ty.abiSize(self.target.*)); | |
| 8679 | assert(some_info.ty.ip_index == .bool_type); | |
| 8680 | const opt_abi_size = @intCast(u32, opt_ty.abiSize(mod)); | |
| 8692 | 8681 | try self.asmRegisterImmediate( |
| 8693 | 8682 | .{ ._, .bt }, |
| 8694 | 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 | 8696 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 8708 | 8697 | |
| 8709 | 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 | 8700 | try self.asmMemoryImmediate( |
| 8712 | 8701 | .{ ._, .cmp }, |
| 8713 | 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 | 8709 | }, |
| 8721 | 8710 | |
| 8722 | 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 | 8713 | try self.asmMemoryImmediate( |
| 8725 | 8714 | .{ ._, .cmp }, |
| 8726 | 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 | 8731 | } |
| 8743 | 8732 | |
| 8744 | 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 | 8735 | try self.spillEflagsIfOccupied(); |
| 8746 | 8736 | self.eflags_inst = inst; |
| 8747 | 8737 | |
| 8748 | const opt_ty = ptr_ty.childType(); | |
| 8749 | var pl_buf: Type.Payload.ElemType = undefined; | |
| 8750 | const pl_ty = opt_ty.optionalChild(&pl_buf); | |
| 8738 | const opt_ty = ptr_ty.childType(mod); | |
| 8739 | const pl_ty = opt_ty.optionalChild(mod); | |
| 8751 | 8740 | |
| 8752 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 8753 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload()) | |
| 8754 | .{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty } | |
| 8741 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(mod)) | |
| 8742 | .{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(mod) else pl_ty } | |
| 8755 | 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 | 8746 | const ptr_reg = switch (ptr_mcv) { |
| 8759 | 8747 | .register => |reg| reg, |
| ... | ... | @@ -8762,7 +8750,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) |
| 8762 | 8750 | const ptr_lock = self.register_manager.lockReg(ptr_reg); |
| 8763 | 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 | 8754 | try self.asmMemoryImmediate( |
| 8767 | 8755 | .{ ._, .cmp }, |
| 8768 | 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 | 8763 | } |
| 8776 | 8764 | |
| 8777 | 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 | 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 | 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 | 8779 | switch (operand) { |
| 8791 | 8780 | .register => |reg| { |
| 8792 | 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 | 8833 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 8845 | 8834 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8846 | 8835 | const operand = try self.resolveInst(un_op); |
| 8847 | const ty = self.air.typeOf(un_op); | |
| 8836 | const ty = self.typeOf(un_op); | |
| 8848 | 8837 | const result = try self.isNull(inst, ty, operand); |
| 8849 | 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 | 8841 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8853 | 8842 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8854 | 8843 | const operand = try self.resolveInst(un_op); |
| 8855 | const ty = self.air.typeOf(un_op); | |
| 8844 | const ty = self.typeOf(un_op); | |
| 8856 | 8845 | const result = try self.isNullPtr(inst, ty, operand); |
| 8857 | 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 | 8849 | fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 8861 | 8850 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8862 | 8851 | const operand = try self.resolveInst(un_op); |
| 8863 | const ty = self.air.typeOf(un_op); | |
| 8852 | const ty = self.typeOf(un_op); | |
| 8864 | 8853 | const result = switch (try self.isNull(inst, ty, operand)) { |
| 8865 | 8854 | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 8866 | 8855 | else => unreachable, |
| ... | ... | @@ -8871,7 +8860,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 8871 | 8860 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8872 | 8861 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8873 | 8862 | const operand = try self.resolveInst(un_op); |
| 8874 | const ty = self.air.typeOf(un_op); | |
| 8863 | const ty = self.typeOf(un_op); | |
| 8875 | 8864 | const result = switch (try self.isNullPtr(inst, ty, operand)) { |
| 8876 | 8865 | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 8877 | 8866 | else => unreachable, |
| ... | ... | @@ -8882,12 +8871,13 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8882 | 8871 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 8883 | 8872 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8884 | 8873 | const operand = try self.resolveInst(un_op); |
| 8885 | const ty = self.air.typeOf(un_op); | |
| 8874 | const ty = self.typeOf(un_op); | |
| 8886 | 8875 | const result = try self.isErr(inst, ty, operand); |
| 8887 | 8876 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8888 | 8877 | } |
| 8889 | 8878 | |
| 8890 | 8879 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8880 | const mod = self.bin_file.options.module.?; | |
| 8891 | 8881 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8892 | 8882 | |
| 8893 | 8883 | const operand_ptr = try self.resolveInst(un_op); |
| ... | ... | @@ -8905,10 +8895,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8905 | 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 | 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 | 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 | 8906 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 8917 | 8907 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8918 | 8908 | const operand = try self.resolveInst(un_op); |
| 8919 | const ty = self.air.typeOf(un_op); | |
| 8909 | const ty = self.typeOf(un_op); | |
| 8920 | 8910 | const result = try self.isNonErr(inst, ty, operand); |
| 8921 | 8911 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8922 | 8912 | } |
| 8923 | 8913 | |
| 8924 | 8914 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8915 | const mod = self.bin_file.options.module.?; | |
| 8925 | 8916 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8926 | 8917 | |
| 8927 | 8918 | const operand_ptr = try self.resolveInst(un_op); |
| ... | ... | @@ -8939,10 +8930,10 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8939 | 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 | 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 | 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 | 8996 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9006 | 8997 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 9007 | 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 | 9000 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 9010 | 9001 | var extra_index: usize = switch_br.end; |
| 9011 | 9002 | var case_i: u32 = 0; |
| ... | ... | @@ -9088,12 +9079,13 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { |
| 9088 | 9079 | } |
| 9089 | 9080 | |
| 9090 | 9081 | fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9082 | const mod = self.bin_file.options.module.?; | |
| 9091 | 9083 | const br = self.air.instructions.items(.data)[inst].br; |
| 9092 | 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 | 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 | 9089 | const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; |
| 9098 | 9090 | const block_data = self.blocks.getPtr(br.block_inst).?; |
| 9099 | 9091 | const first_br = block_data.relocs.items.len == 0; |
| ... | ... | @@ -9216,7 +9208,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9216 | 9208 | |
| 9217 | 9209 | const arg_mcv = try self.resolveInst(input); |
| 9218 | 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 | 9394 | }; |
| 9403 | 9395 | }; |
| 9404 | 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 | 9399 | else => return .{ .move = .{ ._, .mov } }, |
| 9407 | 9400 | .Float => switch (ty.floatBits(self.target.*)) { |
| 9408 | 9401 | 16 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| ... | ... | @@ -9419,9 +9412,9 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9419 | 9412 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 9420 | 9413 | else => {}, |
| 9421 | 9414 | }, |
| 9422 | .Vector => switch (ty.childType().zigTypeTag()) { | |
| 9423 | .Int => switch (ty.childType().intInfo(self.target.*).bits) { | |
| 9424 | 8 => switch (ty.vectorLen()) { | |
| 9415 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { | |
| 9416 | .Int => switch (ty.childType(mod).intInfo(mod).bits) { | |
| 9417 | 8 => switch (ty.vectorLen(mod)) { | |
| 9425 | 9418 | 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{ |
| 9426 | 9419 | .insert = .{ .vp_b, .insr }, |
| 9427 | 9420 | .extract = .{ .vp_b, .extr }, |
| ... | ... | @@ -9451,7 +9444,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9451 | 9444 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9452 | 9445 | else => {}, |
| 9453 | 9446 | }, |
| 9454 | 16 => switch (ty.vectorLen()) { | |
| 9447 | 16 => switch (ty.vectorLen(mod)) { | |
| 9455 | 9448 | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 9456 | 9449 | .insert = .{ .vp_w, .insr }, |
| 9457 | 9450 | .extract = .{ .vp_w, .extr }, |
| ... | ... | @@ -9474,7 +9467,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9474 | 9467 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9475 | 9468 | else => {}, |
| 9476 | 9469 | }, |
| 9477 | 32 => switch (ty.vectorLen()) { | |
| 9470 | 32 => switch (ty.vectorLen(mod)) { | |
| 9478 | 9471 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9479 | 9472 | .{ .v_d, .mov } |
| 9480 | 9473 | else |
| ... | ... | @@ -9490,7 +9483,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9490 | 9483 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9491 | 9484 | else => {}, |
| 9492 | 9485 | }, |
| 9493 | 64 => switch (ty.vectorLen()) { | |
| 9486 | 64 => switch (ty.vectorLen(mod)) { | |
| 9494 | 9487 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9495 | 9488 | .{ .v_q, .mov } |
| 9496 | 9489 | else |
| ... | ... | @@ -9502,7 +9495,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9502 | 9495 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9503 | 9496 | else => {}, |
| 9504 | 9497 | }, |
| 9505 | 128 => switch (ty.vectorLen()) { | |
| 9498 | 128 => switch (ty.vectorLen(mod)) { | |
| 9506 | 9499 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9507 | 9500 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 9508 | 9501 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| ... | ... | @@ -9510,15 +9503,15 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9510 | 9503 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9511 | 9504 | else => {}, |
| 9512 | 9505 | }, |
| 9513 | 256 => switch (ty.vectorLen()) { | |
| 9506 | 256 => switch (ty.vectorLen(mod)) { | |
| 9514 | 9507 | 1 => if (self.hasFeature(.avx)) |
| 9515 | 9508 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9516 | 9509 | else => {}, |
| 9517 | 9510 | }, |
| 9518 | 9511 | else => {}, |
| 9519 | 9512 | }, |
| 9520 | .Float => switch (ty.childType().floatBits(self.target.*)) { | |
| 9521 | 16 => switch (ty.vectorLen()) { | |
| 9513 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { | |
| 9514 | 16 => switch (ty.vectorLen(mod)) { | |
| 9522 | 9515 | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 9523 | 9516 | .insert = .{ .vp_w, .insr }, |
| 9524 | 9517 | .extract = .{ .vp_w, .extr }, |
| ... | ... | @@ -9541,7 +9534,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9541 | 9534 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9542 | 9535 | else => {}, |
| 9543 | 9536 | }, |
| 9544 | 32 => switch (ty.vectorLen()) { | |
| 9537 | 32 => switch (ty.vectorLen(mod)) { | |
| 9545 | 9538 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9546 | 9539 | .{ .v_ss, .mov } |
| 9547 | 9540 | else |
| ... | ... | @@ -9557,7 +9550,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9557 | 9550 | return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } }, |
| 9558 | 9551 | else => {}, |
| 9559 | 9552 | }, |
| 9560 | 64 => switch (ty.vectorLen()) { | |
| 9553 | 64 => switch (ty.vectorLen(mod)) { | |
| 9561 | 9554 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9562 | 9555 | .{ .v_sd, .mov } |
| 9563 | 9556 | else |
| ... | ... | @@ -9569,7 +9562,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9569 | 9562 | return .{ .move = if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } }, |
| 9570 | 9563 | else => {}, |
| 9571 | 9564 | }, |
| 9572 | 128 => switch (ty.vectorLen()) { | |
| 9565 | 128 => switch (ty.vectorLen(mod)) { | |
| 9573 | 9566 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9574 | 9567 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 9575 | 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 | 9640 | } |
| 9648 | 9641 | |
| 9649 | 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 | 9645 | if (abi_size * 8 > dst_reg.bitSize()) |
| 9652 | 9646 | return self.fail("genSetReg called with a value larger than dst_reg", .{}); |
| 9653 | 9647 | switch (src_mcv) { |
| ... | ... | @@ -9730,7 +9724,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9730 | 9724 | .{ .register = try self.copyToTmpRegister(ty, src_mcv) }, |
| 9731 | 9725 | ), |
| 9732 | 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 | 9728 | else => switch (abi_size) { |
| 9735 | 9729 | 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, |
| 9736 | 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 | 9732 | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, |
| 9739 | 9733 | else => null, |
| 9740 | 9734 | }, |
| 9741 | .Float => switch (ty.scalarType().floatBits(self.target.*)) { | |
| 9735 | .Float => switch (ty.scalarType(mod).floatBits(self.target.*)) { | |
| 9742 | 9736 | 16, 128 => switch (abi_size) { |
| 9743 | 9737 | 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, |
| 9744 | 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 | 9783 | .indirect => try self.moveStrategy(ty, false), |
| 9790 | 9784 | .load_frame => |frame_addr| try self.moveStrategy( |
| 9791 | 9785 | ty, |
| 9792 | self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(self.target.*), | |
| 9786 | self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(mod), | |
| 9793 | 9787 | ), |
| 9794 | 9788 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| 9795 | 9789 | else => unreachable, |
| ... | ... | @@ -9821,7 +9815,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9821 | 9815 | switch (try self.moveStrategy(ty, mem.isAlignedGeneric( |
| 9822 | 9816 | u32, |
| 9823 | 9817 | @bitCast(u32, small_addr), |
| 9824 | ty.abiAlignment(self.target.*), | |
| 9818 | ty.abiAlignment(mod), | |
| 9825 | 9819 | ))) { |
| 9826 | 9820 | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), |
| 9827 | 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 | 9833 | ), |
| 9840 | 9834 | } |
| 9841 | 9835 | }, |
| 9842 | .load_direct => |sym_index| switch (ty.zigTypeTag()) { | |
| 9836 | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { | |
| 9843 | 9837 | else => { |
| 9844 | 9838 | const atom_index = try self.owner.getSymbolIndex(self); |
| 9845 | 9839 | _ = try self.addInst(.{ |
| ... | ... | @@ -9933,7 +9927,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9933 | 9927 | } |
| 9934 | 9928 | |
| 9935 | 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 | 9932 | const dst_ptr_mcv: MCValue = switch (base) { |
| 9938 | 9933 | .none => .{ .immediate = @bitCast(u64, @as(i64, disp)) }, |
| 9939 | 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 | 9940 | try self.genInlineMemset(dst_ptr_mcv, .{ .immediate = 0xaa }, .{ .immediate = abi_size }), |
| 9946 | 9941 | .immediate => |imm| switch (abi_size) { |
| 9947 | 9942 | 1, 2, 4 => { |
| 9948 | const immediate = if (ty.isSignedInt()) | |
| 9943 | const immediate = if (ty.isSignedInt(mod)) | |
| 9949 | 9944 | Immediate.s(@truncate(i32, @bitCast(i64, imm))) |
| 9950 | 9945 | else |
| 9951 | 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 | 9962 | while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate( |
| 9968 | 9963 | .{ ._, .mov }, |
| 9969 | 9964 | Memory.sib(.dword, .{ .base = base, .disp = disp + offset }), |
| 9970 | if (ty.isSignedInt()) | |
| 9965 | if (ty.isSignedInt(mod)) | |
| 9971 | 9966 | Immediate.s(@truncate( |
| 9972 | 9967 | i32, |
| 9973 | 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 | 9986 | .none => mem.isAlignedGeneric( |
| 9992 | 9987 | u32, |
| 9993 | 9988 | @bitCast(u32, disp), |
| 9994 | ty.abiAlignment(self.target.*), | |
| 9989 | ty.abiAlignment(mod), | |
| 9995 | 9990 | ), |
| 9996 | 9991 | .reg => |reg| switch (reg) { |
| 9997 | 9992 | .es, .cs, .ss, .ds => mem.isAlignedGeneric( |
| 9998 | 9993 | u32, |
| 9999 | 9994 | @bitCast(u32, disp), |
| 10000 | ty.abiAlignment(self.target.*), | |
| 9995 | ty.abiAlignment(mod), | |
| 10001 | 9996 | ), |
| 10002 | 9997 | else => false, |
| 10003 | 9998 | }, |
| 10004 | 9999 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10005 | 10000 | .{ .index = frame_index, .off = disp }, |
| 10006 | ) >= ty.abiAlignment(self.target.*), | |
| 10001 | ) >= ty.abiAlignment(mod), | |
| 10007 | 10002 | })) { |
| 10008 | 10003 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| 10009 | 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 | 10012 | .register_overflow => |ro| { |
| 10018 | 10013 | try self.genSetMem( |
| 10019 | 10014 | base, |
| 10020 | disp + @intCast(i32, ty.structFieldOffset(0, self.target.*)), | |
| 10021 | ty.structFieldType(0), | |
| 10015 | disp + @intCast(i32, ty.structFieldOffset(0, mod)), | |
| 10016 | ty.structFieldType(0, mod), | |
| 10022 | 10017 | .{ .register = ro.reg }, |
| 10023 | 10018 | ); |
| 10024 | 10019 | try self.genSetMem( |
| 10025 | 10020 | base, |
| 10026 | disp + @intCast(i32, ty.structFieldOffset(1, self.target.*)), | |
| 10027 | ty.structFieldType(1), | |
| 10021 | disp + @intCast(i32, ty.structFieldOffset(1, mod)), | |
| 10022 | ty.structFieldType(1, mod), | |
| 10028 | 10023 | .{ .eflags = ro.eflags }, |
| 10029 | 10024 | ); |
| 10030 | 10025 | }, |
| ... | ... | @@ -10138,7 +10133,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10138 | 10133 | if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; |
| 10139 | 10134 | |
| 10140 | 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 | 10137 | try self.genCopy(dst_ty, dst_mcv, src_mcv); |
| 10143 | 10138 | break :result dst_mcv; |
| 10144 | 10139 | }; |
| ... | ... | @@ -10146,13 +10141,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10146 | 10141 | } |
| 10147 | 10142 | |
| 10148 | 10143 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 10144 | const mod = self.bin_file.options.module.?; | |
| 10149 | 10145 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10150 | const dst_ty = self.air.typeOfIndex(inst); | |
| 10151 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 10146 | const dst_ty = self.typeOfIndex(inst); | |
| 10147 | const src_ty = self.typeOf(ty_op.operand); | |
| 10152 | 10148 | |
| 10153 | 10149 | const result = result: { |
| 10154 | const dst_rc = regClassForType(dst_ty); | |
| 10155 | const src_rc = regClassForType(src_ty); | |
| 10150 | const dst_rc = regClassForType(dst_ty, mod); | |
| 10151 | const src_rc = regClassForType(src_ty, mod); | |
| 10156 | 10152 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 10157 | 10153 | |
| 10158 | 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 | 10168 | }; |
| 10173 | 10169 | |
| 10174 | 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 | 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 | 10174 | if (dst_signedness == src_signedness) break :result dst_mcv; |
| 10179 | 10175 | |
| 10180 | const abi_size = @intCast(u16, dst_ty.abiSize(self.target.*)); | |
| 10181 | const bit_size = @intCast(u16, dst_ty.bitSize(self.target.*)); | |
| 10176 | const abi_size = @intCast(u16, dst_ty.abiSize(mod)); | |
| 10177 | const bit_size = @intCast(u16, dst_ty.bitSize(mod)); | |
| 10182 | 10178 | if (abi_size * 8 <= bit_size) break :result dst_mcv; |
| 10183 | 10179 | |
| 10184 | 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 | 10188 | const high_lock = self.register_manager.lockReg(high_reg); |
| 10193 | 10189 | defer if (high_lock) |lock| self.register_manager.unlockReg(lock); |
| 10194 | 10190 | |
| 10195 | var high_pl = Type.Payload.Bits{ | |
| 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); | |
| 10191 | const high_ty = try mod.intType(dst_signedness, bit_size % 64); | |
| 10203 | 10192 | |
| 10204 | 10193 | try self.truncateRegister(high_ty, high_reg); |
| 10205 | 10194 | if (!dst_mcv.isRegister()) try self.genCopy( |
| ... | ... | @@ -10213,19 +10202,20 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 10213 | 10202 | } |
| 10214 | 10203 | |
| 10215 | 10204 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 10205 | const mod = self.bin_file.options.module.?; | |
| 10216 | 10206 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10217 | 10207 | |
| 10218 | const slice_ty = self.air.typeOfIndex(inst); | |
| 10219 | const ptr_ty = self.air.typeOf(ty_op.operand); | |
| 10208 | const slice_ty = self.typeOfIndex(inst); | |
| 10209 | const ptr_ty = self.typeOf(ty_op.operand); | |
| 10220 | 10210 | const ptr = try self.resolveInst(ty_op.operand); |
| 10221 | const array_ty = ptr_ty.childType(); | |
| 10222 | const array_len = array_ty.arrayLen(); | |
| 10211 | const array_ty = ptr_ty.childType(mod); | |
| 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 | 10215 | try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr); |
| 10226 | 10216 | try self.genSetMem( |
| 10227 | 10217 | .{ .frame = frame_index }, |
| 10228 | @intCast(i32, ptr_ty.abiSize(self.target.*)), | |
| 10218 | @intCast(i32, ptr_ty.abiSize(mod)), | |
| 10229 | 10219 | Type.usize, |
| 10230 | 10220 | .{ .immediate = array_len }, |
| 10231 | 10221 | ); |
| ... | ... | @@ -10235,20 +10225,21 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 10235 | 10225 | } |
| 10236 | 10226 | |
| 10237 | 10227 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 10228 | const mod = self.bin_file.options.module.?; | |
| 10238 | 10229 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10239 | 10230 | |
| 10240 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 10241 | const src_bits = @intCast(u32, src_ty.bitSize(self.target.*)); | |
| 10231 | const src_ty = self.typeOf(ty_op.operand); | |
| 10232 | const src_bits = @intCast(u32, src_ty.bitSize(mod)); | |
| 10242 | 10233 | const src_signedness = |
| 10243 | if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned; | |
| 10244 | const dst_ty = self.air.typeOfIndex(inst); | |
| 10234 | if (src_ty.isAbiInt(mod)) src_ty.intInfo(mod).signedness else .unsigned; | |
| 10235 | const dst_ty = self.typeOfIndex(inst); | |
| 10245 | 10236 | |
| 10246 | 10237 | const src_size = math.divCeil(u32, @max(switch (src_signedness) { |
| 10247 | 10238 | .signed => src_bits, |
| 10248 | 10239 | .unsigned => src_bits + 1, |
| 10249 | 10240 | }, 32), 8) catch unreachable; |
| 10250 | 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 | 10245 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -10261,12 +10252,12 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 10261 | 10252 | |
| 10262 | 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 | 10256 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 10266 | 10257 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 10267 | 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 | 10261 | .Float => switch (dst_ty.floatBits(self.target.*)) { |
| 10271 | 10262 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 }, |
| 10272 | 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 | 10266 | }, |
| 10276 | 10267 | else => null, |
| 10277 | 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 | 10271 | const dst_alias = dst_reg.to128(); |
| 10281 | 10272 | const src_alias = registerAlias(src_reg, src_size); |
| ... | ... | @@ -10288,13 +10279,14 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 10288 | 10279 | } |
| 10289 | 10280 | |
| 10290 | 10281 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10282 | const mod = self.bin_file.options.module.?; | |
| 10291 | 10283 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10292 | 10284 | |
| 10293 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 10294 | const dst_ty = self.air.typeOfIndex(inst); | |
| 10295 | const dst_bits = @intCast(u32, dst_ty.bitSize(self.target.*)); | |
| 10285 | const src_ty = self.typeOf(ty_op.operand); | |
| 10286 | const dst_ty = self.typeOfIndex(inst); | |
| 10287 | const dst_bits = @intCast(u32, dst_ty.bitSize(mod)); | |
| 10296 | 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 | 10291 | const dst_size = math.divCeil(u32, @max(switch (dst_signedness) { |
| 10300 | 10292 | .signed => dst_bits, |
| ... | ... | @@ -10312,13 +10304,13 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10312 | 10304 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 10313 | 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 | 10308 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 10317 | 10309 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 10318 | 10310 | defer self.register_manager.unlockReg(dst_lock); |
| 10319 | 10311 | |
| 10320 | 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 | 10314 | .Float => switch (src_ty.floatBits(self.target.*)) { |
| 10323 | 10315 | 32 => if (self.hasFeature(.avx)) .{ .v_, .cvttss2si } else .{ ._, .cvttss2si }, |
| 10324 | 10316 | 64 => if (self.hasFeature(.avx)) .{ .v_, .cvttsd2si } else .{ ._, .cvttsd2si }, |
| ... | ... | @@ -10339,12 +10331,13 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10339 | 10331 | } |
| 10340 | 10332 | |
| 10341 | 10333 | fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 10334 | const mod = self.bin_file.options.module.?; | |
| 10342 | 10335 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 10343 | 10336 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 10344 | 10337 | |
| 10345 | const ptr_ty = self.air.typeOf(extra.ptr); | |
| 10346 | const val_ty = self.air.typeOf(extra.expected_value); | |
| 10347 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); | |
| 10338 | const ptr_ty = self.typeOf(extra.ptr); | |
| 10339 | const val_ty = self.typeOf(extra.expected_value); | |
| 10340 | const val_abi_size = @intCast(u32, val_ty.abiSize(mod)); | |
| 10348 | 10341 | |
| 10349 | 10342 | try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); |
| 10350 | 10343 | const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx }); |
| ... | ... | @@ -10433,6 +10426,7 @@ fn atomicOp( |
| 10433 | 10426 | rmw_op: ?std.builtin.AtomicRmwOp, |
| 10434 | 10427 | order: std.builtin.AtomicOrder, |
| 10435 | 10428 | ) InnerError!MCValue { |
| 10429 | const mod = self.bin_file.options.module.?; | |
| 10436 | 10430 | const ptr_lock = switch (ptr_mcv) { |
| 10437 | 10431 | .register => |reg| self.register_manager.lockReg(reg), |
| 10438 | 10432 | else => null, |
| ... | ... | @@ -10445,7 +10439,7 @@ fn atomicOp( |
| 10445 | 10439 | }; |
| 10446 | 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 | 10443 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 10450 | 10444 | const ptr_mem = switch (ptr_mcv) { |
| 10451 | 10445 | .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), |
| ... | ... | @@ -10539,8 +10533,8 @@ fn atomicOp( |
| 10539 | 10533 | .Or => try self.genBinOpMir(.{ ._, .@"or" }, val_ty, tmp_mcv, val_mcv), |
| 10540 | 10534 | .Xor => try self.genBinOpMir(.{ ._, .xor }, val_ty, tmp_mcv, val_mcv), |
| 10541 | 10535 | .Min, .Max => { |
| 10542 | const cc: Condition = switch (if (val_ty.isAbiInt()) | |
| 10543 | val_ty.intInfo(self.target.*).signedness | |
| 10536 | const cc: Condition = switch (if (val_ty.isAbiInt(mod)) | |
| 10537 | val_ty.intInfo(mod).signedness | |
| 10544 | 10538 | else |
| 10545 | 10539 | .unsigned) { |
| 10546 | 10540 | .unsigned => switch (op) { |
| ... | ... | @@ -10682,10 +10676,10 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { |
| 10682 | 10676 | |
| 10683 | 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 | 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 | 10683 | const val_mcv = try self.resolveInst(extra.operand); |
| 10690 | 10684 | |
| 10691 | 10685 | const result = |
| ... | ... | @@ -10696,7 +10690,7 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { |
| 10696 | 10690 | fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 10697 | 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 | 10694 | const ptr_mcv = try self.resolveInst(atomic_load.ptr); |
| 10701 | 10695 | const ptr_lock = switch (ptr_mcv) { |
| 10702 | 10696 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -10717,10 +10711,10 @@ fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 10717 | 10711 | fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { |
| 10718 | 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 | 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 | 10718 | const val_mcv = try self.resolveInst(bin_op.rhs); |
| 10725 | 10719 | |
| 10726 | 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 | 10722 | } |
| 10729 | 10723 | |
| 10730 | 10724 | fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10725 | const mod = self.bin_file.options.module.?; | |
| 10731 | 10726 | if (safety) { |
| 10732 | 10727 | // TODO if the value is undef, write 0xaa bytes to dest |
| 10733 | 10728 | } else { |
| ... | ... | @@ -10737,7 +10732,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10737 | 10732 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 10738 | 10733 | |
| 10739 | 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 | 10736 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 10742 | 10737 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 10743 | 10738 | else => null, |
| ... | ... | @@ -10745,26 +10740,26 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10745 | 10740 | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 10746 | 10741 | |
| 10747 | 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 | 10744 | const src_val_lock: ?RegisterLock = switch (src_val) { |
| 10750 | 10745 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 10751 | 10746 | else => null, |
| 10752 | 10747 | }; |
| 10753 | 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 | 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 | 10754 | // TODO: this only handles slices stored in the stack |
| 10760 | 10755 | .Slice => dst_ptr, |
| 10761 | 10756 | .One => dst_ptr, |
| 10762 | 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 | 10760 | // TODO: this only handles slices stored in the stack |
| 10766 | 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 | 10763 | .C, .Many => unreachable, |
| 10769 | 10764 | }; |
| 10770 | 10765 | const len_lock: ?RegisterLock = switch (len) { |
| ... | ... | @@ -10780,10 +10775,9 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10780 | 10775 | // Store the first element, and then rely on memcpy copying forwards. |
| 10781 | 10776 | // Length zero requires a runtime check - so we handle arrays specially |
| 10782 | 10777 | // here to elide it. |
| 10783 | switch (dst_ptr_ty.ptrSize()) { | |
| 10778 | switch (dst_ptr_ty.ptrSize(mod)) { | |
| 10784 | 10779 | .Slice => { |
| 10785 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 10786 | const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(&buf); | |
| 10780 | const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(mod); | |
| 10787 | 10781 | |
| 10788 | 10782 | // TODO: this only handles slices stored in the stack |
| 10789 | 10783 | const ptr = dst_ptr; |
| ... | ... | @@ -10823,13 +10817,9 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10823 | 10817 | try self.performReloc(skip_reloc); |
| 10824 | 10818 | }, |
| 10825 | 10819 | .One => { |
| 10826 | var elem_ptr_pl = Type.Payload.ElemType{ | |
| 10827 | .base = .{ .tag = .single_mut_pointer }, | |
| 10828 | .data = elem_ty, | |
| 10829 | }; | |
| 10830 | const elem_ptr_ty = Type.initPayload(&elem_ptr_pl.base); | |
| 10820 | const elem_ptr_ty = try mod.singleMutPtrType(elem_ty); | |
| 10831 | 10821 | |
| 10832 | const len = dst_ptr_ty.childType().arrayLen(); | |
| 10822 | const len = dst_ptr_ty.childType(mod).arrayLen(mod); | |
| 10833 | 10823 | |
| 10834 | 10824 | assert(len != 0); // prevented by Sema |
| 10835 | 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 | 10844 | } |
| 10855 | 10845 | |
| 10856 | 10846 | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 10847 | const mod = self.bin_file.options.module.?; | |
| 10857 | 10848 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 10858 | 10849 | |
| 10859 | 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 | 10852 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 10862 | 10853 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 10863 | 10854 | else => null, |
| ... | ... | @@ -10871,9 +10862,9 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 10871 | 10862 | }; |
| 10872 | 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 | 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 | 10868 | .C, .Many => unreachable, |
| 10878 | 10869 | }; |
| 10879 | 10870 | const len_lock: ?RegisterLock = switch (len) { |
| ... | ... | @@ -10891,14 +10882,14 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 10891 | 10882 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 10892 | 10883 | const mod = self.bin_file.options.module.?; |
| 10893 | 10884 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 10894 | const inst_ty = self.air.typeOfIndex(inst); | |
| 10895 | const enum_ty = self.air.typeOf(un_op); | |
| 10885 | const inst_ty = self.typeOfIndex(inst); | |
| 10886 | const enum_ty = self.typeOf(un_op); | |
| 10896 | 10887 | |
| 10897 | 10888 | // We need a properly aligned and sized call frame to be able to call this function. |
| 10898 | 10889 | { |
| 10899 | 10890 | const needed_call_frame = FrameAlloc.init(.{ |
| 10900 | .size = inst_ty.abiSize(self.target.*), | |
| 10901 | .alignment = inst_ty.abiAlignment(self.target.*), | |
| 10891 | .size = inst_ty.abiSize(mod), | |
| 10892 | .alignment = inst_ty.abiAlignment(mod), | |
| 10902 | 10893 | }); |
| 10903 | 10894 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 10904 | 10895 | const stack_frame_size = |
| ... | ... | @@ -10923,7 +10914,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 10923 | 10914 | try self.genLazySymbolRef( |
| 10924 | 10915 | .call, |
| 10925 | 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 | 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 | 10924 | const mod = self.bin_file.options.module.?; |
| 10934 | 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 | 10928 | const err_mcv = try self.resolveInst(un_op); |
| 10938 | 10929 | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); |
| 10939 | 10930 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); |
| ... | ... | @@ -11013,17 +11004,18 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 11013 | 11004 | } |
| 11014 | 11005 | |
| 11015 | 11006 | fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 11007 | const mod = self.bin_file.options.module.?; | |
| 11016 | 11008 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 11017 | const vector_ty = self.air.typeOfIndex(inst); | |
| 11018 | const dst_rc = regClassForType(vector_ty); | |
| 11019 | const scalar_ty = vector_ty.scalarType(); | |
| 11009 | const vector_ty = self.typeOfIndex(inst); | |
| 11010 | const dst_rc = regClassForType(vector_ty, mod); | |
| 11011 | const scalar_ty = vector_ty.scalarType(mod); | |
| 11020 | 11012 | |
| 11021 | 11013 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 11022 | 11014 | const result: MCValue = result: { |
| 11023 | switch (scalar_ty.zigTypeTag()) { | |
| 11015 | switch (scalar_ty.zigTypeTag(mod)) { | |
| 11024 | 11016 | else => {}, |
| 11025 | 11017 | .Float => switch (scalar_ty.floatBits(self.target.*)) { |
| 11026 | 32 => switch (vector_ty.vectorLen()) { | |
| 11018 | 32 => switch (vector_ty.vectorLen(mod)) { | |
| 11027 | 11019 | 1 => { |
| 11028 | 11020 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 11029 | 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 | 11095 | }, |
| 11104 | 11096 | else => {}, |
| 11105 | 11097 | }, |
| 11106 | 64 => switch (vector_ty.vectorLen()) { | |
| 11098 | 64 => switch (vector_ty.vectorLen(mod)) { | |
| 11107 | 11099 | 1 => { |
| 11108 | 11100 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 11109 | 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 | 11161 | }, |
| 11170 | 11162 | else => {}, |
| 11171 | 11163 | }, |
| 11172 | 128 => switch (vector_ty.vectorLen()) { | |
| 11164 | 128 => switch (vector_ty.vectorLen(mod)) { | |
| 11173 | 11165 | 1 => { |
| 11174 | 11166 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 11175 | 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 | 11225 | } |
| 11234 | 11226 | |
| 11235 | 11227 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11236 | const result_ty = self.air.typeOfIndex(inst); | |
| 11237 | const len = @intCast(usize, result_ty.arrayLen()); | |
| 11228 | const mod = self.bin_file.options.module.?; | |
| 11229 | const result_ty = self.typeOfIndex(inst); | |
| 11230 | const len = @intCast(usize, result_ty.arrayLen(mod)); | |
| 11238 | 11231 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 11239 | 11232 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 11240 | 11233 | const result: MCValue = result: { |
| 11241 | switch (result_ty.zigTypeTag()) { | |
| 11234 | switch (result_ty.zigTypeTag(mod)) { | |
| 11242 | 11235 | .Struct => { |
| 11243 | 11236 | const frame_index = |
| 11244 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, self.target.*)); | |
| 11245 | if (result_ty.containerLayout() == .Packed) { | |
| 11246 | const struct_obj = result_ty.castTag(.@"struct").?.data; | |
| 11237 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod)); | |
| 11238 | if (result_ty.containerLayout(mod) == .Packed) { | |
| 11239 | const struct_obj = mod.typeToStruct(result_ty).?; | |
| 11247 | 11240 | try self.genInlineMemset( |
| 11248 | 11241 | .{ .lea_frame = .{ .index = frame_index } }, |
| 11249 | 11242 | .{ .immediate = 0 }, |
| 11250 | .{ .immediate = result_ty.abiSize(self.target.*) }, | |
| 11243 | .{ .immediate = result_ty.abiSize(mod) }, | |
| 11251 | 11244 | ); |
| 11252 | 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); | |
| 11256 | const elem_bit_size = @intCast(u32, elem_ty.bitSize(self.target.*)); | |
| 11248 | const elem_ty = result_ty.structFieldType(elem_i, mod); | |
| 11249 | const elem_bit_size = @intCast(u32, elem_ty.bitSize(mod)); | |
| 11257 | 11250 | if (elem_bit_size > 64) { |
| 11258 | 11251 | return self.fail( |
| 11259 | 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 | 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 | 11259 | const elem_byte_off = @intCast(i32, elem_off / elem_abi_bits * elem_abi_size); |
| 11267 | 11260 | const elem_bit_off = elem_off % elem_abi_bits; |
| 11268 | 11261 | const elem_mcv = try self.resolveInst(elem); |
| ... | ... | @@ -11322,10 +11315,10 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11322 | 11315 | } |
| 11323 | 11316 | } |
| 11324 | 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); | |
| 11328 | const elem_off = @intCast(i32, result_ty.structFieldOffset(elem_i, self.target.*)); | |
| 11320 | const elem_ty = result_ty.structFieldType(elem_i, mod); | |
| 11321 | const elem_off = @intCast(i32, result_ty.structFieldOffset(elem_i, mod)); | |
| 11329 | 11322 | const elem_mcv = try self.resolveInst(elem); |
| 11330 | 11323 | const mat_elem_mcv = switch (elem_mcv) { |
| 11331 | 11324 | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, |
| ... | ... | @@ -11337,9 +11330,9 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11337 | 11330 | }, |
| 11338 | 11331 | .Array => { |
| 11339 | 11332 | const frame_index = |
| 11340 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, self.target.*)); | |
| 11341 | const elem_ty = result_ty.childType(); | |
| 11342 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | |
| 11333 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod)); | |
| 11334 | const elem_ty = result_ty.childType(mod); | |
| 11335 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | |
| 11343 | 11336 | |
| 11344 | 11337 | for (elements, 0..) |elem, elem_i| { |
| 11345 | 11338 | const elem_mcv = try self.resolveInst(elem); |
| ... | ... | @@ -11350,7 +11343,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11350 | 11343 | const elem_off = @intCast(i32, elem_size * elem_i); |
| 11351 | 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 | 11347 | .{ .frame = frame_index }, |
| 11355 | 11348 | @intCast(i32, elem_size * elements.len), |
| 11356 | 11349 | elem_ty, |
| ... | ... | @@ -11374,13 +11367,14 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11374 | 11367 | } |
| 11375 | 11368 | |
| 11376 | 11369 | fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11370 | const mod = self.bin_file.options.module.?; | |
| 11377 | 11371 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 11378 | 11372 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 11379 | 11373 | const result: MCValue = result: { |
| 11380 | const union_ty = self.air.typeOfIndex(inst); | |
| 11381 | const layout = union_ty.unionGetLayout(self.target.*); | |
| 11374 | const union_ty = self.typeOfIndex(inst); | |
| 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 | 11378 | const src_mcv = try self.resolveInst(extra.init); |
| 11385 | 11379 | if (layout.tag_size == 0) { |
| 11386 | 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 | 11386 | |
| 11393 | 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 | 11390 | const field_name = union_obj.fields.keys()[extra.field_index]; |
| 11397 | const tag_ty = union_ty.unionTagTypeSafety().?; | |
| 11398 | const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); | |
| 11399 | var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index }; | |
| 11400 | const tag_val = Value.initPayload(&tag_pl.base); | |
| 11401 | var tag_int_pl: Value.Payload.U64 = undefined; | |
| 11402 | const tag_int_val = tag_val.enumToInt(tag_ty, &tag_int_pl); | |
| 11403 | const tag_int = tag_int_val.toUnsignedInt(self.target.*); | |
| 11391 | const tag_ty = union_obj.tag_ty; | |
| 11392 | const field_index = tag_ty.enumFieldIndex(field_name, mod).?; | |
| 11393 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); | |
| 11394 | const tag_int_val = try tag_val.enumToInt(tag_ty, mod); | |
| 11395 | const tag_int = tag_int_val.toUnsignedInt(mod); | |
| 11404 | 11396 | const tag_off = if (layout.tag_align < layout.payload_align) |
| 11405 | 11397 | @intCast(i32, layout.payload_size) |
| 11406 | 11398 | else |
| ... | ... | @@ -11424,9 +11416,10 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { |
| 11424 | 11416 | } |
| 11425 | 11417 | |
| 11426 | 11418 | fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11419 | const mod = self.bin_file.options.module.?; | |
| 11427 | 11420 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 11428 | 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 | 11424 | if (!self.hasFeature(.fma)) return self.fail("TODO implement airMulAdd for {}", .{ |
| 11432 | 11425 | ty.fmt(self.bin_file.options.module.?), |
| ... | ... | @@ -11466,21 +11459,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11466 | 11459 | const mir_tag = if (@as( |
| 11467 | 11460 | ?Mir.Inst.FixedTag, |
| 11468 | 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 | 11463 | .Float => switch (ty.floatBits(self.target.*)) { |
| 11471 | 11464 | 32 => .{ .v_ss, .fmadd132 }, |
| 11472 | 11465 | 64 => .{ .v_sd, .fmadd132 }, |
| 11473 | 11466 | 16, 80, 128 => null, |
| 11474 | 11467 | else => unreachable, |
| 11475 | 11468 | }, |
| 11476 | .Vector => switch (ty.childType().zigTypeTag()) { | |
| 11477 | .Float => switch (ty.childType().floatBits(self.target.*)) { | |
| 11478 | 32 => switch (ty.vectorLen()) { | |
| 11469 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { | |
| 11470 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { | |
| 11471 | 32 => switch (ty.vectorLen(mod)) { | |
| 11479 | 11472 | 1 => .{ .v_ss, .fmadd132 }, |
| 11480 | 11473 | 2...8 => .{ .v_ps, .fmadd132 }, |
| 11481 | 11474 | else => null, |
| 11482 | 11475 | }, |
| 11483 | 64 => switch (ty.vectorLen()) { | |
| 11476 | 64 => switch (ty.vectorLen(mod)) { | |
| 11484 | 11477 | 1 => .{ .v_sd, .fmadd132 }, |
| 11485 | 11478 | 2...4 => .{ .v_pd, .fmadd132 }, |
| 11486 | 11479 | else => null, |
| ... | ... | @@ -11493,21 +11486,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11493 | 11486 | else => unreachable, |
| 11494 | 11487 | } |
| 11495 | 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 | 11490 | .Float => switch (ty.floatBits(self.target.*)) { |
| 11498 | 11491 | 32 => .{ .v_ss, .fmadd213 }, |
| 11499 | 11492 | 64 => .{ .v_sd, .fmadd213 }, |
| 11500 | 11493 | 16, 80, 128 => null, |
| 11501 | 11494 | else => unreachable, |
| 11502 | 11495 | }, |
| 11503 | .Vector => switch (ty.childType().zigTypeTag()) { | |
| 11504 | .Float => switch (ty.childType().floatBits(self.target.*)) { | |
| 11505 | 32 => switch (ty.vectorLen()) { | |
| 11496 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { | |
| 11497 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { | |
| 11498 | 32 => switch (ty.vectorLen(mod)) { | |
| 11506 | 11499 | 1 => .{ .v_ss, .fmadd213 }, |
| 11507 | 11500 | 2...8 => .{ .v_ps, .fmadd213 }, |
| 11508 | 11501 | else => null, |
| 11509 | 11502 | }, |
| 11510 | 64 => switch (ty.vectorLen()) { | |
| 11503 | 64 => switch (ty.vectorLen(mod)) { | |
| 11511 | 11504 | 1 => .{ .v_sd, .fmadd213 }, |
| 11512 | 11505 | 2...4 => .{ .v_pd, .fmadd213 }, |
| 11513 | 11506 | else => null, |
| ... | ... | @@ -11520,21 +11513,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11520 | 11513 | else => unreachable, |
| 11521 | 11514 | } |
| 11522 | 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 | 11517 | .Float => switch (ty.floatBits(self.target.*)) { |
| 11525 | 11518 | 32 => .{ .v_ss, .fmadd231 }, |
| 11526 | 11519 | 64 => .{ .v_sd, .fmadd231 }, |
| 11527 | 11520 | 16, 80, 128 => null, |
| 11528 | 11521 | else => unreachable, |
| 11529 | 11522 | }, |
| 11530 | .Vector => switch (ty.childType().zigTypeTag()) { | |
| 11531 | .Float => switch (ty.childType().floatBits(self.target.*)) { | |
| 11532 | 32 => switch (ty.vectorLen()) { | |
| 11523 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { | |
| 11524 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { | |
| 11525 | 32 => switch (ty.vectorLen(mod)) { | |
| 11533 | 11526 | 1 => .{ .v_ss, .fmadd231 }, |
| 11534 | 11527 | 2...8 => .{ .v_ps, .fmadd231 }, |
| 11535 | 11528 | else => null, |
| 11536 | 11529 | }, |
| 11537 | 64 => switch (ty.vectorLen()) { | |
| 11530 | 64 => switch (ty.vectorLen(mod)) { | |
| 11538 | 11531 | 1 => .{ .v_sd, .fmadd231 }, |
| 11539 | 11532 | 2...4 => .{ .v_pd, .fmadd231 }, |
| 11540 | 11533 | else => null, |
| ... | ... | @@ -11555,7 +11548,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11555 | 11548 | var mops: [3]MCValue = undefined; |
| 11556 | 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 | 11552 | const mop1_reg = registerAlias(mops[0].getReg().?, abi_size); |
| 11560 | 11553 | const mop2_reg = registerAlias(mops[1].getReg().?, abi_size); |
| 11561 | 11554 | if (mops[2].isRegister()) try self.asmRegisterRegisterRegister( |
| ... | ... | @@ -11573,22 +11566,22 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11573 | 11566 | } |
| 11574 | 11567 | |
| 11575 | 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 | 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 | 11575 | if (Air.refToIndex(ref)) |inst| { |
| 11582 | 11576 | const mcv = switch (self.air.instructions.items(.tag)[inst]) { |
| 11583 | .constant => tracking: { | |
| 11577 | .interned => tracking: { | |
| 11584 | 11578 | const gop = try self.const_tracking.getOrPut(self.gpa, inst); |
| 11585 | 11579 | if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{ |
| 11586 | 11580 | .ty = ty, |
| 11587 | .val = self.air.value(ref).?, | |
| 11581 | .val = self.air.instructions.items(.data)[inst].interned.toValue(), | |
| 11588 | 11582 | })); |
| 11589 | 11583 | break :tracking gop.value_ptr; |
| 11590 | 11584 | }, |
| 11591 | .const_ty => unreachable, | |
| 11592 | 11585 | else => self.inst_tracking.getPtr(inst).?, |
| 11593 | 11586 | }.short; |
| 11594 | 11587 | switch (mcv) { |
| ... | ... | @@ -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 | 11596 | fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking { |
| 11604 | 11597 | const tracking = switch (self.air.instructions.items(.tag)[inst]) { |
| 11605 | .constant => &self.const_tracking, | |
| 11606 | .const_ty => unreachable, | |
| 11598 | .interned => &self.const_tracking, | |
| 11607 | 11599 | else => &self.inst_tracking, |
| 11608 | 11600 | }.getPtr(inst).?; |
| 11609 | 11601 | return switch (tracking.short) { |
| ... | ... | @@ -11634,7 +11626,8 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV |
| 11634 | 11626 | } |
| 11635 | 11627 | |
| 11636 | 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 | 11631 | .mcv => |mcv| switch (mcv) { |
| 11639 | 11632 | .none => .none, |
| 11640 | 11633 | .undef => .undef, |
| ... | ... | @@ -11666,17 +11659,23 @@ const CallMCValues = struct { |
| 11666 | 11659 | /// Caller must call `CallMCValues.deinit`. |
| 11667 | 11660 | fn resolveCallingConventionValues( |
| 11668 | 11661 | self: *Self, |
| 11669 | fn_ty: Type, | |
| 11662 | fn_info: InternPool.Key.FuncType, | |
| 11670 | 11663 | var_args: []const Air.Inst.Ref, |
| 11671 | 11664 | stack_frame_base: FrameIndex, |
| 11672 | 11665 | ) !CallMCValues { |
| 11673 | const cc = fn_ty.fnCallingConvention(); | |
| 11674 | const param_len = fn_ty.fnParamLen(); | |
| 11675 | const param_types = try self.gpa.alloc(Type, param_len + var_args.len); | |
| 11666 | const mod = self.bin_file.options.module.?; | |
| 11667 | const cc = fn_info.cc; | |
| 11668 | const param_types = try self.gpa.alloc(Type, fn_info.param_types.len + var_args.len); | |
| 11676 | 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 | 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 | 11679 | var result: CallMCValues = .{ |
| 11681 | 11680 | .args = try self.gpa.alloc(MCValue, param_types.len), |
| 11682 | 11681 | // These undefined values must be populated before returning from this function. |
| ... | ... | @@ -11686,7 +11685,7 @@ fn resolveCallingConventionValues( |
| 11686 | 11685 | }; |
| 11687 | 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 | 11690 | switch (cc) { |
| 11692 | 11691 | .Naked => { |
| ... | ... | @@ -11702,21 +11701,21 @@ fn resolveCallingConventionValues( |
| 11702 | 11701 | switch (self.target.os.tag) { |
| 11703 | 11702 | .windows => { |
| 11704 | 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 | 11706 | else => {}, |
| 11708 | 11707 | } |
| 11709 | 11708 | |
| 11710 | 11709 | // Return values |
| 11711 | if (ret_ty.zigTypeTag() == .NoReturn) { | |
| 11710 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { | |
| 11712 | 11711 | result.return_value = InstTracking.init(.unreach); |
| 11713 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 11712 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 11714 | 11713 | // TODO: is this even possible for C calling convention? |
| 11715 | 11714 | result.return_value = InstTracking.init(.none); |
| 11716 | 11715 | } else { |
| 11717 | 11716 | const classes = switch (self.target.os.tag) { |
| 11718 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, self.target.*)}, | |
| 11719 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, self.target.*, .ret), .none), | |
| 11717 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, | |
| 11718 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), | |
| 11720 | 11719 | }; |
| 11721 | 11720 | if (classes.len > 1) { |
| 11722 | 11721 | return self.fail("TODO handle multiple classes per type", .{}); |
| ... | ... | @@ -11725,7 +11724,7 @@ fn resolveCallingConventionValues( |
| 11725 | 11724 | result.return_value = switch (classes[0]) { |
| 11726 | 11725 | .integer => InstTracking.init(.{ .register = registerAlias( |
| 11727 | 11726 | ret_reg, |
| 11728 | @intCast(u32, ret_ty.abiSize(self.target.*)), | |
| 11727 | @intCast(u32, ret_ty.abiSize(mod)), | |
| 11729 | 11728 | ) }), |
| 11730 | 11729 | .float, .sse => InstTracking.init(.{ .register = .xmm0 }), |
| 11731 | 11730 | .memory => ret: { |
| ... | ... | @@ -11744,11 +11743,11 @@ fn resolveCallingConventionValues( |
| 11744 | 11743 | |
| 11745 | 11744 | // Input params |
| 11746 | 11745 | for (param_types, result.args) |ty, *arg| { |
| 11747 | assert(ty.hasRuntimeBitsIgnoreComptime()); | |
| 11746 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); | |
| 11748 | 11747 | |
| 11749 | 11748 | const classes = switch (self.target.os.tag) { |
| 11750 | .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)}, | |
| 11751 | else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none), | |
| 11749 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, | |
| 11750 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), | |
| 11752 | 11751 | }; |
| 11753 | 11752 | if (classes.len > 1) { |
| 11754 | 11753 | return self.fail("TODO handle multiple classes per type", .{}); |
| ... | ... | @@ -11783,8 +11782,8 @@ fn resolveCallingConventionValues( |
| 11783 | 11782 | }), |
| 11784 | 11783 | } |
| 11785 | 11784 | |
| 11786 | const param_size = @intCast(u31, ty.abiSize(self.target.*)); | |
| 11787 | const param_align = @intCast(u31, ty.abiAlignment(self.target.*)); | |
| 11785 | const param_size = @intCast(u31, ty.abiSize(mod)); | |
| 11786 | const param_align = @intCast(u31, ty.abiAlignment(mod)); | |
| 11788 | 11787 | result.stack_byte_count = |
| 11789 | 11788 | mem.alignForwardGeneric(u31, result.stack_byte_count, param_align); |
| 11790 | 11789 | arg.* = .{ .load_frame = .{ |
| ... | ... | @@ -11798,13 +11797,13 @@ fn resolveCallingConventionValues( |
| 11798 | 11797 | result.stack_align = 16; |
| 11799 | 11798 | |
| 11800 | 11799 | // Return values |
| 11801 | if (ret_ty.zigTypeTag() == .NoReturn) { | |
| 11800 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { | |
| 11802 | 11801 | result.return_value = InstTracking.init(.unreach); |
| 11803 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 11802 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 11804 | 11803 | result.return_value = InstTracking.init(.none); |
| 11805 | 11804 | } else { |
| 11806 | 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 | 11807 | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { |
| 11809 | 11808 | const aliased_reg = registerAlias(ret_reg, ret_ty_size); |
| 11810 | 11809 | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; |
| ... | ... | @@ -11819,12 +11818,12 @@ fn resolveCallingConventionValues( |
| 11819 | 11818 | |
| 11820 | 11819 | // Input params |
| 11821 | 11820 | for (param_types, result.args) |ty, *arg| { |
| 11822 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | |
| 11821 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 11823 | 11822 | arg.* = .none; |
| 11824 | 11823 | continue; |
| 11825 | 11824 | } |
| 11826 | const param_size = @intCast(u31, ty.abiSize(self.target.*)); | |
| 11827 | const param_align = @intCast(u31, ty.abiAlignment(self.target.*)); | |
| 11825 | const param_size = @intCast(u31, ty.abiSize(mod)); | |
| 11826 | const param_align = @intCast(u31, ty.abiAlignment(mod)); | |
| 11828 | 11827 | result.stack_byte_count = |
| 11829 | 11828 | mem.alignForwardGeneric(u31, result.stack_byte_count, param_align); |
| 11830 | 11829 | arg.* = .{ .load_frame = .{ |
| ... | ... | @@ -11908,9 +11907,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 11908 | 11907 | /// Truncates the value in the register in place. |
| 11909 | 11908 | /// Clobbers any remaining bits. |
| 11910 | 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 | 11912 | .signedness = .unsigned, |
| 11913 | .bits = @intCast(u16, ty.bitSize(self.target.*)), | |
| 11913 | .bits = @intCast(u16, ty.bitSize(mod)), | |
| 11914 | 11914 | }; |
| 11915 | 11915 | const max_reg_bit_width = Register.rax.bitSize(); |
| 11916 | 11916 | switch (int_info.signedness) { |
| ... | ... | @@ -11953,8 +11953,9 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 11953 | 11953 | } |
| 11954 | 11954 | |
| 11955 | 11955 | fn regBitSize(self: *Self, ty: Type) u64 { |
| 11956 | const abi_size = ty.abiSize(self.target.*); | |
| 11957 | return switch (ty.zigTypeTag()) { | |
| 11956 | const mod = self.bin_file.options.module.?; | |
| 11957 | const abi_size = ty.abiSize(mod); | |
| 11958 | return switch (ty.zigTypeTag(mod)) { | |
| 11958 | 11959 | else => switch (abi_size) { |
| 11959 | 11960 | 1 => 8, |
| 11960 | 11961 | 2 => 16, |
| ... | ... | @@ -11971,7 +11972,8 @@ fn regBitSize(self: *Self, ty: Type) u64 { |
| 11971 | 11972 | } |
| 11972 | 11973 | |
| 11973 | 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 | 11979 | fn hasFeature(self: *Self, feature: Target.x86.Feature) bool { |
| ... | ... | @@ -11983,3 +11985,13 @@ fn hasAnyFeatures(self: *Self, features: anytype) bool { |
| 11983 | 11985 | fn hasAllFeatures(self: *Self, features: anytype) bool { |
| 11984 | 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 | 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 | 1 | pub const Class = enum { |
| 9 | 2 | integer, |
| 10 | 3 | sse, |
| ... | ... | @@ -19,7 +12,7 @@ pub const Class = enum { |
| 19 | 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 | 16 | // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 |
| 24 | 17 | // "There's a strict one-to-one correspondence between a function call's arguments |
| 25 | 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 | 21 | // "All floating point operations are done using the 16 XMM registers." |
| 29 | 22 | // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed |
| 30 | 23 | // as if they were integers of the same size." |
| 31 | switch (ty.zigTypeTag()) { | |
| 24 | switch (ty.zigTypeTag(mod)) { | |
| 32 | 25 | .Pointer, |
| 33 | 26 | .Int, |
| 34 | 27 | .Bool, |
| ... | ... | @@ -43,12 +36,12 @@ pub fn classifyWindows(ty: Type, target: Target) Class { |
| 43 | 36 | .ErrorUnion, |
| 44 | 37 | .AnyFrame, |
| 45 | 38 | .Frame, |
| 46 | => switch (ty.abiSize(target)) { | |
| 39 | => switch (ty.abiSize(mod)) { | |
| 47 | 40 | 0 => unreachable, |
| 48 | 41 | 1, 2, 4, 8 => return .integer, |
| 49 | else => switch (ty.zigTypeTag()) { | |
| 42 | else => switch (ty.zigTypeTag(mod)) { | |
| 50 | 43 | .Int => return .win_i128, |
| 51 | .Struct, .Union => if (ty.containerLayout() == .Packed) { | |
| 44 | .Struct, .Union => if (ty.containerLayout(mod) == .Packed) { | |
| 52 | 45 | return .win_i128; |
| 53 | 46 | } else { |
| 54 | 47 | return .memory; |
| ... | ... | @@ -75,14 +68,15 @@ pub const Context = enum { ret, arg, other }; |
| 75 | 68 | |
| 76 | 69 | /// There are a maximum of 8 possible return slots. Returned values are in |
| 77 | 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 | 73 | const memory_class = [_]Class{ |
| 80 | 74 | .memory, .none, .none, .none, |
| 81 | 75 | .none, .none, .none, .none, |
| 82 | 76 | }; |
| 83 | 77 | var result = [1]Class{.none} ** 8; |
| 84 | switch (ty.zigTypeTag()) { | |
| 85 | .Pointer => switch (ty.ptrSize()) { | |
| 78 | switch (ty.zigTypeTag(mod)) { | |
| 79 | .Pointer => switch (ty.ptrSize(mod)) { | |
| 86 | 80 | .Slice => { |
| 87 | 81 | result[0] = .integer; |
| 88 | 82 | result[1] = .integer; |
| ... | ... | @@ -94,7 +88,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 94 | 88 | }, |
| 95 | 89 | }, |
| 96 | 90 | .Int, .Enum, .ErrorSet => { |
| 97 | const bits = ty.intInfo(target).bits; | |
| 91 | const bits = ty.intInfo(mod).bits; | |
| 98 | 92 | if (bits <= 64) { |
| 99 | 93 | result[0] = .integer; |
| 100 | 94 | return result; |
| ... | ... | @@ -164,8 +158,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 164 | 158 | else => unreachable, |
| 165 | 159 | }, |
| 166 | 160 | .Vector => { |
| 167 | const elem_ty = ty.childType(); | |
| 168 | const bits = elem_ty.bitSize(target) * ty.arrayLen(); | |
| 161 | const elem_ty = ty.childType(mod); | |
| 162 | const bits = elem_ty.bitSize(mod) * ty.arrayLen(mod); | |
| 169 | 163 | if (bits <= 64) return .{ |
| 170 | 164 | .sse, .none, .none, .none, |
| 171 | 165 | .none, .none, .none, .none, |
| ... | ... | @@ -204,7 +198,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 204 | 198 | return memory_class; |
| 205 | 199 | }, |
| 206 | 200 | .Optional => { |
| 207 | if (ty.isPtrLikeOptional()) { | |
| 201 | if (ty.isPtrLikeOptional(mod)) { | |
| 208 | 202 | result[0] = .integer; |
| 209 | 203 | return result; |
| 210 | 204 | } |
| ... | ... | @@ -215,8 +209,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 215 | 209 | // it contains unaligned fields, it has class MEMORY" |
| 216 | 210 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 217 | 211 | // separately.". |
| 218 | const ty_size = ty.abiSize(target); | |
| 219 | if (ty.containerLayout() == .Packed) { | |
| 212 | const ty_size = ty.abiSize(mod); | |
| 213 | if (ty.containerLayout(mod) == .Packed) { | |
| 220 | 214 | assert(ty_size <= 128); |
| 221 | 215 | result[0] = .integer; |
| 222 | 216 | if (ty_size > 64) result[1] = .integer; |
| ... | ... | @@ -227,15 +221,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 227 | 221 | |
| 228 | 222 | var result_i: usize = 0; // out of 8 |
| 229 | 223 | var byte_i: usize = 0; // out of 8 |
| 230 | const fields = ty.structFields(); | |
| 224 | const fields = ty.structFields(mod); | |
| 231 | 225 | for (fields.values()) |field| { |
| 232 | 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 | 228 | return memory_class; |
| 235 | 229 | } |
| 236 | 230 | } |
| 237 | const field_size = field.ty.abiSize(target); | |
| 238 | const field_class_array = classifySystemV(field.ty, target, .other); | |
| 231 | const field_size = field.ty.abiSize(mod); | |
| 232 | const field_class_array = classifySystemV(field.ty, mod, .other); | |
| 239 | 233 | const field_class = std.mem.sliceTo(&field_class_array, .none); |
| 240 | 234 | if (byte_i + field_size <= 8) { |
| 241 | 235 | // Combine this field with the previous one. |
| ... | ... | @@ -334,8 +328,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 334 | 328 | // it contains unaligned fields, it has class MEMORY" |
| 335 | 329 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 336 | 330 | // separately.". |
| 337 | const ty_size = ty.abiSize(target); | |
| 338 | if (ty.containerLayout() == .Packed) { | |
| 331 | const ty_size = ty.abiSize(mod); | |
| 332 | if (ty.containerLayout(mod) == .Packed) { | |
| 339 | 333 | assert(ty_size <= 128); |
| 340 | 334 | result[0] = .integer; |
| 341 | 335 | if (ty_size > 64) result[1] = .integer; |
| ... | ... | @@ -344,15 +338,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 344 | 338 | if (ty_size > 64) |
| 345 | 339 | return memory_class; |
| 346 | 340 | |
| 347 | const fields = ty.unionFields(); | |
| 341 | const fields = ty.unionFields(mod); | |
| 348 | 342 | for (fields.values()) |field| { |
| 349 | 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 | 345 | return memory_class; |
| 352 | 346 | } |
| 353 | 347 | } |
| 354 | 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 | 350 | for (&result, 0..) |*result_item, i| { |
| 357 | 351 | const field_item = field_class[i]; |
| 358 | 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 | 420 | return result; |
| 427 | 421 | }, |
| 428 | 422 | .Array => { |
| 429 | const ty_size = ty.abiSize(target); | |
| 423 | const ty_size = ty.abiSize(mod); | |
| 430 | 424 | if (ty_size <= 64) { |
| 431 | 425 | result[0] = .integer; |
| 432 | 426 | return result; |
| ... | ... | @@ -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 | 528 | const testing = std.testing; |
| 529 | ||
| 531 | 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 | 534 | const Value = @import("../../value.zig").Value; |
| 533 | const builtin = @import("builtin"); | |
| 534 | 535 | |
| 535 | 536 | fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field { |
| 536 | 537 | return .{ |
| ... | ... | @@ -541,34 +542,3 @@ fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field { |
| 541 | 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 | 14 | const Allocator = mem.Allocator; |
| 15 | 15 | const Compilation = @import("Compilation.zig"); |
| 16 | 16 | const ErrorMsg = Module.ErrorMsg; |
| 17 | const InternPool = @import("InternPool.zig"); | |
| 17 | 18 | const Liveness = @import("Liveness.zig"); |
| 18 | 19 | const Module = @import("Module.zig"); |
| 19 | 20 | const Target = std.Target; |
| ... | ... | @@ -66,7 +67,7 @@ pub const DebugInfoOutput = union(enum) { |
| 66 | 67 | pub fn generateFunction( |
| 67 | 68 | bin_file: *link.File, |
| 68 | 69 | src_loc: Module.SrcLoc, |
| 69 | func: *Module.Fn, | |
| 70 | func_index: Module.Fn.Index, | |
| 70 | 71 | air: Air, |
| 71 | 72 | liveness: Liveness, |
| 72 | 73 | code: *std.ArrayList(u8), |
| ... | ... | @@ -75,17 +76,17 @@ pub fn generateFunction( |
| 75 | 76 | switch (bin_file.options.target.cpu.arch) { |
| 76 | 77 | .arm, |
| 77 | 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 | 80 | .aarch64, |
| 80 | 81 | .aarch64_be, |
| 81 | 82 | .aarch64_32, |
| 82 | => return @import("arch/aarch64/CodeGen.zig").generate(bin_file, src_loc, func, 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 | .sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(bin_file, src_loc, func, 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), | |
| 83 | => return @import("arch/aarch64/CodeGen.zig").generate(bin_file, src_loc, func_index, 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), | |
| 85 | .sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(bin_file, src_loc, func_index, 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 | 87 | .wasm32, |
| 87 | 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 | 90 | else => unreachable, |
| 90 | 91 | } |
| 91 | 92 | } |
| ... | ... | @@ -139,13 +140,14 @@ pub fn generateLazySymbol( |
| 139 | 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 | 144 | alignment.* = 4; |
| 144 | const err_names = mod.error_name_list.items; | |
| 145 | const err_names = mod.global_error_set.keys(); | |
| 145 | 146 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); |
| 146 | 147 | var offset = code.items.len; |
| 147 | 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 | 151 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); |
| 150 | 152 | offset += 4; |
| 151 | 153 | try code.ensureUnusedCapacity(err_name.len + 1); |
| ... | ... | @@ -154,9 +156,10 @@ pub fn generateLazySymbol( |
| 154 | 156 | } |
| 155 | 157 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); |
| 156 | 158 | return Result.ok; |
| 157 | } else if (lazy_sym.ty.zigTypeTag() == .Enum) { | |
| 159 | } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) { | |
| 158 | 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 | 163 | try code.ensureUnusedCapacity(tag_name.len + 1); |
| 161 | 164 | code.appendSliceAssumeCapacity(tag_name); |
| 162 | 165 | code.appendAssumeCapacity(0); |
| ... | ... | @@ -181,749 +184,512 @@ pub fn generateSymbol( |
| 181 | 184 | const tracy = trace(@src()); |
| 182 | 185 | defer tracy.end(); |
| 183 | 186 | |
| 187 | const mod = bin_file.options.module.?; | |
| 184 | 188 | var typed_value = arg_tv; |
| 185 | if (arg_tv.val.castTag(.runtime_value)) |rt| { | |
| 186 | typed_value.val = rt.data; | |
| 189 | switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { | |
| 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 | 195 | const endian = target.cpu.arch.endian(); |
| 191 | 196 | |
| 192 | const mod = bin_file.options.module.?; | |
| 193 | 197 | log.debug("generateSymbol: ty = {}, val = {}", .{ |
| 194 | 198 | typed_value.ty.fmt(mod), |
| 195 | 199 | typed_value.val.fmtValue(typed_value.ty, mod), |
| 196 | 200 | }); |
| 197 | 201 | |
| 198 | if (typed_value.val.isUndefDeep()) { | |
| 199 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | |
| 202 | if (typed_value.val.isUndefDeep(mod)) { | |
| 203 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | |
| 200 | 204 | try code.appendNTimes(0xaa, abi_size); |
| 201 | return Result.ok; | |
| 205 | return .ok; | |
| 202 | 206 | } |
| 203 | 207 | |
| 204 | switch (typed_value.ty.zigTypeTag()) { | |
| 205 | .Fn => { | |
| 206 | return Result{ | |
| 207 | .fail = try ErrorMsg.create( | |
| 208 | bin_file.allocator, | |
| 209 | src_loc, | |
| 210 | "TODO implement generateSymbol function pointers", | |
| 211 | .{}, | |
| 212 | ), | |
| 213 | }; | |
| 214 | }, | |
| 215 | .Float => { | |
| 216 | switch (typed_value.ty.floatBits(target)) { | |
| 217 | 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)), | |
| 218 | 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)), | |
| 219 | 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)), | |
| 220 | 80 => { | |
| 221 | writeFloat(f80, typed_value.val.toFloat(f80), target, endian, try code.addManyAsArray(10)); | |
| 222 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | |
| 223 | try code.appendNTimes(0, abi_size - 10); | |
| 224 | }, | |
| 225 | 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)), | |
| 208 | switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { | |
| 209 | .int_type, | |
| 210 | .ptr_type, | |
| 211 | .array_type, | |
| 212 | .vector_type, | |
| 213 | .opt_type, | |
| 214 | .anyframe_type, | |
| 215 | .error_union_type, | |
| 216 | .simple_type, | |
| 217 | .struct_type, | |
| 218 | .anon_struct_type, | |
| 219 | .union_type, | |
| 220 | .opaque_type, | |
| 221 | .enum_type, | |
| 222 | .func_type, | |
| 223 | .error_set_type, | |
| 224 | .inferred_error_set_type, | |
| 225 | => unreachable, // types, not values | |
| 226 | ||
| 227 | .undef, .runtime_value => unreachable, // handled above | |
| 228 | .simple_value => |simple_value| switch (simple_value) { | |
| 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 | 239 | else => unreachable, |
| 227 | } | |
| 228 | return Result.ok; | |
| 240 | }), | |
| 229 | 241 | }, |
| 230 | .Array => switch (typed_value.val.tag()) { | |
| 231 | .bytes => { | |
| 232 | const bytes = typed_value.val.castTag(.bytes).?.data; | |
| 233 | const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel()); | |
| 234 | // The bytes payload already includes the sentinel, if any | |
| 235 | try code.ensureUnusedCapacity(len); | |
| 236 | code.appendSliceAssumeCapacity(bytes[0..len]); | |
| 237 | return Result.ok; | |
| 238 | }, | |
| 239 | .str_lit => { | |
| 240 | const str_lit = typed_value.val.castTag(.str_lit).?.data; | |
| 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 | }, | |
| 242 | .variable, | |
| 243 | .extern_func, | |
| 244 | .func, | |
| 245 | .enum_literal, | |
| 246 | .empty_enum_value, | |
| 247 | => unreachable, // non-runtime values | |
| 248 | .int => { | |
| 249 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | |
| 250 | var space: Value.BigIntSpace = undefined; | |
| 251 | const val = typed_value.val.toBigInt(&space, mod); | |
| 252 | val.writeTwosComplement(try code.addManyAsSlice(abi_size), endian); | |
| 314 | 253 | }, |
| 315 | .Pointer => switch (typed_value.val.tag()) { | |
| 316 | .null_value => { | |
| 317 | switch (target.ptrBitWidth()) { | |
| 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 | }, | |
| 254 | .err => |err| { | |
| 255 | const int = try mod.getErrorValue(err.name); | |
| 256 | try code.writer().writeInt(u16, @intCast(u16, int), endian); | |
| 400 | 257 | }, |
| 401 | .Int => { | |
| 402 | const info = typed_value.ty.intInfo(target); | |
| 403 | if (info.bits <= 8) { | |
| 404 | const x: u8 = switch (info.signedness) { | |
| 405 | .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)), | |
| 406 | .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(target))), | |
| 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 | } | |
| 258 | .error_union => |error_union| { | |
| 259 | const payload_ty = typed_value.ty.errorUnionPayload(mod); | |
| 260 | const err_val = switch (error_union.val) { | |
| 261 | .err_name => |err_name| @intCast(u16, try mod.getErrorValue(err_name)), | |
| 262 | .payload => @as(u16, 0), | |
| 263 | }; | |
| 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; | |
| 536 | const field_vals = typed_value.val.castTag(.aggregate).?.data; | |
| 537 | for (field_vals, 0..) |field_val, index| { | |
| 538 | const field_ty = typed_value.ty.structFieldType(index); | |
| 539 | if (!field_ty.hasRuntimeBits()) continue; | |
| 270 | const payload_align = payload_ty.abiAlignment(mod); | |
| 271 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 272 | const abi_align = typed_value.ty.abiAlignment(mod); | |
| 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 | 282 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 542 | .ty = field_ty, | |
| 543 | .val = field_val, | |
| 283 | .ty = payload_ty, | |
| 284 | .val = switch (error_union.val) { | |
| 285 | .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), | |
| 286 | .payload => |payload| payload, | |
| 287 | }.toValue(), | |
| 544 | 288 | }, code, debug_output, reloc_info)) { |
| 545 | 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; | |
| 549 | ||
| 550 | // Pad struct members if required | |
| 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; | |
| 292 | const unpadded_end = code.items.len - begin; | |
| 293 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | |
| 294 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | |
| 553 | 295 | |
| 554 | 296 | if (padding > 0) { |
| 555 | 297 | try code.writer().writeByteNTimes(0, padding); |
| 556 | 298 | } |
| 557 | 299 | } |
| 558 | 300 | |
| 559 | return Result.ok; | |
| 560 | }, | |
| 561 | .Union => { | |
| 562 | const union_obj = typed_value.val.castTag(.@"union").?.data; | |
| 563 | const layout = typed_value.ty.unionGetLayout(target); | |
| 564 | ||
| 565 | if (layout.payload_size == 0) { | |
| 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 | } | |
| 301 | // Payload size is larger than error set, so emit our error set last | |
| 302 | if (error_align <= payload_align) { | |
| 303 | const begin = code.items.len; | |
| 304 | try code.writer().writeInt(u16, err_val, endian); | |
| 305 | const unpadded_end = code.items.len - begin; | |
| 306 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | |
| 307 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | |
| 597 | 308 | |
| 598 | const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(target)) orelse return error.Overflow; | |
| 599 | 309 | if (padding > 0) { |
| 600 | 310 | try code.writer().writeByteNTimes(0, padding); |
| 601 | 311 | } |
| 602 | 312 | } |
| 603 | ||
| 604 | if (layout.tag_size > 0) { | |
| 313 | }, | |
| 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 | 346 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 606 | .ty = union_ty.tag_ty, | |
| 607 | .val = union_obj.tag, | |
| 347 | .ty = Type.usize, | |
| 348 | .val = ptr.len.toValue(), | |
| 608 | 349 | }, code, debug_output, reloc_info)) { |
| 609 | 350 | .ok => {}, |
| 610 | 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 => { | |
| 621 | var opt_buf: Type.Payload.ElemType = undefined; | |
| 622 | const payload_type = typed_value.ty.optionalChild(&opt_buf); | |
| 623 | const is_pl = !typed_value.val.isNull(); | |
| 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 | } | |
| 355 | .opt => { | |
| 356 | const payload_type = typed_value.ty.optionalChild(mod); | |
| 357 | const payload_val = typed_value.val.optionalValue(mod); | |
| 358 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | |
| 630 | 359 | |
| 631 | if (typed_value.ty.optionalReprIsPayload()) { | |
| 632 | if (typed_value.val.castTag(.opt_payload)) |payload| { | |
| 360 | if (typed_value.ty.optionalReprIsPayload(mod)) { | |
| 361 | if (payload_val) |value| { | |
| 633 | 362 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 634 | 363 | .ty = payload_type, |
| 635 | .val = payload.data, | |
| 364 | .val = value, | |
| 636 | 365 | }, code, debug_output, reloc_info)) { |
| 637 | 366 | .ok => {}, |
| 638 | 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 | 376 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 642 | 377 | .ty = payload_type, |
| 643 | .val = typed_value.val, | |
| 378 | .val = value, | |
| 644 | 379 | }, code, debug_output, reloc_info)) { |
| 645 | 380 | .ok => {}, |
| 646 | 381 | .fail => |em| return Result{ .fail = em }, |
| 647 | 382 | } |
| 648 | } else { | |
| 649 | try code.writer().writeByteNTimes(0, abi_size); | |
| 650 | 383 | } |
| 651 | ||
| 652 | return Result.ok; | |
| 384 | try code.writer().writeByte(@boolToInt(payload_val != null)); | |
| 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; | |
| 656 | const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef); | |
| 657 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 658 | .ty = payload_type, | |
| 659 | .val = value, | |
| 660 | }, code, debug_output, reloc_info)) { | |
| 661 | .ok => {}, | |
| 662 | .fail => |em| return Result{ .fail = em }, | |
| 663 | } | |
| 664 | try code.writer().writeByte(@boolToInt(is_pl)); | |
| 665 | try code.writer().writeByteNTimes(0, padding); | |
| 431 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - | |
| 432 | (math.divCeil(u64, vector_type.child.toType().bitSize(mod) * vector_type.len, 8) catch |err| switch (err) { | |
| 433 | error.DivisionByZero => unreachable, | |
| 434 | else => |e| return e, | |
| 435 | })) orelse return error.Overflow; | |
| 436 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | |
| 437 | }, | |
| 438 | .anon_struct_type => |tuple| { | |
| 439 | const struct_begin = code.items.len; | |
| 440 | for (tuple.types, tuple.values, 0..) |field_ty, comptime_val, index| { | |
| 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 => { | |
| 670 | const error_ty = typed_value.ty.errorUnionSet(); | |
| 671 | const payload_ty = typed_value.ty.errorUnionPayload(); | |
| 672 | const is_payload = typed_value.val.errorUnionIsPayload(); | |
| 550 | .un => |un| { | |
| 551 | const layout = typed_value.ty.unionGetLayout(mod); | |
| 673 | 552 | |
| 674 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 675 | const err_val = if (is_payload) Value.initTag(.zero) else typed_value.val; | |
| 553 | if (layout.payload_size == 0) { | |
| 676 | 554 | return generateSymbol(bin_file, src_loc, .{ |
| 677 | .ty = error_ty, | |
| 678 | .val = err_val, | |
| 555 | .ty = typed_value.ty.unionTagType(mod).?, | |
| 556 | .val = un.tag.toValue(), | |
| 679 | 557 | }, code, debug_output, reloc_info); |
| 680 | 558 | } |
| 681 | 559 | |
| 682 | const payload_align = payload_ty.abiAlignment(target); | |
| 683 | const error_align = Type.anyerror.abiAlignment(target); | |
| 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) { | |
| 560 | // Check if we should store the tag first. | |
| 561 | if (layout.tag_align >= layout.payload_align) { | |
| 688 | 562 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 689 | .ty = error_ty, | |
| 690 | .val = if (is_payload) Value.initTag(.zero) else typed_value.val, | |
| 563 | .ty = typed_value.ty.unionTagType(mod).?, | |
| 564 | .val = un.tag.toValue(), | |
| 691 | 565 | }, code, debug_output, reloc_info)) { |
| 692 | 566 | .ok => {}, |
| 693 | 567 | .fail => |em| return Result{ .fail = em }, |
| 694 | 568 | } |
| 695 | 569 | } |
| 696 | 570 | |
| 697 | // emit payload part of the error union | |
| 698 | { | |
| 699 | const begin = code.items.len; | |
| 700 | const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef); | |
| 571 | const union_ty = mod.typeToUnion(typed_value.ty).?; | |
| 572 | const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?; | |
| 573 | assert(union_ty.haveFieldTypes()); | |
| 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 | 578 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 702 | .ty = payload_ty, | |
| 703 | .val = payload_val, | |
| 579 | .ty = field_ty, | |
| 580 | .val = un.val.toValue(), | |
| 704 | 581 | }, code, debug_output, reloc_info)) { |
| 705 | 582 | .ok => {}, |
| 706 | 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 | 587 | if (padding > 0) { |
| 713 | 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 | |
| 718 | if (error_align <= payload_align) { | |
| 719 | const begin = code.items.len; | |
| 592 | if (layout.tag_size > 0) { | |
| 720 | 593 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 721 | .ty = error_ty, | |
| 722 | .val = if (is_payload) Value.initTag(.zero) else typed_value.val, | |
| 594 | .ty = union_ty.tag_ty, | |
| 595 | .val = un.tag.toValue(), | |
| 723 | 596 | }, code, debug_output, reloc_info)) { |
| 724 | 597 | .ok => {}, |
| 725 | 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()) { | |
| 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 | ) }, | |
| 602 | .memoized_call => unreachable, | |
| 823 | 603 | } |
| 604 | return .ok; | |
| 824 | 605 | } |
| 825 | 606 | |
| 826 | 607 | fn lowerParentPtr( |
| 827 | 608 | bin_file: *link.File, |
| 828 | 609 | src_loc: Module.SrcLoc, |
| 829 | typed_value: TypedValue, | |
| 830 | parent_ptr: Value, | |
| 610 | parent_ptr: InternPool.Index, | |
| 831 | 611 | code: *std.ArrayList(u8), |
| 832 | 612 | debug_output: DebugInfoOutput, |
| 833 | 613 | reloc_info: RelocInfo, |
| 834 | 614 | ) CodeGenError!Result { |
| 835 | const target = bin_file.options.target; | |
| 836 | switch (parent_ptr.tag()) { | |
| 837 | .field_ptr => { | |
| 838 | const field_ptr = parent_ptr.castTag(.field_ptr).?.data; | |
| 615 | const mod = bin_file.options.module.?; | |
| 616 | const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr; | |
| 617 | assert(ptr.len == .none); | |
| 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 | 665 | return lowerParentPtr( |
| 840 | 666 | bin_file, |
| 841 | 667 | src_loc, |
| 842 | typed_value, | |
| 843 | field_ptr.container_ptr, | |
| 668 | field.base, | |
| 844 | 669 | code, |
| 845 | 670 | debug_output, |
| 846 | reloc_info.offset(@intCast(u32, switch (field_ptr.container_ty.zigTypeTag()) { | |
| 847 | .Pointer => offset: { | |
| 848 | assert(field_ptr.container_ty.isSlice()); | |
| 849 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 850 | break :offset switch (field_ptr.field_index) { | |
| 671 | reloc_info.offset(switch (mod.intern_pool.indexToKey(base_type)) { | |
| 672 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 673 | .One, .Many, .C => unreachable, | |
| 674 | .Slice => switch (field.index) { | |
| 851 | 675 | 0 => 0, |
| 852 | 1 => field_ptr.container_ty.slicePtrFieldType(&buf).abiSize(target), | |
| 676 | 1 => @divExact(mod.getTarget().ptrBitWidth(), 8), | |
| 853 | 677 | else => unreachable, |
| 854 | }; | |
| 678 | }, | |
| 855 | 679 | }, |
| 856 | .Struct, .Union => field_ptr.container_ty.structFieldOffset( | |
| 857 | field_ptr.field_index, | |
| 858 | target, | |
| 859 | ), | |
| 860 | else => return Result{ .fail = try ErrorMsg.create( | |
| 861 | bin_file.allocator, | |
| 862 | src_loc, | |
| 863 | "TODO implement lowerParentPtr for field_ptr with a container of type {}", | |
| 864 | .{field_ptr.container_ty.fmt(bin_file.options.module.?)}, | |
| 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))), | |
| 680 | .struct_type, | |
| 681 | .anon_struct_type, | |
| 682 | .union_type, | |
| 683 | => @intCast(u32, base_type.toType().structFieldOffset( | |
| 684 | @intCast(u32, field.index), | |
| 685 | mod, | |
| 686 | )), | |
| 687 | else => unreachable, | |
| 688 | }), | |
| 904 | 689 | ); |
| 905 | 690 | }, |
| 906 | .variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef( | |
| 907 | bin_file, | |
| 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 | } | |
| 691 | .comptime_field => unreachable, | |
| 692 | }; | |
| 927 | 693 | } |
| 928 | 694 | |
| 929 | 695 | const RelocInfo = struct { |
| ... | ... | @@ -938,51 +704,25 @@ const RelocInfo = struct { |
| 938 | 704 | fn lowerDeclRef( |
| 939 | 705 | bin_file: *link.File, |
| 940 | 706 | src_loc: Module.SrcLoc, |
| 941 | typed_value: TypedValue, | |
| 942 | 707 | decl_index: Module.Decl.Index, |
| 943 | 708 | code: *std.ArrayList(u8), |
| 944 | 709 | debug_output: DebugInfoOutput, |
| 945 | 710 | reloc_info: RelocInfo, |
| 946 | 711 | ) CodeGenError!Result { |
| 712 | _ = src_loc; | |
| 713 | _ = debug_output; | |
| 947 | 714 | const target = bin_file.options.target; |
| 948 | const module = 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 | } | |
| 715 | const mod = bin_file.options.module.?; | |
| 976 | 716 | |
| 977 | 717 | const ptr_width = target.ptrBitWidth(); |
| 978 | const decl = module.declPtr(decl_index); | |
| 979 | const is_fn_body = decl.ty.zigTypeTag() == .Fn; | |
| 980 | if (!is_fn_body and !decl.ty.hasRuntimeBits()) { | |
| 718 | const decl = mod.declPtr(decl_index); | |
| 719 | const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn; | |
| 720 | if (!is_fn_body and !decl.ty.hasRuntimeBits(mod)) { | |
| 981 | 721 | try code.writer().writeByteNTimes(0xaa, @divExact(ptr_width, 8)); |
| 982 | 722 | return Result.ok; |
| 983 | 723 | } |
| 984 | 724 | |
| 985 | module.markDeclAlive(decl); | |
| 725 | try mod.markDeclAlive(decl); | |
| 986 | 726 | |
| 987 | 727 | const vaddr = try bin_file.getDeclVAddr(decl_index, .{ |
| 988 | 728 | .parent_atom_index = reloc_info.parent_atom_index, |
| ... | ... | @@ -1059,16 +799,16 @@ fn genDeclRef( |
| 1059 | 799 | tv: TypedValue, |
| 1060 | 800 | decl_index: Module.Decl.Index, |
| 1061 | 801 | ) CodeGenError!GenResult { |
| 1062 | const module = bin_file.options.module.?; | |
| 1063 | log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmt(module), tv.val.fmtValue(tv.ty, module) }); | |
| 802 | const mod = bin_file.options.module.?; | |
| 803 | log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmt(mod), tv.val.fmtValue(tv.ty, mod) }); | |
| 1064 | 804 | |
| 1065 | 805 | const target = bin_file.options.target; |
| 1066 | 806 | const ptr_bits = target.ptrBitWidth(); |
| 1067 | 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 | 812 | const imm: u64 = switch (ptr_bytes) { |
| 1073 | 813 | 1 => 0xaa, |
| 1074 | 814 | 2 => 0xaaaa, |
| ... | ... | @@ -1080,20 +820,20 @@ fn genDeclRef( |
| 1080 | 820 | } |
| 1081 | 821 | |
| 1082 | 822 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? |
| 1083 | if (tv.ty.castPtrToFn()) |fn_ty| { | |
| 1084 | if (fn_ty.fnInfo().is_generic) { | |
| 1085 | return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(target) }); | |
| 823 | if (tv.ty.castPtrToFn(mod)) |fn_ty| { | |
| 824 | if (mod.typeToFunc(fn_ty).?.is_generic) { | |
| 825 | return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(mod) }); | |
| 1086 | 826 | } |
| 1087 | } else if (tv.ty.zigTypeTag() == .Pointer) { | |
| 1088 | const elem_ty = tv.ty.elemType2(); | |
| 1089 | if (!elem_ty.hasRuntimeBits()) { | |
| 1090 | return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(target) }); | |
| 827 | } else if (tv.ty.zigTypeTag(mod) == .Pointer) { | |
| 828 | const elem_ty = tv.ty.elemType2(mod); | |
| 829 | if (!elem_ty.hasRuntimeBits(mod)) { | |
| 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 | 838 | if (bin_file.cast(link.File.Elf)) |elf_file| { |
| 1099 | 839 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); |
| ... | ... | @@ -1157,57 +897,56 @@ pub fn genTypedValue( |
| 1157 | 897 | arg_tv: TypedValue, |
| 1158 | 898 | owner_decl_index: Module.Decl.Index, |
| 1159 | 899 | ) CodeGenError!GenResult { |
| 900 | const mod = bin_file.options.module.?; | |
| 1160 | 901 | var typed_value = arg_tv; |
| 1161 | if (typed_value.val.castTag(.runtime_value)) |rt| { | |
| 1162 | typed_value.val = rt.data; | |
| 902 | switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { | |
| 903 | .runtime_value => |rt| typed_value.val = rt.val.toValue(), | |
| 904 | else => {}, | |
| 1163 | 905 | } |
| 1164 | 906 | |
| 1165 | const mod = bin_file.options.module.?; | |
| 1166 | 907 | log.debug("genTypedValue: ty = {}, val = {}", .{ |
| 1167 | 908 | typed_value.ty.fmt(mod), |
| 1168 | 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 | 913 | return GenResult.mcv(.undef); |
| 1173 | 914 | |
| 1174 | 915 | const target = bin_file.options.target; |
| 1175 | 916 | const ptr_bits = target.ptrBitWidth(); |
| 1176 | 917 | |
| 1177 | if (!typed_value.ty.isSlice()) { | |
| 1178 | if (typed_value.val.castTag(.variable)) |payload| { | |
| 1179 | return genDeclRef(bin_file, src_loc, typed_value, payload.data.owner_decl); | |
| 1180 | } | |
| 1181 | if (typed_value.val.castTag(.decl_ref)) |payload| { | |
| 1182 | return genDeclRef(bin_file, src_loc, typed_value, payload.data); | |
| 1183 | } | |
| 1184 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | |
| 1185 | return genDeclRef(bin_file, src_loc, typed_value, payload.data.decl_index); | |
| 1186 | } | |
| 1187 | } | |
| 918 | if (!typed_value.ty.isSlice(mod)) switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { | |
| 919 | .ptr => |ptr| switch (ptr.addr) { | |
| 920 | .decl => |decl| return genDeclRef(bin_file, src_loc, typed_value, decl), | |
| 921 | .mut_decl => |mut_decl| return genDeclRef(bin_file, src_loc, typed_value, mut_decl.decl), | |
| 922 | else => {}, | |
| 923 | }, | |
| 924 | else => {}, | |
| 925 | }; | |
| 1188 | 926 | |
| 1189 | switch (typed_value.ty.zigTypeTag()) { | |
| 927 | switch (typed_value.ty.zigTypeTag(mod)) { | |
| 1190 | 928 | .Void => return GenResult.mcv(.none), |
| 1191 | .Pointer => switch (typed_value.ty.ptrSize()) { | |
| 929 | .Pointer => switch (typed_value.ty.ptrSize(mod)) { | |
| 1192 | 930 | .Slice => {}, |
| 1193 | else => { | |
| 1194 | switch (typed_value.val.tag()) { | |
| 1195 | .null_value => { | |
| 1196 | return GenResult.mcv(.{ .immediate = 0 }); | |
| 1197 | }, | |
| 1198 | .int_u64 => { | |
| 1199 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); | |
| 931 | else => switch (typed_value.val.toIntern()) { | |
| 932 | .null_value => { | |
| 933 | return GenResult.mcv(.{ .immediate = 0 }); | |
| 934 | }, | |
| 935 | .none => {}, | |
| 936 | else => switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { | |
| 937 | .int => { | |
| 938 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(mod) }); | |
| 1200 | 939 | }, |
| 1201 | 940 | else => {}, |
| 1202 | } | |
| 941 | }, | |
| 1203 | 942 | }, |
| 1204 | 943 | }, |
| 1205 | 944 | .Int => { |
| 1206 | const info = typed_value.ty.intInfo(target); | |
| 945 | const info = typed_value.ty.intInfo(mod); | |
| 1207 | 946 | if (info.bits <= ptr_bits) { |
| 1208 | 947 | const unsigned = switch (info.signedness) { |
| 1209 | .signed => @bitCast(u64, typed_value.val.toSignedInt(target)), | |
| 1210 | .unsigned => typed_value.val.toUnsignedInt(target), | |
| 948 | .signed => @bitCast(u64, typed_value.val.toSignedInt(mod)), | |
| 949 | .unsigned => typed_value.val.toUnsignedInt(mod), | |
| 1211 | 950 | }; |
| 1212 | 951 | return GenResult.mcv(.{ .immediate = unsigned }); |
| 1213 | 952 | } |
| ... | ... | @@ -1216,78 +955,46 @@ pub fn genTypedValue( |
| 1216 | 955 | return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool()) }); |
| 1217 | 956 | }, |
| 1218 | 957 | .Optional => { |
| 1219 | if (typed_value.ty.isPtrLikeOptional()) { | |
| 1220 | if (typed_value.val.tag() == .null_value) return GenResult.mcv(.{ .immediate = 0 }); | |
| 1221 | ||
| 1222 | var buf: Type.Payload.ElemType = undefined; | |
| 958 | if (typed_value.ty.isPtrLikeOptional(mod)) { | |
| 1223 | 959 | return genTypedValue(bin_file, src_loc, .{ |
| 1224 | .ty = typed_value.ty.optionalChild(&buf), | |
| 1225 | .val = if (typed_value.val.castTag(.opt_payload)) |pl| pl.data else typed_value.val, | |
| 960 | .ty = typed_value.ty.optionalChild(mod), | |
| 961 | .val = typed_value.val.optionalValue(mod) orelse return GenResult.mcv(.{ .immediate = 0 }), | |
| 1226 | 962 | }, owner_decl_index); |
| 1227 | } else if (typed_value.ty.abiSize(target) == 1) { | |
| 1228 | return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) }); | |
| 963 | } else if (typed_value.ty.abiSize(mod) == 1) { | |
| 964 | return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull(mod)) }); | |
| 1229 | 965 | } |
| 1230 | 966 | }, |
| 1231 | 967 | .Enum => { |
| 1232 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | |
| 1233 | switch (typed_value.ty.tag()) { | |
| 1234 | .enum_simple => { | |
| 1235 | return GenResult.mcv(.{ .immediate = field_index.data }); | |
| 1236 | }, | |
| 1237 | .enum_numbered, .enum_full, .enum_nonexhaustive => { | |
| 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 | } | |
| 968 | const enum_tag = mod.intern_pool.indexToKey(typed_value.val.toIntern()).enum_tag; | |
| 969 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); | |
| 970 | return genTypedValue(bin_file, src_loc, .{ | |
| 971 | .ty = int_tag_ty.toType(), | |
| 972 | .val = enum_tag.int.toValue(), | |
| 973 | }, owner_decl_index); | |
| 1263 | 974 | }, |
| 1264 | 975 | .ErrorSet => { |
| 1265 | switch (typed_value.val.tag()) { | |
| 1266 | .@"error" => { | |
| 1267 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | |
| 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 | } | |
| 976 | const err_name = mod.intern_pool.indexToKey(typed_value.val.toIntern()).err.name; | |
| 977 | const error_index = mod.global_error_set.getIndex(err_name).?; | |
| 978 | return GenResult.mcv(.{ .immediate = error_index }); | |
| 1278 | 979 | }, |
| 1279 | 980 | .ErrorUnion => { |
| 1280 | const error_type = typed_value.ty.errorUnionSet(); | |
| 1281 | const payload_type = typed_value.ty.errorUnionPayload(); | |
| 1282 | const is_pl = typed_value.val.errorUnionIsPayload(); | |
| 1283 | ||
| 1284 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | |
| 981 | const err_type = typed_value.ty.errorUnionSet(mod); | |
| 982 | const payload_type = typed_value.ty.errorUnionPayload(mod); | |
| 983 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1285 | 984 | // We use the error type directly as the type. |
| 1286 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | |
| 1287 | return genTypedValue(bin_file, src_loc, .{ | |
| 1288 | .ty = error_type, | |
| 1289 | .val = err_val, | |
| 1290 | }, owner_decl_index); | |
| 985 | switch (mod.intern_pool.indexToKey(typed_value.val.toIntern()).error_union.val) { | |
| 986 | .err_name => |err_name| return genTypedValue(bin_file, src_loc, .{ | |
| 987 | .ty = err_type, | |
| 988 | .val = (try mod.intern(.{ .err = .{ | |
| 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 | 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 { | |
| 1310 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return 0; | |
| 1311 | const payload_align = payload_ty.abiAlignment(target); | |
| 1312 | const error_align = Type.anyerror.abiAlignment(target); | |
| 1313 | if (payload_align >= error_align or !payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1016 | pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 { | |
| 1017 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; | |
| 1018 | const payload_align = payload_ty.abiAlignment(mod); | |
| 1019 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 1020 | if (payload_align >= error_align or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1314 | 1021 | return 0; |
| 1315 | 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 { | |
| 1321 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return 0; | |
| 1322 | const payload_align = payload_ty.abiAlignment(target); | |
| 1323 | const error_align = Type.anyerror.abiAlignment(target); | |
| 1324 | if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1325 | return mem.alignForwardGeneric(u64, payload_ty.abiSize(target), error_align); | |
| 1027 | pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 { | |
| 1028 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; | |
| 1029 | const payload_align = payload_ty.abiAlignment(mod); | |
| 1030 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 1031 | if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1032 | return mem.alignForwardGeneric(u64, payload_ty.abiSize(mod), error_align); | |
| 1326 | 1033 | } else { |
| 1327 | 1034 | return 0; |
| 1328 | 1035 | } |
src/codegen/c.zig+1341-1369| ... | ... | @@ -16,6 +16,7 @@ const trace = @import("../tracy.zig").trace; |
| 16 | 16 | const LazySrcLoc = Module.LazySrcLoc; |
| 17 | 17 | const Air = @import("../Air.zig"); |
| 18 | 18 | const Liveness = @import("../Liveness.zig"); |
| 19 | const InternPool = @import("../InternPool.zig"); | |
| 19 | 20 | |
| 20 | 21 | const BigIntLimb = std.math.big.Limb; |
| 21 | 22 | const BigInt = std.math.big.int; |
| ... | ... | @@ -256,7 +257,7 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { |
| 256 | 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 | 261 | /// It is not available when generating .h file. |
| 261 | 262 | pub const Function = struct { |
| 262 | 263 | air: Air, |
| ... | ... | @@ -267,7 +268,7 @@ pub const Function = struct { |
| 267 | 268 | next_block_index: usize = 0, |
| 268 | 269 | object: Object, |
| 269 | 270 | lazy_fns: LazyFnMap, |
| 270 | func: *Module.Fn, | |
| 271 | func_index: Module.Fn.Index, | |
| 271 | 272 | /// All the locals, to be emitted at the top of the function. |
| 272 | 273 | locals: std.ArrayListUnmanaged(Local) = .{}, |
| 273 | 274 | /// Which locals are available for reuse, based on Type. |
| ... | ... | @@ -285,10 +286,11 @@ pub const Function = struct { |
| 285 | 286 | const gop = try f.value_map.getOrPut(inst); |
| 286 | 287 | if (gop.found_existing) return gop.value_ptr.*; |
| 287 | 288 | |
| 288 | const val = f.air.value(ref).?; | |
| 289 | const ty = f.air.typeOf(ref); | |
| 289 | const mod = f.object.dg.module; | |
| 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 | 294 | const writer = f.object.code_header.writer(); |
| 293 | 295 | const alignment = 0; |
| 294 | 296 | const decl_c_value = try f.allocLocalValue(ty, alignment); |
| ... | ... | @@ -318,11 +320,11 @@ pub const Function = struct { |
| 318 | 320 | /// those which go into `allocs`. This function does not add the resulting local into `allocs`; |
| 319 | 321 | /// that responsibility lies with the caller. |
| 320 | 322 | fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue { |
| 323 | const mod = f.object.dg.module; | |
| 321 | 324 | const gpa = f.object.dg.gpa; |
| 322 | const target = f.object.dg.module.getTarget(); | |
| 323 | 325 | try f.locals.append(gpa, .{ |
| 324 | 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 | 329 | return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) }; |
| 328 | 330 | } |
| ... | ... | @@ -336,10 +338,10 @@ pub const Function = struct { |
| 336 | 338 | /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should |
| 337 | 339 | /// not be used for persistent locals (i.e. those in `allocs`). |
| 338 | 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 | 342 | if (f.free_locals_map.getPtr(.{ |
| 341 | 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 | 345 | })) |locals_list| { |
| 344 | 346 | if (locals_list.popOrNull()) |local_entry| { |
| 345 | 347 | return .{ .new_local = local_entry.key }; |
| ... | ... | @@ -352,8 +354,9 @@ pub const Function = struct { |
| 352 | 354 | fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void { |
| 353 | 355 | switch (c_value) { |
| 354 | 356 | .constant => |inst| { |
| 355 | const ty = f.air.typeOf(inst); | |
| 356 | const val = f.air.value(inst).?; | |
| 357 | const mod = f.object.dg.module; | |
| 358 | const ty = f.typeOf(inst); | |
| 359 | const val = (try f.air.value(inst, mod)).?; | |
| 357 | 360 | return f.object.dg.renderValue(w, ty, val, location); |
| 358 | 361 | }, |
| 359 | 362 | .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), |
| ... | ... | @@ -364,8 +367,9 @@ pub const Function = struct { |
| 364 | 367 | fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void { |
| 365 | 368 | switch (c_value) { |
| 366 | 369 | .constant => |inst| { |
| 367 | const ty = f.air.typeOf(inst); | |
| 368 | const val = f.air.value(inst).?; | |
| 370 | const mod = f.object.dg.module; | |
| 371 | const ty = f.typeOf(inst); | |
| 372 | const val = (try f.air.value(inst, mod)).?; | |
| 369 | 373 | try w.writeAll("(*"); |
| 370 | 374 | try f.object.dg.renderValue(w, ty, val, .Other); |
| 371 | 375 | return w.writeByte(')'); |
| ... | ... | @@ -377,8 +381,9 @@ pub const Function = struct { |
| 377 | 381 | fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { |
| 378 | 382 | switch (c_value) { |
| 379 | 383 | .constant => |inst| { |
| 380 | const ty = f.air.typeOf(inst); | |
| 381 | const val = f.air.value(inst).?; | |
| 384 | const mod = f.object.dg.module; | |
| 385 | const ty = f.typeOf(inst); | |
| 386 | const val = (try f.air.value(inst, mod)).?; | |
| 382 | 387 | try f.object.dg.renderValue(w, ty, val, .Other); |
| 383 | 388 | try w.writeByte('.'); |
| 384 | 389 | return f.writeCValue(w, member, .Other); |
| ... | ... | @@ -390,8 +395,9 @@ pub const Function = struct { |
| 390 | 395 | fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { |
| 391 | 396 | switch (c_value) { |
| 392 | 397 | .constant => |inst| { |
| 393 | const ty = f.air.typeOf(inst); | |
| 394 | const val = f.air.value(inst).?; | |
| 398 | const mod = f.object.dg.module; | |
| 399 | const ty = f.typeOf(inst); | |
| 400 | const val = (try f.air.value(inst, mod)).?; | |
| 395 | 401 | try w.writeByte('('); |
| 396 | 402 | try f.object.dg.renderValue(w, ty, val, .Other); |
| 397 | 403 | try w.writeAll(")->"); |
| ... | ... | @@ -446,6 +452,7 @@ pub const Function = struct { |
| 446 | 452 | var promoted = f.object.dg.ctypes.promote(gpa); |
| 447 | 453 | defer f.object.dg.ctypes.demote(promoted); |
| 448 | 454 | const arena = promoted.arena.allocator(); |
| 455 | const mod = f.object.dg.module; | |
| 449 | 456 | |
| 450 | 457 | gop.value_ptr.* = .{ |
| 451 | 458 | .fn_name = switch (key) { |
| ... | ... | @@ -454,12 +461,12 @@ pub const Function = struct { |
| 454 | 461 | .never_inline, |
| 455 | 462 | => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{ |
| 456 | 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 | 465 | @enumToInt(owner_decl), |
| 459 | 466 | }), |
| 460 | 467 | }, |
| 461 | 468 | .data = switch (key) { |
| 462 | .tag_name => .{ .tag_name = try data.tag_name.copy(arena) }, | |
| 469 | .tag_name => .{ .tag_name = data.tag_name }, | |
| 463 | 470 | .never_tail => .{ .never_tail = data.never_tail }, |
| 464 | 471 | .never_inline => .{ .never_inline = data.never_inline }, |
| 465 | 472 | }, |
| ... | ... | @@ -480,6 +487,16 @@ pub const Function = struct { |
| 480 | 487 | f.object.dg.ctypes.deinit(gpa); |
| 481 | 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 | 502 | /// This data is available when outputting .c code for a `Module`. |
| ... | ... | @@ -508,8 +525,9 @@ pub const DeclGen = struct { |
| 508 | 525 | |
| 509 | 526 | fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { |
| 510 | 527 | @setCold(true); |
| 528 | const mod = dg.module; | |
| 511 | 529 | const src = LazySrcLoc.nodeOffset(0); |
| 512 | const src_loc = src.toSrcLoc(dg.decl.?); | |
| 530 | const src_loc = src.toSrcLoc(dg.decl.?, mod); | |
| 513 | 531 | dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args); |
| 514 | 532 | return error.AnalysisFail; |
| 515 | 533 | } |
| ... | ... | @@ -522,53 +540,28 @@ pub const DeclGen = struct { |
| 522 | 540 | decl_index: Decl.Index, |
| 523 | 541 | location: ValueRenderLocation, |
| 524 | 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 | 545 | assert(decl.has_tv); |
| 527 | 546 | |
| 528 | 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 | 549 | return dg.writeCValue(writer, .{ .undef = ty }); |
| 531 | 550 | } |
| 532 | 551 | |
| 533 | 552 | // Chase function values in order to be able to reference the original function. |
| 534 | inline for (.{ .function, .extern_fn }) |tag| | |
| 535 | if (decl.val.castTag(tag)) |func| | |
| 536 | if (func.data.owner_decl != decl_index) | |
| 537 | return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location); | |
| 553 | if (decl.val.getFunction(mod)) |func| if (func.owner_decl != decl_index) | |
| 554 | return dg.renderDeclValue(writer, ty, val, func.owner_decl, location); | |
| 555 | if (decl.val.getExternFunc(mod)) |extern_func| if (extern_func.decl != decl_index) | |
| 556 | return dg.renderDeclValue(writer, ty, val, extern_func.decl, location); | |
| 538 | 557 | |
| 539 | if (decl.val.castTag(.variable)) |var_payload| | |
| 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 | } | |
| 558 | if (decl.val.getVariable(mod)) |variable| try dg.renderFwdDecl(decl_index, variable); | |
| 566 | 559 | |
| 567 | 560 | // We shouldn't cast C function pointers as this is UB (when you call |
| 568 | 561 | // them). The analysis until now should ensure that the C function |
| 569 | 562 | // pointers are compatible. If they are not, then there is a bug |
| 570 | 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 | 565 | if (need_typecast) { |
| 573 | 566 | try writer.writeAll("(("); |
| 574 | 567 | try dg.renderType(writer, ty); |
| ... | ... | @@ -579,127 +572,124 @@ pub const DeclGen = struct { |
| 579 | 572 | if (need_typecast) try writer.writeByte(')'); |
| 580 | 573 | } |
| 581 | 574 | |
| 582 | // Renders a "parent" pointer by recursing to the root decl/variable | |
| 583 | // that its contents are defined with respect to. | |
| 584 | // | |
| 585 | // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr | |
| 586 | fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void { | |
| 587 | if (!ptr_ty.isSlice()) { | |
| 588 | try writer.writeByte('('); | |
| 589 | try dg.renderType(writer, ptr_ty); | |
| 590 | try writer.writeByte(')'); | |
| 591 | } | |
| 592 | switch (ptr_val.tag()) { | |
| 593 | .int_u64, .one => try writer.print("{x}", .{try dg.fmtIntLiteral(Type.usize, ptr_val, .Other)}), | |
| 594 | .decl_ref_mut, .decl_ref, .variable => { | |
| 595 | const decl_index = switch (ptr_val.tag()) { | |
| 596 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, | |
| 597 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 598 | .variable => ptr_val.castTag(.variable).?.data.owner_decl, | |
| 575 | /// Renders a "parent" pointer by recursing to the root decl/variable | |
| 576 | /// that its contents are defined with respect to. | |
| 577 | fn renderParentPtr( | |
| 578 | dg: *DeclGen, | |
| 579 | writer: anytype, | |
| 580 | ptr_val: InternPool.Index, | |
| 581 | location: ValueRenderLocation, | |
| 582 | ) error{ OutOfMemory, AnalysisFail }!void { | |
| 583 | const mod = dg.module; | |
| 584 | const ptr_ty = mod.intern_pool.typeOf(ptr_val).toType(); | |
| 585 | const ptr_cty = try dg.typeToIndex(ptr_ty, .complete); | |
| 586 | const ptr = mod.intern_pool.indexToKey(ptr_val).ptr; | |
| 587 | switch (ptr.addr) { | |
| 588 | .decl, .mut_decl => try dg.renderDeclValue( | |
| 589 | writer, | |
| 590 | ptr_ty, | |
| 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 | 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 => { | |
| 604 | const target = dg.module.getTarget(); | |
| 605 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 606 | ||
| 623 | .elem => |elem| { | |
| 624 | const ptr_base_ty = mod.intern_pool.typeOf(elem.base).toType(); | |
| 625 | const elem_ty = ptr_base_ty.elemType2(mod); | |
| 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 | 642 | // Ensure complete type definition is visible before accessing fields. |
| 608 | _ = try dg.typeToIndex(field_ptr.container_ty, .complete); | |
| 609 | ||
| 610 | var container_ptr_pl = ptr_ty.ptrInfo(); | |
| 611 | container_ptr_pl.data.pointee_type = field_ptr.container_ty; | |
| 612 | const container_ptr_ty = Type.initPayload(&container_ptr_pl.base); | |
| 613 | ||
| 614 | switch (fieldLocation( | |
| 615 | field_ptr.container_ty, | |
| 616 | ptr_ty, | |
| 617 | @intCast(u32, field_ptr.field_index), | |
| 618 | target, | |
| 619 | )) { | |
| 620 | .begin => try dg.renderParentPtr( | |
| 621 | writer, | |
| 622 | field_ptr.container_ptr, | |
| 623 | container_ptr_ty, | |
| 624 | location, | |
| 625 | ), | |
| 626 | .field => |field| { | |
| 643 | _ = try dg.typeToIndex(base_ty, .complete); | |
| 644 | const field_ty = switch (mod.intern_pool.indexToKey(base_ty.toIntern())) { | |
| 645 | .anon_struct_type, .struct_type, .union_type => base_ty.structFieldType(@intCast(usize, field.index), mod), | |
| 646 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 647 | .One, .Many, .C => unreachable, | |
| 648 | .Slice => switch (field.index) { | |
| 649 | Value.slice_ptr_index => base_ty.slicePtrFieldType(mod), | |
| 650 | Value.slice_len_index => Type.usize, | |
| 651 | else => unreachable, | |
| 652 | }, | |
| 653 | }, | |
| 654 | else => unreachable, | |
| 655 | }; | |
| 656 | const ptr_field_ty = try mod.adjustPtrTypeChild(ptr_base_ty, field_ty); | |
| 657 | const ptr_field_cty = try dg.typeToIndex(ptr_field_ty, .complete); | |
| 658 | if (ptr_cty != ptr_field_cty) { | |
| 659 | try writer.writeByte('('); | |
| 660 | try dg.renderCType(writer, ptr_cty); | |
| 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 | 666 | try writer.writeAll("&("); |
| 628 | try dg.renderParentPtr( | |
| 629 | writer, | |
| 630 | field_ptr.container_ptr, | |
| 631 | container_ptr_ty, | |
| 632 | location, | |
| 633 | ); | |
| 667 | try dg.renderParentPtr(writer, field.base, location); | |
| 634 | 668 | try writer.writeAll(")->"); |
| 635 | try dg.writeCValue(writer, field); | |
| 669 | try dg.writeCValue(writer, name); | |
| 636 | 670 | }, |
| 637 | 671 | .byte_offset => |byte_offset| { |
| 638 | var u8_ptr_pl = ptr_ty.ptrInfo(); | |
| 639 | u8_ptr_pl.data.pointee_type = Type.u8; | |
| 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); | |
| 672 | const u8_ptr_ty = try mod.adjustPtrTypeChild(ptr_ty, Type.u8); | |
| 673 | const byte_offset_val = try mod.intValue(Type.usize, byte_offset); | |
| 647 | 674 | |
| 648 | 675 | try writer.writeAll("(("); |
| 649 | 676 | try dg.renderType(writer, u8_ptr_ty); |
| 650 | 677 | try writer.writeByte(')'); |
| 651 | try dg.renderParentPtr( | |
| 652 | writer, | |
| 653 | field_ptr.container_ptr, | |
| 654 | container_ptr_ty, | |
| 655 | location, | |
| 656 | ); | |
| 678 | try dg.renderParentPtr(writer, field.base, location); | |
| 657 | 679 | try writer.print(" + {})", .{ |
| 658 | 680 | try dg.fmtIntLiteral(Type.usize, byte_offset_val, .Other), |
| 659 | 681 | }); |
| 660 | 682 | }, |
| 661 | 683 | .end => { |
| 662 | 684 | try writer.writeAll("(("); |
| 663 | try dg.renderParentPtr( | |
| 664 | writer, | |
| 665 | field_ptr.container_ptr, | |
| 666 | container_ptr_ty, | |
| 667 | location, | |
| 668 | ); | |
| 685 | try dg.renderParentPtr(writer, field.base, location); | |
| 669 | 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 => { | |
| 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, | |
| 692 | .comptime_field => unreachable, | |
| 703 | 693 | } |
| 704 | 694 | } |
| 705 | 695 | |
| ... | ... | @@ -710,23 +700,25 @@ pub const DeclGen = struct { |
| 710 | 700 | arg_val: Value, |
| 711 | 701 | location: ValueRenderLocation, |
| 712 | 702 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 703 | const mod = dg.module; | |
| 713 | 704 | var val = arg_val; |
| 714 | if (val.castTag(.runtime_value)) |rt| { | |
| 715 | val = rt.data; | |
| 705 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 706 | .runtime_value => |rt| val = rt.val.toValue(), | |
| 707 | else => {}, | |
| 716 | 708 | } |
| 717 | const target = dg.module.getTarget(); | |
| 709 | const target = mod.getTarget(); | |
| 718 | 710 | const initializer_type: ValueRenderLocation = switch (location) { |
| 719 | 711 | .StaticInitializer => .StaticInitializer, |
| 720 | 712 | else => .Initializer, |
| 721 | 713 | }; |
| 722 | 714 | |
| 723 | const safety_on = switch (dg.module.optimizeMode()) { | |
| 715 | const safety_on = switch (mod.optimizeMode()) { | |
| 724 | 716 | .Debug, .ReleaseSafe => true, |
| 725 | 717 | .ReleaseFast, .ReleaseSmall => false, |
| 726 | 718 | }; |
| 727 | 719 | |
| 728 | if (val.isUndefDeep()) { | |
| 729 | switch (ty.zigTypeTag()) { | |
| 720 | if (val.isUndefDeep(mod)) { | |
| 721 | switch (ty.zigTypeTag(mod)) { | |
| 730 | 722 | .Bool => { |
| 731 | 723 | if (safety_on) { |
| 732 | 724 | return writer.writeAll("0xaa"); |
| ... | ... | @@ -737,8 +729,8 @@ pub const DeclGen = struct { |
| 737 | 729 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val, location)}), |
| 738 | 730 | .Float => { |
| 739 | 731 | const bits = ty.floatBits(target); |
| 740 | var repr_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = bits }; | |
| 741 | const repr_ty = Type.initPayload(&repr_pl.base); | |
| 732 | // All unsigned ints matching float types are pre-allocated. | |
| 733 | const repr_ty = mod.intType(.unsigned, bits) catch unreachable; | |
| 742 | 734 | |
| 743 | 735 | try writer.writeAll("zig_cast_"); |
| 744 | 736 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| ... | ... | @@ -757,7 +749,7 @@ pub const DeclGen = struct { |
| 757 | 749 | try dg.renderValue(writer, repr_ty, Value.undef, .FunctionArgument); |
| 758 | 750 | return writer.writeByte(')'); |
| 759 | 751 | }, |
| 760 | .Pointer => if (ty.isSlice()) { | |
| 752 | .Pointer => if (ty.isSlice(mod)) { | |
| 761 | 753 | if (!location.isInitializer()) { |
| 762 | 754 | try writer.writeByte('('); |
| 763 | 755 | try dg.renderType(writer, ty); |
| ... | ... | @@ -765,8 +757,7 @@ pub const DeclGen = struct { |
| 765 | 757 | } |
| 766 | 758 | |
| 767 | 759 | try writer.writeAll("{("); |
| 768 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 769 | const ptr_ty = ty.slicePtrFieldType(&buf); | |
| 760 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 770 | 761 | try dg.renderType(writer, ptr_ty); |
| 771 | 762 | return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); |
| 772 | 763 | } else { |
| ... | ... | @@ -775,14 +766,13 @@ pub const DeclGen = struct { |
| 775 | 766 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); |
| 776 | 767 | }, |
| 777 | 768 | .Optional => { |
| 778 | var opt_buf: Type.Payload.ElemType = undefined; | |
| 779 | const payload_ty = ty.optionalChild(&opt_buf); | |
| 769 | const payload_ty = ty.optionalChild(mod); | |
| 780 | 770 | |
| 781 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 771 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 782 | 772 | return dg.renderValue(writer, Type.bool, val, location); |
| 783 | 773 | } |
| 784 | 774 | |
| 785 | if (ty.optionalReprIsPayload()) { | |
| 775 | if (ty.optionalReprIsPayload(mod)) { | |
| 786 | 776 | return dg.renderValue(writer, payload_ty, val, location); |
| 787 | 777 | } |
| 788 | 778 | |
| ... | ... | @@ -798,7 +788,7 @@ pub const DeclGen = struct { |
| 798 | 788 | try dg.renderValue(writer, Type.bool, val, initializer_type); |
| 799 | 789 | return writer.writeAll(" }"); |
| 800 | 790 | }, |
| 801 | .Struct => switch (ty.containerLayout()) { | |
| 791 | .Struct => switch (ty.containerLayout(mod)) { | |
| 802 | 792 | .Auto, .Extern => { |
| 803 | 793 | if (!location.isInitializer()) { |
| 804 | 794 | try writer.writeByte('('); |
| ... | ... | @@ -808,10 +798,10 @@ pub const DeclGen = struct { |
| 808 | 798 | |
| 809 | 799 | try writer.writeByte('{'); |
| 810 | 800 | var empty = true; |
| 811 | for (0..ty.structFieldCount()) |field_i| { | |
| 812 | if (ty.structFieldIsComptime(field_i)) continue; | |
| 813 | const field_ty = ty.structFieldType(field_i); | |
| 814 | if (!field_ty.hasRuntimeBits()) continue; | |
| 801 | for (0..ty.structFieldCount(mod)) |field_i| { | |
| 802 | if (ty.structFieldIsComptime(field_i, mod)) continue; | |
| 803 | const field_ty = ty.structFieldType(field_i, mod); | |
| 804 | if (!field_ty.hasRuntimeBits(mod)) continue; | |
| 815 | 805 | |
| 816 | 806 | if (!empty) try writer.writeByte(','); |
| 817 | 807 | try dg.renderValue(writer, field_ty, val, initializer_type); |
| ... | ... | @@ -831,29 +821,29 @@ pub const DeclGen = struct { |
| 831 | 821 | } |
| 832 | 822 | |
| 833 | 823 | try writer.writeByte('{'); |
| 834 | if (ty.unionTagTypeSafety()) |tag_ty| { | |
| 835 | const layout = ty.unionGetLayout(target); | |
| 824 | if (ty.unionTagTypeSafety(mod)) |tag_ty| { | |
| 825 | const layout = ty.unionGetLayout(mod); | |
| 836 | 826 | if (layout.tag_size != 0) { |
| 837 | 827 | try writer.writeAll(" .tag = "); |
| 838 | 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 | 831 | if (layout.tag_size != 0) try writer.writeByte(','); |
| 842 | 832 | try writer.writeAll(" .payload = {"); |
| 843 | 833 | } |
| 844 | for (ty.unionFields().values()) |field| { | |
| 845 | if (!field.ty.hasRuntimeBits()) continue; | |
| 834 | for (ty.unionFields(mod).values()) |field| { | |
| 835 | if (!field.ty.hasRuntimeBits(mod)) continue; | |
| 846 | 836 | try dg.renderValue(writer, field.ty, val, initializer_type); |
| 847 | 837 | break; |
| 848 | 838 | } |
| 849 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); | |
| 839 | if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}'); | |
| 850 | 840 | return writer.writeByte('}'); |
| 851 | 841 | }, |
| 852 | 842 | .ErrorUnion => { |
| 853 | const payload_ty = ty.errorUnionPayload(); | |
| 854 | const error_ty = ty.errorUnionSet(); | |
| 843 | const payload_ty = ty.errorUnionPayload(mod); | |
| 844 | const error_ty = ty.errorUnionSet(mod); | |
| 855 | 845 | |
| 856 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 846 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 857 | 847 | return dg.renderValue(writer, error_ty, val, location); |
| 858 | 848 | } |
| 859 | 849 | |
| ... | ... | @@ -870,11 +860,11 @@ pub const DeclGen = struct { |
| 870 | 860 | return writer.writeAll(" }"); |
| 871 | 861 | }, |
| 872 | 862 | .Array, .Vector => { |
| 873 | const ai = ty.arrayInfo(); | |
| 874 | if (ai.elem_type.eql(Type.u8, dg.module)) { | |
| 863 | const ai = ty.arrayInfo(mod); | |
| 864 | if (ai.elem_type.eql(Type.u8, mod)) { | |
| 875 | 865 | var literal = stringLiteral(writer); |
| 876 | 866 | try literal.start(); |
| 877 | const c_len = ty.arrayLenIncludingSentinel(); | |
| 867 | const c_len = ty.arrayLenIncludingSentinel(mod); | |
| 878 | 868 | var index: u64 = 0; |
| 879 | 869 | while (index < c_len) : (index += 1) |
| 880 | 870 | try literal.writeChar(0xaa); |
| ... | ... | @@ -887,11 +877,11 @@ pub const DeclGen = struct { |
| 887 | 877 | } |
| 888 | 878 | |
| 889 | 879 | try writer.writeByte('{'); |
| 890 | const c_len = ty.arrayLenIncludingSentinel(); | |
| 880 | const c_len = ty.arrayLenIncludingSentinel(mod); | |
| 891 | 881 | var index: u64 = 0; |
| 892 | 882 | while (index < c_len) : (index += 1) { |
| 893 | 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 | 886 | return writer.writeByte('}'); |
| 897 | 887 | } |
| ... | ... | @@ -916,23 +906,129 @@ pub const DeclGen = struct { |
| 916 | 906 | } |
| 917 | 907 | unreachable; |
| 918 | 908 | } |
| 919 | switch (ty.zigTypeTag()) { | |
| 920 | .Int => switch (val.tag()) { | |
| 921 | .field_ptr, | |
| 922 | .elem_ptr, | |
| 923 | .opt_payload_ptr, | |
| 924 | .eu_payload_ptr, | |
| 925 | .decl_ref_mut, | |
| 926 | .decl_ref, | |
| 927 | => try dg.renderParentPtr(writer, val, ty, location), | |
| 928 | else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}), | |
| 909 | ||
| 910 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 911 | // types, not values | |
| 912 | .int_type, | |
| 913 | .ptr_type, | |
| 914 | .array_type, | |
| 915 | .vector_type, | |
| 916 | .opt_type, | |
| 917 | .anyframe_type, | |
| 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 | 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 }; | |
| 935 | const repr_ty = Type.initPayload(&repr_ty_pl.base); | |
| 1030 | // All unsigned ints matching float types are pre-allocated. | |
| 1031 | const repr_ty = mod.intType(.unsigned, bits) catch unreachable; | |
| 936 | 1032 | |
| 937 | 1033 | assert(bits <= 128); |
| 938 | 1034 | var repr_val_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; |
| ... | ... | @@ -943,21 +1039,15 @@ pub const DeclGen = struct { |
| 943 | 1039 | }; |
| 944 | 1040 | |
| 945 | 1041 | switch (bits) { |
| 946 | 16 => repr_val_big.set(@bitCast(u16, val.toFloat(f16))), | |
| 947 | 32 => repr_val_big.set(@bitCast(u32, val.toFloat(f32))), | |
| 948 | 64 => repr_val_big.set(@bitCast(u64, val.toFloat(f64))), | |
| 949 | 80 => repr_val_big.set(@bitCast(u80, val.toFloat(f80))), | |
| 1042 | 16 => repr_val_big.set(@bitCast(u16, val.toFloat(f16, mod))), | |
| 1043 | 32 => repr_val_big.set(@bitCast(u32, val.toFloat(f32, mod))), | |
| 1044 | 64 => repr_val_big.set(@bitCast(u64, val.toFloat(f64, mod))), | |
| 1045 | 80 => repr_val_big.set(@bitCast(u80, val.toFloat(f80, mod))), | |
| 950 | 1046 | 128 => repr_val_big.set(@bitCast(u128, f128_val)), |
| 951 | 1047 | else => unreachable, |
| 952 | 1048 | } |
| 953 | 1049 | |
| 954 | var repr_val_pl = Value.Payload.BigInt{ | |
| 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); | |
| 1050 | const repr_val = try mod.intValue_big(repr_ty, repr_val_big.toConst()); | |
| 961 | 1051 | |
| 962 | 1052 | try writer.writeAll("zig_cast_"); |
| 963 | 1053 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| ... | ... | @@ -968,10 +1058,10 @@ pub const DeclGen = struct { |
| 968 | 1058 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 969 | 1059 | try writer.writeByte('('); |
| 970 | 1060 | switch (bits) { |
| 971 | 16 => try writer.print("{x}", .{val.toFloat(f16)}), | |
| 972 | 32 => try writer.print("{x}", .{val.toFloat(f32)}), | |
| 973 | 64 => try writer.print("{x}", .{val.toFloat(f64)}), | |
| 974 | 80 => try writer.print("{x}", .{val.toFloat(f80)}), | |
| 1061 | 16 => try writer.print("{x}", .{val.toFloat(f16, mod)}), | |
| 1062 | 32 => try writer.print("{x}", .{val.toFloat(f32, mod)}), | |
| 1063 | 64 => try writer.print("{x}", .{val.toFloat(f64, mod)}), | |
| 1064 | 80 => try writer.print("{x}", .{val.toFloat(f80, mod)}), | |
| 975 | 1065 | 128 => try writer.print("{x}", .{f128_val}), |
| 976 | 1066 | else => unreachable, |
| 977 | 1067 | } |
| ... | ... | @@ -1011,10 +1101,10 @@ pub const DeclGen = struct { |
| 1011 | 1101 | if (std.math.isNan(f128_val)) switch (bits) { |
| 1012 | 1102 | // We only actually need to pass the significand, but it will get |
| 1013 | 1103 | // properly masked anyway, so just pass the whole value. |
| 1014 | 16 => try writer.print("\"0x{x}\"", .{@bitCast(u16, val.toFloat(f16))}), | |
| 1015 | 32 => try writer.print("\"0x{x}\"", .{@bitCast(u32, val.toFloat(f32))}), | |
| 1016 | 64 => try writer.print("\"0x{x}\"", .{@bitCast(u64, val.toFloat(f64))}), | |
| 1017 | 80 => try writer.print("\"0x{x}\"", .{@bitCast(u80, val.toFloat(f80))}), | |
| 1104 | 16 => try writer.print("\"0x{x}\"", .{@bitCast(u16, val.toFloat(f16, mod))}), | |
| 1105 | 32 => try writer.print("\"0x{x}\"", .{@bitCast(u32, val.toFloat(f32, mod))}), | |
| 1106 | 64 => try writer.print("\"0x{x}\"", .{@bitCast(u64, val.toFloat(f64, mod))}), | |
| 1107 | 80 => try writer.print("\"0x{x}\"", .{@bitCast(u80, val.toFloat(f80, mod))}), | |
| 1018 | 1108 | 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}), |
| 1019 | 1109 | else => unreachable, |
| 1020 | 1110 | }; |
| ... | ... | @@ -1023,173 +1113,80 @@ pub const DeclGen = struct { |
| 1023 | 1113 | } |
| 1024 | 1114 | try writer.print("{x}", .{try dg.fmtIntLiteral(repr_ty, repr_val, location)}); |
| 1025 | 1115 | if (!empty) try writer.writeByte(')'); |
| 1026 | return; | |
| 1027 | 1116 | }, |
| 1028 | .Pointer => switch (val.tag()) { | |
| 1029 | .null_value, .zero => if (ty.isSlice()) { | |
| 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 => { | |
| 1117 | .ptr => |ptr| { | |
| 1118 | if (ptr.len != .none) { | |
| 1047 | 1119 | if (!location.isInitializer()) { |
| 1048 | 1120 | try writer.writeByte('('); |
| 1049 | 1121 | try dg.renderType(writer, ty); |
| 1050 | 1122 | try writer.writeByte(')'); |
| 1051 | 1123 | } |
| 1052 | ||
| 1053 | const slice = val.castTag(.slice).?.data; | |
| 1054 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 1055 | ||
| 1056 | 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 | ||
| 1091 | // First try specific tag representations for more efficiency. | |
| 1092 | switch (val.tag()) { | |
| 1093 | .undef, .empty_struct_value, .empty_array => { | |
| 1094 | const ai = ty.arrayInfo(); | |
| 1095 | try writer.writeByte('{'); | |
| 1096 | if (ai.sentinel) |s| { | |
| 1097 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1098 | } else { | |
| 1099 | try writer.writeByte('0'); | |
| 1100 | } | |
| 1101 | try writer.writeByte('}'); | |
| 1102 | }, | |
| 1103 | .bytes, .str_lit => |t| { | |
| 1104 | const bytes = switch (t) { | |
| 1105 | .bytes => val.castTag(.bytes).?.data, | |
| 1106 | .str_lit => bytes: { | |
| 1107 | const str_lit = val.castTag(.str_lit).?.data; | |
| 1108 | break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 1109 | }, | |
| 1126 | const ptr_location = switch (ptr.len) { | |
| 1127 | .none => location, | |
| 1128 | else => initializer_type, | |
| 1129 | }; | |
| 1130 | const ptr_ty = switch (ptr.len) { | |
| 1131 | .none => ty, | |
| 1132 | else => ty.slicePtrFieldType(mod), | |
| 1133 | }; | |
| 1134 | const ptr_val = switch (ptr.len) { | |
| 1135 | .none => val, | |
| 1136 | else => val.slicePtr(mod), | |
| 1137 | }; | |
| 1138 | switch (ptr.addr) { | |
| 1139 | .decl, .mut_decl => try dg.renderDeclValue( | |
| 1140 | writer, | |
| 1141 | ptr_ty, | |
| 1142 | ptr_val, | |
| 1143 | switch (ptr.addr) { | |
| 1144 | .decl => |decl| decl, | |
| 1145 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 1110 | 1146 | else => unreachable, |
| 1111 | }; | |
| 1112 | const sentinel = if (ty.sentinel()) |sentinel| @intCast(u8, sentinel.toUnsignedInt(target)) else null; | |
| 1113 | try writer.print("{s}", .{ | |
| 1114 | fmtStringLiteral(bytes[0..@intCast(usize, ty.arrayLen())], sentinel), | |
| 1147 | }, | |
| 1148 | ptr_location, | |
| 1149 | ), | |
| 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 => { | |
| 1118 | // Fall back to generic implementation. | |
| 1119 | var arena = std.heap.ArenaAllocator.init(dg.gpa); | |
| 1120 | defer arena.deinit(); | |
| 1121 | const arena_allocator = arena.allocator(); | |
| 1122 | ||
| 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 | }, | |
| 1157 | .eu_payload, | |
| 1158 | .opt_payload, | |
| 1159 | .elem, | |
| 1160 | .field, | |
| 1161 | => try dg.renderParentPtr(writer, ptr_val.ip_index, ptr_location), | |
| 1162 | .comptime_field => unreachable, | |
| 1172 | 1163 | } |
| 1173 | }, | |
| 1174 | .Bool => { | |
| 1175 | if (val.toBool()) { | |
| 1176 | return writer.writeAll("true"); | |
| 1177 | } else { | |
| 1178 | return writer.writeAll("false"); | |
| 1164 | if (ptr.len != .none) { | |
| 1165 | try writer.writeAll(", "); | |
| 1166 | try dg.renderValue(writer, Type.usize, ptr.len.toValue(), initializer_type); | |
| 1167 | try writer.writeByte('}'); | |
| 1179 | 1168 | } |
| 1180 | 1169 | }, |
| 1181 | .Optional => { | |
| 1182 | var opt_buf: Type.Payload.ElemType = undefined; | |
| 1183 | const payload_ty = ty.optionalChild(&opt_buf); | |
| 1170 | .opt => |opt| { | |
| 1171 | const payload_ty = ty.optionalChild(mod); | |
| 1184 | 1172 | |
| 1185 | const is_null_val = Value.makeBool(val.tag() == .null_value); | |
| 1186 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) | |
| 1173 | const is_null_val = Value.makeBool(opt.val == .none); | |
| 1174 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 1187 | 1175 | return dg.renderValue(writer, Type.bool, is_null_val, location); |
| 1188 | 1176 | |
| 1189 | if (ty.optionalReprIsPayload()) { | |
| 1190 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else val; | |
| 1191 | return dg.renderValue(writer, payload_ty, payload_val, location); | |
| 1192 | } | |
| 1177 | if (ty.optionalReprIsPayload(mod)) return dg.renderValue( | |
| 1178 | writer, | |
| 1179 | payload_ty, | |
| 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 | 1191 | if (!location.isInitializer()) { |
| 1195 | 1192 | try writer.writeByte('('); |
| ... | ... | @@ -1197,93 +1194,74 @@ pub const DeclGen = struct { |
| 1197 | 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 | 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 | 1202 | try writer.writeAll(", .is_null = "); |
| 1205 | 1203 | try dg.renderValue(writer, Type.bool, is_null_val, initializer_type); |
| 1206 | 1204 | try writer.writeAll(" }"); |
| 1207 | 1205 | }, |
| 1208 | .ErrorSet => { | |
| 1209 | if (val.castTag(.@"error")) |error_pl| { | |
| 1210 | // Error values are already defined by genErrDecls. | |
| 1211 | try writer.print("zig_error_{}", .{fmtIdent(error_pl.data.name)}); | |
| 1212 | } else { | |
| 1213 | try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, .Other)}); | |
| 1214 | } | |
| 1215 | }, | |
| 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; | |
| 1206 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 1207 | .array_type, .vector_type => { | |
| 1208 | if (location == .FunctionArgument) { | |
| 1209 | try writer.writeByte('('); | |
| 1210 | try dg.renderType(writer, ty); | |
| 1211 | try writer.writeByte(')'); | |
| 1212 | } | |
| 1213 | // Fall back to generic implementation. | |
| 1220 | 1214 | |
| 1221 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1222 | return dg.renderValue(writer, error_ty, error_val, location); | |
| 1223 | } | |
| 1215 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal | |
| 1216 | const max_string_initializer_len = 65535; | |
| 1224 | 1217 | |
| 1225 | if (!location.isInitializer()) { | |
| 1226 | try writer.writeByte('('); | |
| 1227 | try dg.renderType(writer, ty); | |
| 1228 | try writer.writeByte(')'); | |
| 1229 | } | |
| 1230 | ||
| 1231 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; | |
| 1232 | try writer.writeAll("{ .payload = "); | |
| 1233 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); | |
| 1234 | try writer.writeAll(", .error = "); | |
| 1235 | try dg.renderValue(writer, error_ty, error_val, initializer_type); | |
| 1236 | try writer.writeAll(" }"); | |
| 1237 | }, | |
| 1238 | .Enum => { | |
| 1239 | switch (val.tag()) { | |
| 1240 | .enum_field_index => { | |
| 1241 | const field_index = val.castTag(.enum_field_index).?.data; | |
| 1242 | switch (ty.tag()) { | |
| 1243 | .enum_simple => return writer.print("{d}", .{field_index}), | |
| 1244 | .enum_full, .enum_nonexhaustive => { | |
| 1245 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | |
| 1246 | if (enum_full.values.count() != 0) { | |
| 1247 | const tag_val = enum_full.values.keys()[field_index]; | |
| 1248 | return dg.renderValue(writer, enum_full.tag_ty, tag_val, location); | |
| 1249 | } else { | |
| 1250 | return writer.print("{d}", .{field_index}); | |
| 1251 | } | |
| 1252 | }, | |
| 1253 | .enum_numbered => { | |
| 1254 | const enum_obj = ty.castTag(.enum_numbered).?.data; | |
| 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, | |
| 1218 | const ai = ty.arrayInfo(mod); | |
| 1219 | if (ai.elem_type.eql(Type.u8, mod)) { | |
| 1220 | if (ai.len <= max_string_initializer_len) { | |
| 1221 | var literal = stringLiteral(writer); | |
| 1222 | try literal.start(); | |
| 1223 | var index: usize = 0; | |
| 1224 | while (index < ai.len) : (index += 1) { | |
| 1225 | const elem_val = try val.elemValue(mod, index); | |
| 1226 | const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 1227 | try literal.writeChar(elem_val_u8); | |
| 1228 | } | |
| 1229 | if (ai.sentinel) |s| { | |
| 1230 | const s_u8 = @intCast(u8, s.toUnsignedInt(mod)); | |
| 1231 | if (s_u8 != 0) try literal.writeChar(s_u8); | |
| 1232 | } | |
| 1233 | try literal.end(); | |
| 1234 | } else { | |
| 1235 | try writer.writeByte('{'); | |
| 1236 | var index: usize = 0; | |
| 1237 | while (index < ai.len) : (index += 1) { | |
| 1238 | if (index != 0) try writer.writeByte(','); | |
| 1239 | const elem_val = try val.elemValue(mod, index); | |
| 1240 | const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 1241 | try writer.print("'\\x{x}'", .{elem_val_u8}); | |
| 1242 | } | |
| 1243 | if (ai.sentinel) |s| { | |
| 1244 | if (index != 0) try writer.writeByte(','); | |
| 1245 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1246 | } | |
| 1247 | try writer.writeByte('}'); | |
| 1263 | 1248 | } |
| 1264 | }, | |
| 1265 | else => { | |
| 1266 | var int_tag_ty_buffer: Type.Payload.Bits = undefined; | |
| 1267 | const int_tag_ty = ty.intTagType(&int_tag_ty_buffer); | |
| 1268 | return dg.renderValue(writer, int_tag_ty, val, location); | |
| 1269 | }, | |
| 1270 | } | |
| 1271 | }, | |
| 1272 | .Fn => switch (val.tag()) { | |
| 1273 | .function => { | |
| 1274 | const decl = val.castTag(.function).?.data.owner_decl; | |
| 1275 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1276 | }, | |
| 1277 | .extern_fn => { | |
| 1278 | const decl = val.castTag(.extern_fn).?.data.owner_decl; | |
| 1279 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1249 | } else { | |
| 1250 | try writer.writeByte('{'); | |
| 1251 | var index: usize = 0; | |
| 1252 | while (index < ai.len) : (index += 1) { | |
| 1253 | if (index != 0) try writer.writeByte(','); | |
| 1254 | const elem_val = try val.elemValue(mod, index); | |
| 1255 | try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type); | |
| 1256 | } | |
| 1257 | if (ai.sentinel) |s| { | |
| 1258 | if (index != 0) try writer.writeByte(','); | |
| 1259 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1260 | } | |
| 1261 | try writer.writeByte('}'); | |
| 1262 | } | |
| 1280 | 1263 | }, |
| 1281 | else => unreachable, | |
| 1282 | }, | |
| 1283 | .Struct => switch (ty.containerLayout()) { | |
| 1284 | .Auto, .Extern => { | |
| 1285 | const field_vals = val.castTag(.aggregate).?.data; | |
| 1286 | ||
| 1264 | .anon_struct_type => |tuple| { | |
| 1287 | 1265 | if (!location.isInitializer()) { |
| 1288 | 1266 | try writer.writeByte('('); |
| 1289 | 1267 | try dg.renderType(writer, ty); |
| ... | ... | @@ -1292,133 +1270,184 @@ pub const DeclGen = struct { |
| 1292 | 1270 | |
| 1293 | 1271 | try writer.writeByte('{'); |
| 1294 | 1272 | var empty = true; |
| 1295 | for (field_vals, 0..) |field_val, field_i| { | |
| 1296 | if (ty.structFieldIsComptime(field_i)) continue; | |
| 1297 | const field_ty = ty.structFieldType(field_i); | |
| 1298 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1273 | for (tuple.types, tuple.values, 0..) |field_ty, comptime_ty, field_i| { | |
| 1274 | if (comptime_ty != .none) continue; | |
| 1275 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1299 | 1276 | |
| 1300 | 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 | 1289 | empty = false; |
| 1304 | 1290 | } |
| 1305 | 1291 | try writer.writeByte('}'); |
| 1306 | 1292 | }, |
| 1307 | .Packed => { | |
| 1308 | const field_vals = val.castTag(.aggregate).?.data; | |
| 1309 | const int_info = ty.intInfo(target); | |
| 1293 | .struct_type => |struct_type| { | |
| 1294 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 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{ | |
| 1312 | .base = .{ .tag = .int_unsigned }, | |
| 1313 | .data = Type.smallestUnsignedBits(int_info.bits - 1), | |
| 1314 | }; | |
| 1315 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); | |
| 1303 | try writer.writeByte('{'); | |
| 1304 | var empty = true; | |
| 1305 | for (struct_obj.fields.values(), 0..) |field, field_i| { | |
| 1306 | if (field.is_comptime) continue; | |
| 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 }; | |
| 1318 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | |
| 1327 | const bits = Type.smallestUnsignedBits(int_info.bits - 1); | |
| 1328 | const bit_offset_ty = try mod.intType(.unsigned, bits); | |
| 1319 | 1329 | |
| 1320 | var eff_num_fields: usize = 0; | |
| 1321 | for (0..field_vals.len) |field_i| { | |
| 1322 | if (ty.structFieldIsComptime(field_i)) continue; | |
| 1323 | const field_ty = ty.structFieldType(field_i); | |
| 1324 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1330 | var bit_offset: u64 = 0; | |
| 1331 | var eff_num_fields: usize = 0; | |
| 1325 | 1332 | |
| 1326 | eff_num_fields += 1; | |
| 1327 | } | |
| 1333 | for (struct_obj.fields.values()) |field| { | |
| 1334 | if (field.is_comptime) continue; | |
| 1335 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1328 | 1336 | |
| 1329 | if (eff_num_fields == 0) { | |
| 1330 | try writer.writeByte('('); | |
| 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 | } | |
| 1337 | eff_num_fields += 1; | |
| 1338 | } | |
| 1341 | 1339 | |
| 1342 | var eff_index: usize = 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); | |
| 1340 | if (eff_num_fields == 0) { | |
| 1353 | 1341 | try writer.writeByte('('); |
| 1354 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); | |
| 1355 | try writer.writeAll(", "); | |
| 1356 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1342 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | |
| 1357 | 1343 | try writer.writeByte(')'); |
| 1358 | } else { | |
| 1359 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); | |
| 1360 | } | |
| 1361 | ||
| 1362 | if (needs_closing_paren) try writer.writeByte(')'); | |
| 1363 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | |
| 1364 | ||
| 1365 | bit_offset_val_pl.data += field_ty.bitSize(target); | |
| 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(')'); | |
| 1344 | } else if (ty.bitSize(mod) > 64) { | |
| 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)) | |
| 1346 | var num_or = eff_num_fields - 1; | |
| 1347 | while (num_or > 0) : (num_or -= 1) { | |
| 1348 | try writer.writeAll("zig_or_"); | |
| 1349 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1350 | try writer.writeByte('('); | |
| 1351 | } | |
| 1382 | 1352 | |
| 1383 | if (bit_offset_val_pl.data != 0) { | |
| 1384 | try dg.renderValue(writer, field_ty, field_val, .Other); | |
| 1385 | try writer.writeAll(" << "); | |
| 1386 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1353 | var eff_index: usize = 0; | |
| 1354 | var needs_closing_paren = false; | |
| 1355 | for (struct_obj.fields.values(), 0..) |field, field_i| { | |
| 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 | 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 | ||
| 1391 | bit_offset_val_pl.data += field_ty.bitSize(target); | |
| 1392 | empty = false; | |
| 1393 | } | |
| 1394 | try writer.writeByte(')'); | |
| 1424 | }, | |
| 1395 | 1425 | } |
| 1396 | 1426 | }, |
| 1427 | else => unreachable, | |
| 1397 | 1428 | }, |
| 1398 | .Union => { | |
| 1399 | const union_obj = val.castTag(.@"union").?.data; | |
| 1400 | ||
| 1429 | .un => |un| { | |
| 1401 | 1430 | if (!location.isInitializer()) { |
| 1402 | 1431 | try writer.writeByte('('); |
| 1403 | 1432 | try dg.renderType(writer, ty); |
| 1404 | 1433 | try writer.writeByte(')'); |
| 1405 | 1434 | } |
| 1406 | 1435 | |
| 1407 | const field_i = ty.unionTagFieldIndex(union_obj.tag, dg.module).?; | |
| 1408 | const field_ty = ty.unionFields().values()[field_i].ty; | |
| 1409 | const field_name = ty.unionFields().keys()[field_i]; | |
| 1410 | if (ty.containerLayout() == .Packed) { | |
| 1411 | if (field_ty.hasRuntimeBits()) { | |
| 1412 | if (field_ty.isPtrAtRuntime()) { | |
| 1436 | const field_i = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; | |
| 1437 | const field_ty = ty.unionFields(mod).values()[field_i].ty; | |
| 1438 | const field_name = ty.unionFields(mod).keys()[field_i]; | |
| 1439 | if (ty.containerLayout(mod) == .Packed) { | |
| 1440 | if (field_ty.hasRuntimeBits(mod)) { | |
| 1441 | if (field_ty.isPtrAtRuntime(mod)) { | |
| 1413 | 1442 | try writer.writeByte('('); |
| 1414 | 1443 | try dg.renderType(writer, ty); |
| 1415 | 1444 | try writer.writeByte(')'); |
| 1416 | } else if (field_ty.zigTypeTag() == .Float) { | |
| 1445 | } else if (field_ty.zigTypeTag(mod) == .Float) { | |
| 1417 | 1446 | try writer.writeByte('('); |
| 1418 | 1447 | try dg.renderType(writer, ty); |
| 1419 | 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 | 1451 | } else { |
| 1423 | 1452 | try writer.writeAll("0"); |
| 1424 | 1453 | } |
| ... | ... | @@ -1426,44 +1455,28 @@ pub const DeclGen = struct { |
| 1426 | 1455 | } |
| 1427 | 1456 | |
| 1428 | 1457 | try writer.writeByte('{'); |
| 1429 | if (ty.unionTagTypeSafety()) |tag_ty| { | |
| 1430 | const layout = ty.unionGetLayout(target); | |
| 1458 | if (ty.unionTagTypeSafety(mod)) |tag_ty| { | |
| 1459 | const layout = ty.unionGetLayout(mod); | |
| 1431 | 1460 | if (layout.tag_size != 0) { |
| 1432 | 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 | 1465 | if (layout.tag_size != 0) try writer.writeByte(','); |
| 1437 | 1466 | try writer.writeAll(" .payload = {"); |
| 1438 | 1467 | } |
| 1439 | if (field_ty.hasRuntimeBits()) { | |
| 1440 | try writer.print(" .{ } = ", .{fmtIdent(field_name)}); | |
| 1441 | try dg.renderValue(writer, field_ty, union_obj.val, initializer_type); | |
| 1468 | if (field_ty.hasRuntimeBits(mod)) { | |
| 1469 | try writer.print(" .{ } = ", .{fmtIdent(mod.intern_pool.stringToSlice(field_name))}); | |
| 1470 | try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type); | |
| 1442 | 1471 | try writer.writeByte(' '); |
| 1443 | } else for (ty.unionFields().values()) |field| { | |
| 1444 | if (!field.ty.hasRuntimeBits()) continue; | |
| 1472 | } else for (ty.unionFields(mod).values()) |field| { | |
| 1473 | if (!field.ty.hasRuntimeBits(mod)) continue; | |
| 1445 | 1474 | try dg.renderValue(writer, field.ty, Value.undef, initializer_type); |
| 1446 | 1475 | break; |
| 1447 | 1476 | } |
| 1448 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); | |
| 1477 | if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}'); | |
| 1449 | 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 | 1491 | }, |
| 1479 | 1492 | ) !void { |
| 1480 | 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 | 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 | 1500 | if (fn_info.cc == .Naked) { |
| 1488 | 1501 | switch (kind) { |
| 1489 | 1502 | .forward => try w.writeAll("zig_naked_decl "), |
| ... | ... | @@ -1491,14 +1504,13 @@ pub const DeclGen = struct { |
| 1491 | 1504 | else => unreachable, |
| 1492 | 1505 | } |
| 1493 | 1506 | } |
| 1494 | if (fn_decl.val.castTag(.function)) |func_payload| | |
| 1495 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); | |
| 1496 | if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn "); | |
| 1507 | if (fn_decl.val.getFunction(mod)) |func| if (func.is_cold) try w.writeAll("zig_cold "); | |
| 1508 | if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn "); | |
| 1497 | 1509 | |
| 1498 | 1510 | const trailing = try renderTypePrefix( |
| 1499 | 1511 | dg.decl_index, |
| 1500 | 1512 | store.*, |
| 1501 | module, | |
| 1513 | mod, | |
| 1502 | 1514 | w, |
| 1503 | 1515 | fn_cty_idx, |
| 1504 | 1516 | .suffix, |
| ... | ... | @@ -1512,8 +1524,8 @@ pub const DeclGen = struct { |
| 1512 | 1524 | |
| 1513 | 1525 | switch (kind) { |
| 1514 | 1526 | .forward => {}, |
| 1515 | .complete => if (fn_info.alignment > 0) | |
| 1516 | try w.print(" zig_align_fn({})", .{fn_info.alignment}), | |
| 1527 | .complete => if (fn_info.alignment.toByteUnitsOptional()) |a| | |
| 1528 | try w.print(" zig_align_fn({})", .{a}), | |
| 1517 | 1529 | else => unreachable, |
| 1518 | 1530 | } |
| 1519 | 1531 | |
| ... | ... | @@ -1525,7 +1537,7 @@ pub const DeclGen = struct { |
| 1525 | 1537 | try renderTypeSuffix( |
| 1526 | 1538 | dg.decl_index, |
| 1527 | 1539 | store.*, |
| 1528 | module, | |
| 1540 | mod, | |
| 1529 | 1541 | w, |
| 1530 | 1542 | fn_cty_idx, |
| 1531 | 1543 | .suffix, |
| ... | ... | @@ -1537,8 +1549,8 @@ pub const DeclGen = struct { |
| 1537 | 1549 | ); |
| 1538 | 1550 | |
| 1539 | 1551 | switch (kind) { |
| 1540 | .forward => if (fn_info.alignment > 0) | |
| 1541 | try w.print(" zig_align_fn({})", .{fn_info.alignment}), | |
| 1552 | .forward => if (fn_info.alignment.toByteUnitsOptional()) |a| | |
| 1553 | try w.print(" zig_align_fn({})", .{a}), | |
| 1542 | 1554 | .complete => {}, |
| 1543 | 1555 | else => unreachable, |
| 1544 | 1556 | } |
| ... | ... | @@ -1577,9 +1589,9 @@ pub const DeclGen = struct { |
| 1577 | 1589 | |
| 1578 | 1590 | fn renderCType(dg: *DeclGen, w: anytype, idx: CType.Index) error{ OutOfMemory, AnalysisFail }!void { |
| 1579 | 1591 | const store = &dg.ctypes.set; |
| 1580 | const module = dg.module; | |
| 1581 | _ = try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, .{}); | |
| 1582 | try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{}); | |
| 1592 | const mod = dg.module; | |
| 1593 | _ = try renderTypePrefix(dg.decl_index, store.*, mod, w, idx, .suffix, .{}); | |
| 1594 | try renderTypeSuffix(dg.decl_index, store.*, mod, w, idx, .suffix, .{}); | |
| 1583 | 1595 | } |
| 1584 | 1596 | |
| 1585 | 1597 | const IntCastContext = union(enum) { |
| ... | ... | @@ -1619,18 +1631,18 @@ pub const DeclGen = struct { |
| 1619 | 1631 | /// | > 64 bit integer | < 64 bit integer | zig_make_<dest_ty>(0, src) |
| 1620 | 1632 | /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src)) |
| 1621 | 1633 | fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void { |
| 1622 | const target = dg.module.getTarget(); | |
| 1623 | const dest_bits = dest_ty.bitSize(target); | |
| 1624 | const dest_int_info = dest_ty.intInfo(target); | |
| 1634 | const mod = dg.module; | |
| 1635 | const dest_bits = dest_ty.bitSize(mod); | |
| 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 | 1639 | const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { |
| 1628 | 1640 | .unsigned => Type.usize, |
| 1629 | 1641 | .signed => Type.isize, |
| 1630 | 1642 | } else src_ty; |
| 1631 | 1643 | |
| 1632 | const src_bits = src_eff_ty.bitSize(target); | |
| 1633 | const src_int_info = if (src_eff_ty.isAbiInt()) src_eff_ty.intInfo(target) else null; | |
| 1644 | const src_bits = src_eff_ty.bitSize(mod); | |
| 1645 | const src_int_info = if (src_eff_ty.isAbiInt(mod)) src_eff_ty.intInfo(mod) else null; | |
| 1634 | 1646 | if (dest_bits <= 64 and src_bits <= 64) { |
| 1635 | 1647 | const needs_cast = src_int_info == null or |
| 1636 | 1648 | (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or |
| ... | ... | @@ -1703,8 +1715,8 @@ pub const DeclGen = struct { |
| 1703 | 1715 | alignment: u32, |
| 1704 | 1716 | kind: CType.Kind, |
| 1705 | 1717 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1706 | const target = dg.module.getTarget(); | |
| 1707 | const alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)); | |
| 1718 | const mod = dg.module; | |
| 1719 | const alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)); | |
| 1708 | 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 | 1729 | alignas: CType.AlignAs, |
| 1718 | 1730 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1719 | 1731 | const store = &dg.ctypes.set; |
| 1720 | const module = dg.module; | |
| 1732 | const mod = dg.module; | |
| 1721 | 1733 | |
| 1722 | 1734 | switch (std.math.order(alignas.@"align", alignas.abi)) { |
| 1723 | 1735 | .lt => try w.print("zig_under_align({}) ", .{alignas.getAlign()}), |
| ... | ... | @@ -1726,25 +1738,20 @@ pub const DeclGen = struct { |
| 1726 | 1738 | } |
| 1727 | 1739 | |
| 1728 | 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 | 1742 | try w.print("{}", .{trailing}); |
| 1731 | 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 | 1747 | fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { |
| 1736 | switch (tv.val.tag()) { | |
| 1737 | .extern_fn => return true, | |
| 1738 | .function => { | |
| 1739 | const func = tv.val.castTag(.function).?.data; | |
| 1740 | return dg.module.decl_exports.contains(func.owner_decl); | |
| 1741 | }, | |
| 1742 | .variable => { | |
| 1743 | const variable = tv.val.castTag(.variable).?.data; | |
| 1744 | return dg.module.decl_exports.contains(variable.owner_decl); | |
| 1745 | }, | |
| 1748 | const mod = dg.module; | |
| 1749 | return switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 1750 | .variable => |variable| mod.decl_exports.contains(variable.decl), | |
| 1751 | .extern_func => true, | |
| 1752 | .func => |func| mod.decl_exports.contains(mod.funcPtr(func.index).owner_decl), | |
| 1746 | 1753 | else => unreachable, |
| 1747 | } | |
| 1754 | }; | |
| 1748 | 1755 | } |
| 1749 | 1756 | |
| 1750 | 1757 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| ... | ... | @@ -1819,7 +1826,7 @@ pub const DeclGen = struct { |
| 1819 | 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 | 1830 | const decl = dg.module.declPtr(decl_index); |
| 1824 | 1831 | const fwd_decl_writer = dg.fwd_decl.writer(); |
| 1825 | 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 | 1837 | fwd_decl_writer, |
| 1831 | 1838 | decl.ty, |
| 1832 | 1839 | .{ .decl = decl_index }, |
| 1833 | CQualifiers.init(.{ .@"const" = !variable.is_mutable }), | |
| 1840 | CQualifiers.init(.{ .@"const" = variable.is_const }), | |
| 1834 | 1841 | decl.@"align", |
| 1835 | 1842 | .complete, |
| 1836 | 1843 | ); |
| ... | ... | @@ -1838,19 +1845,20 @@ pub const DeclGen = struct { |
| 1838 | 1845 | } |
| 1839 | 1846 | |
| 1840 | 1847 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void { |
| 1841 | const decl = dg.module.declPtr(decl_index); | |
| 1842 | dg.module.markDeclAlive(decl); | |
| 1843 | ||
| 1844 | if (dg.module.decl_exports.get(decl_index)) |exports| { | |
| 1845 | try writer.writeAll(exports.items[export_index].options.name); | |
| 1846 | } else if (decl.isExtern()) { | |
| 1847 | try writer.writeAll(mem.span(decl.name)); | |
| 1848 | const mod = dg.module; | |
| 1849 | const decl = mod.declPtr(decl_index); | |
| 1850 | try mod.markDeclAlive(decl); | |
| 1851 | ||
| 1852 | if (mod.decl_exports.get(decl_index)) |exports| { | |
| 1853 | try writer.print("{}", .{exports.items[export_index].opts.name.fmt(&mod.intern_pool)}); | |
| 1854 | } else if (decl.isExtern(mod)) { | |
| 1855 | try writer.print("{}", .{decl.name.fmt(&mod.intern_pool)}); | |
| 1848 | 1856 | } else { |
| 1849 | 1857 | // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), |
| 1850 | 1858 | // expand to 3x the length of its input, but let's cut it off at a much shorter limit. |
| 1851 | 1859 | var name: [100]u8 = undefined; |
| 1852 | 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 | 1862 | error.NoSpaceLeft => {}, |
| 1855 | 1863 | }; |
| 1856 | 1864 | try writer.print("{}__{d}", .{ |
| ... | ... | @@ -1894,18 +1902,18 @@ pub const DeclGen = struct { |
| 1894 | 1902 | .bits => {}, |
| 1895 | 1903 | } |
| 1896 | 1904 | |
| 1897 | const target = dg.module.getTarget(); | |
| 1898 | const int_info = if (ty.isAbiInt()) ty.intInfo(target) else std.builtin.Type.Int{ | |
| 1905 | const mod = dg.module; | |
| 1906 | const int_info = if (ty.isAbiInt(mod)) ty.intInfo(mod) else std.builtin.Type.Int{ | |
| 1899 | 1907 | .signedness = .unsigned, |
| 1900 | .bits = @intCast(u16, ty.bitSize(target)), | |
| 1908 | .bits = @intCast(u16, ty.bitSize(mod)), | |
| 1901 | 1909 | }; |
| 1902 | 1910 | |
| 1903 | 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 | 1914 | try writer.print(", {}", .{try dg.fmtIntLiteral( |
| 1907 | if (is_big) Type.u16 else Type.u8, | |
| 1908 | Value.initPayload(&bits_pl.base), | |
| 1915 | bits_ty, | |
| 1916 | try mod.intValue(bits_ty, int_info.bits), | |
| 1909 | 1917 | .FunctionArgument, |
| 1910 | 1918 | )}); |
| 1911 | 1919 | } |
| ... | ... | @@ -1916,6 +1924,7 @@ pub const DeclGen = struct { |
| 1916 | 1924 | val: Value, |
| 1917 | 1925 | loc: ValueRenderLocation, |
| 1918 | 1926 | ) !std.fmt.Formatter(formatIntLiteral) { |
| 1927 | const mod = dg.module; | |
| 1919 | 1928 | const kind: CType.Kind = switch (loc) { |
| 1920 | 1929 | .FunctionArgument => .parameter, |
| 1921 | 1930 | .Initializer, .Other => .complete, |
| ... | ... | @@ -1923,7 +1932,7 @@ pub const DeclGen = struct { |
| 1923 | 1932 | }; |
| 1924 | 1933 | return std.fmt.Formatter(formatIntLiteral){ .data = .{ |
| 1925 | 1934 | .dg = dg, |
| 1926 | .int_info = ty.intInfo(dg.module.getTarget()), | |
| 1935 | .int_info = ty.intInfo(mod), | |
| 1927 | 1936 | .kind = kind, |
| 1928 | 1937 | .cty = try dg.typeToCType(ty, kind), |
| 1929 | 1938 | .val = val, |
| ... | ... | @@ -1979,7 +1988,7 @@ fn renderTypeName( |
| 1979 | 1988 | try w.print("{s} {s}{}__{d}", .{ |
| 1980 | 1989 | @tagName(tag)["fwd_".len..], |
| 1981 | 1990 | attributes, |
| 1982 | fmtIdent(mem.span(mod.declPtr(owner_decl).name)), | |
| 1991 | fmtIdent(mod.intern_pool.stringToSlice(mod.declPtr(owner_decl).name)), | |
| 1983 | 1992 | @enumToInt(owner_decl), |
| 1984 | 1993 | }); |
| 1985 | 1994 | }, |
| ... | ... | @@ -2392,15 +2401,20 @@ pub fn genGlobalAsm(mod: *Module, writer: anytype) !void { |
| 2392 | 2401 | } |
| 2393 | 2402 | |
| 2394 | 2403 | pub fn genErrDecls(o: *Object) !void { |
| 2404 | const mod = o.dg.module; | |
| 2395 | 2405 | const writer = o.writer(); |
| 2396 | 2406 | |
| 2397 | 2407 | try writer.writeAll("enum {\n"); |
| 2398 | 2408 | o.indent_writer.pushIndent(); |
| 2399 | 2409 | var max_name_len: usize = 0; |
| 2400 | for (o.dg.module.error_name_list.items, 0..) |name, value| { | |
| 2401 | max_name_len = std.math.max(name.len, max_name_len); | |
| 2402 | var err_pl = Value.Payload.Error{ .data = .{ .name = name } }; | |
| 2403 | try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_pl.base), .Other); | |
| 2410 | for (mod.global_error_set.keys()[1..], 1..) |name_nts, value| { | |
| 2411 | const name = mod.intern_pool.stringToSlice(name_nts); | |
| 2412 | max_name_len = @max(name.len, max_name_len); | |
| 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 | 2418 | try writer.print(" = {d}u,\n", .{value}); |
| 2405 | 2419 | } |
| 2406 | 2420 | o.indent_writer.popIndent(); |
| ... | ... | @@ -2412,40 +2426,44 @@ pub fn genErrDecls(o: *Object) !void { |
| 2412 | 2426 | defer o.dg.gpa.free(name_buf); |
| 2413 | 2427 | |
| 2414 | 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 | 2431 | @memcpy(name_buf[name_prefix.len..][0..name.len], name); |
| 2417 | 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 }; | |
| 2420 | const name_ty = Type.initPayload(&name_ty_pl.base); | |
| 2421 | ||
| 2422 | var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name }; | |
| 2423 | const name_val = Value.initPayload(&name_pl.base); | |
| 2434 | const name_ty = try mod.arrayType(.{ | |
| 2435 | .len = name.len, | |
| 2436 | .child = .u8_type, | |
| 2437 | .sentinel = .zero_u8, | |
| 2438 | }); | |
| 2439 | const name_val = try mod.intern(.{ .aggregate = .{ | |
| 2440 | .ty = name_ty.toIntern(), | |
| 2441 | .storage = .{ .bytes = name }, | |
| 2442 | } }); | |
| 2424 | 2443 | |
| 2425 | 2444 | try writer.writeAll("static "); |
| 2426 | 2445 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete); |
| 2427 | 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 | 2448 | try writer.writeAll(";\n"); |
| 2430 | 2449 | } |
| 2431 | 2450 | |
| 2432 | var name_array_ty_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{ | |
| 2433 | .len = o.dg.module.error_name_list.items.len, | |
| 2434 | .elem_type = Type.initTag(.const_slice_u8_sentinel_0), | |
| 2435 | } }; | |
| 2436 | const name_array_ty = Type.initPayload(&name_array_ty_pl.base); | |
| 2451 | const name_array_ty = try mod.arrayType(.{ | |
| 2452 | .len = mod.global_error_set.count(), | |
| 2453 | .child = .slice_const_u8_sentinel_0_type, | |
| 2454 | }); | |
| 2437 | 2455 | |
| 2438 | 2456 | try writer.writeAll("static "); |
| 2439 | 2457 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete); |
| 2440 | 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 | 2461 | if (value != 0) try writer.writeByte(','); |
| 2443 | 2462 | |
| 2444 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len }; | |
| 2445 | const len_val = Value.initPayload(&len_pl.base); | |
| 2463 | const len_val = try mod.intValue(Type.usize, name.len); | |
| 2446 | 2464 | |
| 2447 | 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 | 2469 | try writer.writeAll("};\n"); |
| ... | ... | @@ -2455,20 +2473,23 @@ fn genExports(o: *Object) !void { |
| 2455 | 2473 | const tracy = trace(@src()); |
| 2456 | 2474 | defer tracy.end(); |
| 2457 | 2475 | |
| 2476 | const mod = o.dg.module; | |
| 2477 | const ip = &mod.intern_pool; | |
| 2458 | 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 | 2480 | for (exports.items[1..], 1..) |@"export", i| { |
| 2461 | 2481 | try fwd_decl_writer.writeAll("zig_export("); |
| 2462 | 2482 | try o.dg.renderFunctionSignature(fwd_decl_writer, o.dg.decl_index.unwrap().?, .forward, .{ .export_index = @intCast(u32, i) }); |
| 2463 | 2483 | try fwd_decl_writer.print(", {s}, {s});\n", .{ |
| 2464 | fmtStringLiteral(exports.items[0].options.name, null), | |
| 2465 | fmtStringLiteral(@"export".options.name, null), | |
| 2484 | fmtStringLiteral(ip.stringToSlice(exports.items[0].opts.name), null), | |
| 2485 | fmtStringLiteral(ip.stringToSlice(@"export".opts.name), null), | |
| 2466 | 2486 | }); |
| 2467 | 2487 | } |
| 2468 | 2488 | } |
| 2469 | 2489 | } |
| 2470 | 2490 | |
| 2471 | 2491 | pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2492 | const mod = o.dg.module; | |
| 2472 | 2493 | const w = o.writer(); |
| 2473 | 2494 | const key = lazy_fn.key_ptr.*; |
| 2474 | 2495 | const val = lazy_fn.value_ptr; |
| ... | ... | @@ -2477,7 +2498,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2477 | 2498 | .tag_name => { |
| 2478 | 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 | 2503 | try w.writeAll("static "); |
| 2483 | 2504 | try o.dg.renderType(w, name_slice_ty); |
| ... | ... | @@ -2486,34 +2507,30 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2486 | 2507 | try w.writeByte('('); |
| 2487 | 2508 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete); |
| 2488 | 2509 | try w.writeAll(") {\n switch (tag) {\n"); |
| 2489 | for (enum_ty.enumFields().keys(), 0..) |name, index| { | |
| 2490 | var tag_pl: Value.Payload.U32 = .{ | |
| 2491 | .base = .{ .tag = .enum_field_index }, | |
| 2492 | .data = @intCast(u32, index), | |
| 2493 | }; | |
| 2494 | const tag_val = Value.initPayload(&tag_pl.base); | |
| 2510 | for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| { | |
| 2511 | const index = @intCast(u32, index_usize); | |
| 2512 | const name = mod.intern_pool.stringToSlice(name_ip); | |
| 2513 | const tag_val = try mod.enumValueFieldIndex(enum_ty, index); | |
| 2495 | 2514 | |
| 2496 | var int_pl: Value.Payload.U64 = undefined; | |
| 2497 | const int_val = tag_val.enumToInt(enum_ty, &int_pl); | |
| 2515 | const int_val = try tag_val.enumToInt(enum_ty, mod); | |
| 2498 | 2516 | |
| 2499 | var name_ty_pl = Type.Payload.Len{ | |
| 2500 | .base = .{ .tag = .array_u8_sentinel_0 }, | |
| 2501 | .data = name.len, | |
| 2502 | }; | |
| 2503 | const name_ty = Type.initPayload(&name_ty_pl.base); | |
| 2504 | ||
| 2505 | var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name }; | |
| 2506 | const name_val = Value.initPayload(&name_pl.base); | |
| 2507 | ||
| 2508 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len }; | |
| 2509 | const len_val = Value.initPayload(&len_pl.base); | |
| 2517 | const name_ty = try mod.arrayType(.{ | |
| 2518 | .len = name.len, | |
| 2519 | .child = .u8_type, | |
| 2520 | .sentinel = .zero_u8, | |
| 2521 | }); | |
| 2522 | const name_val = try mod.intern(.{ .aggregate = .{ | |
| 2523 | .ty = name_ty.toIntern(), | |
| 2524 | .storage = .{ .bytes = name }, | |
| 2525 | } }); | |
| 2526 | const len_val = try mod.intValue(Type.usize, name.len); | |
| 2510 | 2527 | |
| 2511 | 2528 | try w.print(" case {}: {{\n static ", .{ |
| 2512 | 2529 | try o.dg.fmtIntLiteral(enum_ty, int_val, .Other), |
| 2513 | 2530 | }); |
| 2514 | 2531 | try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete); |
| 2515 | 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 | 2534 | try w.writeAll(";\n return ("); |
| 2518 | 2535 | try o.dg.renderType(w, name_slice_ty); |
| 2519 | 2536 | try w.print("){{{}, {}}};\n", .{ |
| ... | ... | @@ -2529,7 +2546,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2529 | 2546 | try w.writeAll("}\n"); |
| 2530 | 2547 | }, |
| 2531 | 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 | 2550 | const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete); |
| 2534 | 2551 | const fn_info = fn_cty.cast(CType.Payload.Function).?.data; |
| 2535 | 2552 | |
| ... | ... | @@ -2646,19 +2663,19 @@ pub fn genDecl(o: *Object) !void { |
| 2646 | 2663 | const tracy = trace(@src()); |
| 2647 | 2664 | defer tracy.end(); |
| 2648 | 2665 | |
| 2666 | const mod = o.dg.module; | |
| 2649 | 2667 | const decl = o.dg.decl.?; |
| 2650 | 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; | |
| 2654 | if (tv.val.tag() == .extern_fn) { | |
| 2671 | if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return; | |
| 2672 | if (tv.val.getExternFunc(mod)) |_| { | |
| 2655 | 2673 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2656 | 2674 | try fwd_decl_writer.writeAll("zig_extern "); |
| 2657 | 2675 | try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 }); |
| 2658 | 2676 | try fwd_decl_writer.writeAll(";\n"); |
| 2659 | 2677 | try genExports(o); |
| 2660 | } else if (tv.val.castTag(.variable)) |var_payload| { | |
| 2661 | const variable: *Module.Var = var_payload.data; | |
| 2678 | } else if (tv.val.getVariable(mod)) |variable| { | |
| 2662 | 2679 | try o.dg.renderFwdDecl(decl_c_value.decl, variable); |
| 2663 | 2680 | try genExports(o); |
| 2664 | 2681 | |
| ... | ... | @@ -2669,11 +2686,12 @@ pub fn genDecl(o: *Object) !void { |
| 2669 | 2686 | if (!is_global) try w.writeAll("static "); |
| 2670 | 2687 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); |
| 2671 | 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 | 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 | 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 | 2695 | try w.writeByte(';'); |
| 2678 | 2696 | try o.indent_writer.insertNewline(); |
| 2679 | 2697 | } else { |
| ... | ... | @@ -2686,9 +2704,10 @@ pub fn genDecl(o: *Object) !void { |
| 2686 | 2704 | |
| 2687 | 2705 | const w = o.writer(); |
| 2688 | 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 | 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 | 2711 | try w.writeAll(" = "); |
| 2693 | 2712 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); |
| 2694 | 2713 | try w.writeAll(";\n"); |
| ... | ... | @@ -2704,8 +2723,9 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
| 2704 | 2723 | .val = dg.decl.?.val, |
| 2705 | 2724 | }; |
| 2706 | 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 | 2729 | .Fn => { |
| 2710 | 2730 | const is_global = dg.declIsGlobal(tv); |
| 2711 | 2731 | if (is_global) { |
| ... | ... | @@ -2791,17 +2811,18 @@ fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []con |
| 2791 | 2811 | } |
| 2792 | 2812 | |
| 2793 | 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 | 2816 | const air_tags = f.air.instructions.items(.tag); |
| 2795 | 2817 | |
| 2796 | 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 | 2820 | continue; |
| 2799 | } | |
| 2800 | 2821 | |
| 2801 | 2822 | const result_value = switch (air_tags[inst]) { |
| 2802 | 2823 | // zig fmt: off |
| 2803 | .constant => unreachable, // excluded from function bodies | |
| 2804 | .const_ty => unreachable, // excluded from function bodies | |
| 2824 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 2825 | ||
| 2805 | 2826 | .arg => try airArg(f, inst), |
| 2806 | 2827 | |
| 2807 | 2828 | .trap => try airTrap(f.object.writer()), |
| ... | ... | @@ -2826,10 +2847,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2826 | 2847 | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .none), |
| 2827 | 2848 | .rem => blk: { |
| 2828 | 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 | 2851 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), |
| 2831 | 2852 | // so we only check one. |
| 2832 | break :blk if (lhs_scalar_ty.isInt()) | |
| 2853 | break :blk if (lhs_scalar_ty.isInt(mod)) | |
| 2833 | 2854 | try airBinOp(f, inst, "%", "rem", .none) |
| 2834 | 2855 | else |
| 2835 | 2856 | try airBinFloatOp(f, inst, "fmod"); |
| ... | ... | @@ -3077,7 +3098,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 3077 | 3098 | fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue { |
| 3078 | 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 | 3102 | const operand = try f.resolveInst(ty_op.operand); |
| 3082 | 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 | 3116 | } |
| 3096 | 3117 | |
| 3097 | 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 | 3121 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3100 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3122 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3101 | 3123 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3102 | 3124 | return .none; |
| 3103 | 3125 | } |
| ... | ... | @@ -3120,13 +3142,14 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3120 | 3142 | } |
| 3121 | 3143 | |
| 3122 | 3144 | fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3145 | const mod = f.object.dg.module; | |
| 3123 | 3146 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3124 | 3147 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3125 | 3148 | |
| 3126 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3127 | const ptr_ty = f.air.typeOf(bin_op.lhs); | |
| 3128 | const elem_ty = ptr_ty.childType(); | |
| 3129 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(); | |
| 3149 | const inst_ty = f.typeOfIndex(inst); | |
| 3150 | const ptr_ty = f.typeOf(bin_op.lhs); | |
| 3151 | const elem_ty = ptr_ty.childType(mod); | |
| 3152 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(mod); | |
| 3130 | 3153 | |
| 3131 | 3154 | const ptr = try f.resolveInst(bin_op.lhs); |
| 3132 | 3155 | const index = try f.resolveInst(bin_op.rhs); |
| ... | ... | @@ -3141,7 +3164,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3141 | 3164 | try f.renderType(writer, inst_ty); |
| 3142 | 3165 | try writer.writeByte(')'); |
| 3143 | 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 | 3168 | // It's a pointer to an array, so we need to de-reference. |
| 3146 | 3169 | try f.writeCValueDeref(writer, ptr); |
| 3147 | 3170 | } else try f.writeCValue(writer, ptr, .Other); |
| ... | ... | @@ -3155,9 +3178,10 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3155 | 3178 | } |
| 3156 | 3179 | |
| 3157 | 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 | 3183 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3160 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3184 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3161 | 3185 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3162 | 3186 | return .none; |
| 3163 | 3187 | } |
| ... | ... | @@ -3180,13 +3204,14 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3180 | 3204 | } |
| 3181 | 3205 | |
| 3182 | 3206 | fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3207 | const mod = f.object.dg.module; | |
| 3183 | 3208 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3184 | 3209 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3185 | 3210 | |
| 3186 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3187 | const slice_ty = f.air.typeOf(bin_op.lhs); | |
| 3188 | const elem_ty = slice_ty.elemType2(); | |
| 3189 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(); | |
| 3211 | const inst_ty = f.typeOfIndex(inst); | |
| 3212 | const slice_ty = f.typeOf(bin_op.lhs); | |
| 3213 | const elem_ty = slice_ty.elemType2(mod); | |
| 3214 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(mod); | |
| 3190 | 3215 | |
| 3191 | 3216 | const slice = try f.resolveInst(bin_op.lhs); |
| 3192 | 3217 | const index = try f.resolveInst(bin_op.rhs); |
| ... | ... | @@ -3209,9 +3234,10 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3209 | 3234 | } |
| 3210 | 3235 | |
| 3211 | 3236 | fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3237 | const mod = f.object.dg.module; | |
| 3212 | 3238 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3213 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3214 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3239 | const inst_ty = f.typeOfIndex(inst); | |
| 3240 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3215 | 3241 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3216 | 3242 | return .none; |
| 3217 | 3243 | } |
| ... | ... | @@ -3234,14 +3260,14 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3234 | 3260 | } |
| 3235 | 3261 | |
| 3236 | 3262 | fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3237 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3238 | const elem_type = inst_ty.elemType(); | |
| 3239 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty }; | |
| 3263 | const mod = f.object.dg.module; | |
| 3264 | const inst_ty = f.typeOfIndex(inst); | |
| 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 | 3268 | const local = try f.allocLocalValue( |
| 3243 | 3269 | elem_type, |
| 3244 | inst_ty.ptrAlignment(target), | |
| 3270 | inst_ty.ptrAlignment(mod), | |
| 3245 | 3271 | ); |
| 3246 | 3272 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); |
| 3247 | 3273 | const gpa = f.object.dg.module.gpa; |
| ... | ... | @@ -3250,14 +3276,14 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3250 | 3276 | } |
| 3251 | 3277 | |
| 3252 | 3278 | fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3253 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3254 | const elem_ty = inst_ty.elemType(); | |
| 3255 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty }; | |
| 3279 | const mod = f.object.dg.module; | |
| 3280 | const inst_ty = f.typeOfIndex(inst); | |
| 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 | 3284 | const local = try f.allocLocalValue( |
| 3259 | 3285 | elem_ty, |
| 3260 | inst_ty.ptrAlignment(target), | |
| 3286 | inst_ty.ptrAlignment(mod), | |
| 3261 | 3287 | ); |
| 3262 | 3288 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); |
| 3263 | 3289 | const gpa = f.object.dg.module.gpa; |
| ... | ... | @@ -3266,7 +3292,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3266 | 3292 | } |
| 3267 | 3293 | |
| 3268 | 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 | 3296 | const inst_cty = try f.typeToIndex(inst_ty, .parameter); |
| 3271 | 3297 | |
| 3272 | 3298 | const i = f.next_arg_index; |
| ... | ... | @@ -3290,14 +3316,15 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3290 | 3316 | } |
| 3291 | 3317 | |
| 3292 | 3318 | fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3319 | const mod = f.object.dg.module; | |
| 3293 | 3320 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3294 | 3321 | |
| 3295 | const ptr_ty = f.air.typeOf(ty_op.operand); | |
| 3296 | const ptr_scalar_ty = ptr_ty.scalarType(); | |
| 3297 | const ptr_info = ptr_scalar_ty.ptrInfo().data; | |
| 3322 | const ptr_ty = f.typeOf(ty_op.operand); | |
| 3323 | const ptr_scalar_ty = ptr_ty.scalarType(mod); | |
| 3324 | const ptr_info = ptr_scalar_ty.ptrInfo(mod); | |
| 3298 | 3325 | const src_ty = ptr_info.pointee_type; |
| 3299 | 3326 | |
| 3300 | if (!src_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3327 | if (!src_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3301 | 3328 | try reap(f, inst, &.{ty_op.operand}); |
| 3302 | 3329 | return .none; |
| 3303 | 3330 | } |
| ... | ... | @@ -3306,9 +3333,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3306 | 3333 | |
| 3307 | 3334 | try reap(f, inst, &.{ty_op.operand}); |
| 3308 | 3335 | |
| 3309 | const target = f.object.dg.module.getTarget(); | |
| 3310 | const is_aligned = ptr_info.@"align" == 0 or ptr_info.@"align" >= src_ty.abiAlignment(target); | |
| 3311 | const is_array = lowersToArray(src_ty, target); | |
| 3336 | const is_aligned = ptr_info.@"align" == 0 or ptr_info.@"align" >= src_ty.abiAlignment(mod); | |
| 3337 | const is_array = lowersToArray(src_ty, mod); | |
| 3312 | 3338 | const need_memcpy = !is_aligned or is_array; |
| 3313 | 3339 | |
| 3314 | 3340 | const writer = f.object.writer(); |
| ... | ... | @@ -3327,29 +3353,13 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3327 | 3353 | try f.renderType(writer, src_ty); |
| 3328 | 3354 | try writer.writeAll("))"); |
| 3329 | 3355 | } else if (ptr_info.host_size > 0 and ptr_info.vector_index == .none) { |
| 3330 | var host_pl = Type.Payload.Bits{ | |
| 3331 | .base = .{ .tag = .int_unsigned }, | |
| 3332 | .data = ptr_info.host_size * 8, | |
| 3333 | }; | |
| 3334 | const host_ty = Type.initPayload(&host_pl.base); | |
| 3356 | const host_bits: u16 = ptr_info.host_size * 8; | |
| 3357 | const host_ty = try mod.intType(.unsigned, host_bits); | |
| 3335 | 3358 | |
| 3336 | var bit_offset_ty_pl = Type.Payload.Bits{ | |
| 3337 | .base = .{ .tag = .int_unsigned }, | |
| 3338 | .data = Type.smallestUnsignedBits(host_pl.data - 1), | |
| 3339 | }; | |
| 3340 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); | |
| 3359 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(host_bits - 1)); | |
| 3360 | const bit_offset_val = try mod.intValue(bit_offset_ty, ptr_info.bit_offset); | |
| 3341 | 3361 | |
| 3342 | var bit_offset_val_pl: Value.Payload.U64 = .{ | |
| 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); | |
| 3362 | const field_ty = try mod.intType(.unsigned, @intCast(u16, src_ty.bitSize(mod))); | |
| 3353 | 3363 | |
| 3354 | 3364 | try f.writeCValue(writer, local, .Other); |
| 3355 | 3365 | try v.elem(f, writer); |
| ... | ... | @@ -3360,9 +3370,9 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3360 | 3370 | try writer.writeAll("(("); |
| 3361 | 3371 | try f.renderType(writer, field_ty); |
| 3362 | 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 | 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 | 3376 | try writer.writeAll("zig_lo_"); |
| 3367 | 3377 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3368 | 3378 | try writer.writeByte('('); |
| ... | ... | @@ -3390,23 +3400,22 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3390 | 3400 | } |
| 3391 | 3401 | |
| 3392 | 3402 | fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 3403 | const mod = f.object.dg.module; | |
| 3393 | 3404 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 3394 | 3405 | const writer = f.object.writer(); |
| 3395 | const target = f.object.dg.module.getTarget(); | |
| 3396 | 3406 | const op_inst = Air.refToIndex(un_op); |
| 3397 | const op_ty = f.air.typeOf(un_op); | |
| 3398 | const ret_ty = if (is_ptr) op_ty.childType() else op_ty; | |
| 3399 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | |
| 3400 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); | |
| 3407 | const op_ty = f.typeOf(un_op); | |
| 3408 | const ret_ty = if (is_ptr) op_ty.childType(mod) else op_ty; | |
| 3409 | const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod); | |
| 3401 | 3410 | |
| 3402 | 3411 | if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) { |
| 3403 | 3412 | try reap(f, inst, &.{un_op}); |
| 3404 | 3413 | _ = try airCall(f, op_inst.?, .always_tail); |
| 3405 | } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3414 | } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3406 | 3415 | const operand = try f.resolveInst(un_op); |
| 3407 | 3416 | try reap(f, inst, &.{un_op}); |
| 3408 | 3417 | var deref = is_ptr; |
| 3409 | const is_array = lowersToArray(ret_ty, target); | |
| 3418 | const is_array = lowersToArray(ret_ty, mod); | |
| 3410 | 3419 | const ret_val = if (is_array) ret_val: { |
| 3411 | 3420 | const array_local = try f.allocLocal(inst, lowered_ret_ty); |
| 3412 | 3421 | try writer.writeAll("memcpy("); |
| ... | ... | @@ -3435,22 +3444,23 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 3435 | 3444 | } else { |
| 3436 | 3445 | try reap(f, inst, &.{un_op}); |
| 3437 | 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 | 3448 | try writer.writeAll("return;\n"); |
| 3440 | 3449 | } |
| 3441 | 3450 | return .none; |
| 3442 | 3451 | } |
| 3443 | 3452 | |
| 3444 | 3453 | fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3454 | const mod = f.object.dg.module; | |
| 3445 | 3455 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3446 | 3456 | |
| 3447 | 3457 | const operand = try f.resolveInst(ty_op.operand); |
| 3448 | 3458 | try reap(f, inst, &.{ty_op.operand}); |
| 3449 | 3459 | |
| 3450 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3451 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 3452 | const operand_ty = f.air.typeOf(ty_op.operand); | |
| 3453 | const scalar_ty = operand_ty.scalarType(); | |
| 3460 | const inst_ty = f.typeOfIndex(inst); | |
| 3461 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 3462 | const operand_ty = f.typeOf(ty_op.operand); | |
| 3463 | const scalar_ty = operand_ty.scalarType(mod); | |
| 3454 | 3464 | |
| 3455 | 3465 | const writer = f.object.writer(); |
| 3456 | 3466 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -3467,20 +3477,20 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3467 | 3477 | } |
| 3468 | 3478 | |
| 3469 | 3479 | fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3480 | const mod = f.object.dg.module; | |
| 3470 | 3481 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3471 | 3482 | |
| 3472 | 3483 | const operand = try f.resolveInst(ty_op.operand); |
| 3473 | 3484 | try reap(f, inst, &.{ty_op.operand}); |
| 3474 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3475 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 3476 | const target = f.object.dg.module.getTarget(); | |
| 3477 | const dest_int_info = inst_scalar_ty.intInfo(target); | |
| 3485 | const inst_ty = f.typeOfIndex(inst); | |
| 3486 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 3487 | const dest_int_info = inst_scalar_ty.intInfo(mod); | |
| 3478 | 3488 | const dest_bits = dest_int_info.bits; |
| 3479 | 3489 | const dest_c_bits = toCIntBits(dest_int_info.bits) orelse |
| 3480 | 3490 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 3481 | const operand_ty = f.air.typeOf(ty_op.operand); | |
| 3482 | const scalar_ty = operand_ty.scalarType(); | |
| 3483 | const scalar_int_info = scalar_ty.intInfo(target); | |
| 3491 | const operand_ty = f.typeOf(ty_op.operand); | |
| 3492 | const scalar_ty = operand_ty.scalarType(mod); | |
| 3493 | const scalar_int_info = scalar_ty.intInfo(mod); | |
| 3484 | 3494 | |
| 3485 | 3495 | const writer = f.object.writer(); |
| 3486 | 3496 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -3508,14 +3518,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3508 | 3518 | try v.elem(f, writer); |
| 3509 | 3519 | } else switch (dest_int_info.signedness) { |
| 3510 | 3520 | .unsigned => { |
| 3511 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); | |
| 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); | |
| 3521 | const mask_val = try inst_scalar_ty.maxIntScalar(mod, scalar_ty); | |
| 3519 | 3522 | try writer.writeAll("zig_and_"); |
| 3520 | 3523 | try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); |
| 3521 | 3524 | try writer.writeByte('('); |
| ... | ... | @@ -3526,11 +3529,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3526 | 3529 | .signed => { |
| 3527 | 3530 | const c_bits = toCIntBits(scalar_int_info.bits) orelse |
| 3528 | 3531 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 3529 | var shift_pl = Value.Payload.U64{ | |
| 3530 | .base = .{ .tag = .int_u64 }, | |
| 3531 | .data = c_bits - dest_bits, | |
| 3532 | }; | |
| 3533 | const shift_val = Value.initPayload(&shift_pl.base); | |
| 3532 | const shift_val = try mod.intValue(Type.u8, c_bits - dest_bits); | |
| 3534 | 3533 | |
| 3535 | 3534 | try writer.writeAll("zig_shr_"); |
| 3536 | 3535 | try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); |
| ... | ... | @@ -3566,7 +3565,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3566 | 3565 | const operand = try f.resolveInst(un_op); |
| 3567 | 3566 | try reap(f, inst, &.{un_op}); |
| 3568 | 3567 | const writer = f.object.writer(); |
| 3569 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3568 | const inst_ty = f.typeOfIndex(inst); | |
| 3570 | 3569 | const local = try f.allocLocal(inst, inst_ty); |
| 3571 | 3570 | const a = try Assignment.start(f, writer, inst_ty); |
| 3572 | 3571 | try f.writeCValue(writer, local, .Other); |
| ... | ... | @@ -3577,17 +3576,18 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3577 | 3576 | } |
| 3578 | 3577 | |
| 3579 | 3578 | fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3579 | const mod = f.object.dg.module; | |
| 3580 | 3580 | // *a = b; |
| 3581 | 3581 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3582 | 3582 | |
| 3583 | const ptr_ty = f.air.typeOf(bin_op.lhs); | |
| 3584 | const ptr_scalar_ty = ptr_ty.scalarType(); | |
| 3585 | const ptr_info = ptr_scalar_ty.ptrInfo().data; | |
| 3583 | const ptr_ty = f.typeOf(bin_op.lhs); | |
| 3584 | const ptr_scalar_ty = ptr_ty.scalarType(mod); | |
| 3585 | const ptr_info = ptr_scalar_ty.ptrInfo(mod); | |
| 3586 | 3586 | |
| 3587 | 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 | 3592 | if (val_is_undef) { |
| 3593 | 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 | 3602 | return .none; |
| 3603 | 3603 | } |
| 3604 | 3604 | |
| 3605 | const target = f.object.dg.module.getTarget(); | |
| 3606 | 3605 | const is_aligned = ptr_info.@"align" == 0 or |
| 3607 | ptr_info.@"align" >= ptr_info.pointee_type.abiAlignment(target); | |
| 3608 | const is_array = lowersToArray(ptr_info.pointee_type, target); | |
| 3606 | ptr_info.@"align" >= ptr_info.pointee_type.abiAlignment(mod); | |
| 3607 | const is_array = lowersToArray(ptr_info.pointee_type, mod); | |
| 3609 | 3608 | const need_memcpy = !is_aligned or is_array; |
| 3610 | 3609 | |
| 3611 | 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 | 3646 | } |
| 3648 | 3647 | } else if (ptr_info.host_size > 0 and ptr_info.vector_index == .none) { |
| 3649 | 3648 | const host_bits = ptr_info.host_size * 8; |
| 3650 | var host_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = host_bits }; | |
| 3651 | const host_ty = Type.initPayload(&host_pl.base); | |
| 3649 | const host_ty = try mod.intType(.unsigned, host_bits); | |
| 3652 | 3650 | |
| 3653 | var bit_offset_ty_pl = Type.Payload.Bits{ | |
| 3654 | .base = .{ .tag = .int_unsigned }, | |
| 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); | |
| 3651 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(host_bits - 1)); | |
| 3652 | const bit_offset_val = try mod.intValue(bit_offset_ty, ptr_info.bit_offset); | |
| 3664 | 3653 | |
| 3665 | const src_bits = src_ty.bitSize(target); | |
| 3654 | const src_bits = src_ty.bitSize(mod); | |
| 3666 | 3655 | |
| 3667 | 3656 | const ExpectedContents = [BigInt.Managed.default_capacity]BigIntLimb; |
| 3668 | 3657 | var stack align(@alignOf(ExpectedContents)) = |
| ... | ... | @@ -3675,11 +3664,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3675 | 3664 | try mask.shiftLeft(&mask, ptr_info.bit_offset); |
| 3676 | 3665 | try mask.bitNotWrap(&mask, .unsigned, host_bits); |
| 3677 | 3666 | |
| 3678 | var mask_pl = Value.Payload.BigInt{ | |
| 3679 | .base = .{ .tag = .int_big_positive }, | |
| 3680 | .data = mask.limbs[0..mask.len()], | |
| 3681 | }; | |
| 3682 | const mask_val = Value.initPayload(&mask_pl.base); | |
| 3667 | const mask_val = try mod.intValue_big(host_ty, mask.toConst()); | |
| 3683 | 3668 | |
| 3684 | 3669 | try f.writeCValueDeref(writer, ptr_val); |
| 3685 | 3670 | try v.elem(f, writer); |
| ... | ... | @@ -3693,9 +3678,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3693 | 3678 | try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)}); |
| 3694 | 3679 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3695 | 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 | 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 | 3684 | try writer.writeAll("zig_make_"); |
| 3700 | 3685 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3701 | 3686 | try writer.writeAll("(0, "); |
| ... | ... | @@ -3705,7 +3690,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3705 | 3690 | try writer.writeByte(')'); |
| 3706 | 3691 | } |
| 3707 | 3692 | |
| 3708 | if (src_ty.isPtrAtRuntime()) { | |
| 3693 | if (src_ty.isPtrAtRuntime(mod)) { | |
| 3709 | 3694 | try writer.writeByte('('); |
| 3710 | 3695 | try f.renderType(writer, Type.usize); |
| 3711 | 3696 | try writer.writeByte(')'); |
| ... | ... | @@ -3728,6 +3713,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3728 | 3713 | } |
| 3729 | 3714 | |
| 3730 | 3715 | fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue { |
| 3716 | const mod = f.object.dg.module; | |
| 3731 | 3717 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3732 | 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 | 3721 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3736 | 3722 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3737 | 3723 | |
| 3738 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3739 | const operand_ty = f.air.typeOf(bin_op.lhs); | |
| 3740 | const scalar_ty = operand_ty.scalarType(); | |
| 3724 | const inst_ty = f.typeOfIndex(inst); | |
| 3725 | const operand_ty = f.typeOf(bin_op.lhs); | |
| 3726 | const scalar_ty = operand_ty.scalarType(mod); | |
| 3741 | 3727 | |
| 3742 | 3728 | const w = f.object.writer(); |
| 3743 | 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 | 3751 | } |
| 3766 | 3752 | |
| 3767 | 3753 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3754 | const mod = f.object.dg.module; | |
| 3768 | 3755 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3769 | const operand_ty = f.air.typeOf(ty_op.operand); | |
| 3770 | const scalar_ty = operand_ty.scalarType(); | |
| 3771 | if (scalar_ty.tag() != .bool) return try airUnBuiltinCall(f, inst, "not", .bits); | |
| 3756 | const operand_ty = f.typeOf(ty_op.operand); | |
| 3757 | const scalar_ty = operand_ty.scalarType(mod); | |
| 3758 | if (scalar_ty.ip_index != .bool_type) return try airUnBuiltinCall(f, inst, "not", .bits); | |
| 3772 | 3759 | |
| 3773 | 3760 | const op = try f.resolveInst(ty_op.operand); |
| 3774 | 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 | 3765 | const writer = f.object.writer(); |
| 3779 | 3766 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -3797,18 +3784,18 @@ fn airBinOp( |
| 3797 | 3784 | operation: []const u8, |
| 3798 | 3785 | info: BuiltinInfo, |
| 3799 | 3786 | ) !CValue { |
| 3787 | const mod = f.object.dg.module; | |
| 3800 | 3788 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3801 | const operand_ty = f.air.typeOf(bin_op.lhs); | |
| 3802 | const scalar_ty = operand_ty.scalarType(); | |
| 3803 | const target = f.object.dg.module.getTarget(); | |
| 3804 | if ((scalar_ty.isInt() and scalar_ty.bitSize(target) > 64) or scalar_ty.isRuntimeFloat()) | |
| 3789 | const operand_ty = f.typeOf(bin_op.lhs); | |
| 3790 | const scalar_ty = operand_ty.scalarType(mod); | |
| 3791 | if ((scalar_ty.isInt(mod) and scalar_ty.bitSize(mod) > 64) or scalar_ty.isRuntimeFloat()) | |
| 3805 | 3792 | return try airBinBuiltinCall(f, inst, operation, info); |
| 3806 | 3793 | |
| 3807 | 3794 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3808 | 3795 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3809 | 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 | 3800 | const writer = f.object.writer(); |
| 3814 | 3801 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -3835,12 +3822,12 @@ fn airCmpOp( |
| 3835 | 3822 | data: anytype, |
| 3836 | 3823 | operator: std.math.CompareOperator, |
| 3837 | 3824 | ) !CValue { |
| 3838 | const lhs_ty = f.air.typeOf(data.lhs); | |
| 3839 | const scalar_ty = lhs_ty.scalarType(); | |
| 3825 | const mod = f.object.dg.module; | |
| 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(); | |
| 3842 | const scalar_bits = scalar_ty.bitSize(target); | |
| 3843 | if (scalar_ty.isInt() and scalar_bits > 64) | |
| 3829 | const scalar_bits = scalar_ty.bitSize(mod); | |
| 3830 | if (scalar_ty.isInt(mod) and scalar_bits > 64) | |
| 3844 | 3831 | return airCmpBuiltinCall( |
| 3845 | 3832 | f, |
| 3846 | 3833 | inst, |
| ... | ... | @@ -3852,13 +3839,13 @@ fn airCmpOp( |
| 3852 | 3839 | if (scalar_ty.isRuntimeFloat()) |
| 3853 | 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 | 3843 | const lhs = try f.resolveInst(data.lhs); |
| 3857 | 3844 | const rhs = try f.resolveInst(data.rhs); |
| 3858 | 3845 | try reap(f, inst, &.{ data.lhs, data.rhs }); |
| 3859 | 3846 | |
| 3860 | const rhs_ty = f.air.typeOf(data.rhs); | |
| 3861 | const need_cast = lhs_ty.isSinglePointer() or rhs_ty.isSinglePointer(); | |
| 3847 | const rhs_ty = f.typeOf(data.rhs); | |
| 3848 | const need_cast = lhs_ty.isSinglePointer(mod) or rhs_ty.isSinglePointer(mod); | |
| 3862 | 3849 | const writer = f.object.writer(); |
| 3863 | 3850 | const local = try f.allocLocal(inst, inst_ty); |
| 3864 | 3851 | const v = try Vectorize.start(f, inst, writer, lhs_ty); |
| ... | ... | @@ -3885,12 +3872,12 @@ fn airEquality( |
| 3885 | 3872 | inst: Air.Inst.Index, |
| 3886 | 3873 | operator: std.math.CompareOperator, |
| 3887 | 3874 | ) !CValue { |
| 3875 | const mod = f.object.dg.module; | |
| 3888 | 3876 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3889 | 3877 | |
| 3890 | const operand_ty = f.air.typeOf(bin_op.lhs); | |
| 3891 | const target = f.object.dg.module.getTarget(); | |
| 3892 | const operand_bits = operand_ty.bitSize(target); | |
| 3893 | if (operand_ty.isInt() and operand_bits > 64) | |
| 3878 | const operand_ty = f.typeOf(bin_op.lhs); | |
| 3879 | const operand_bits = operand_ty.bitSize(mod); | |
| 3880 | if (operand_ty.isInt(mod) and operand_bits > 64) | |
| 3894 | 3881 | return airCmpBuiltinCall( |
| 3895 | 3882 | f, |
| 3896 | 3883 | inst, |
| ... | ... | @@ -3907,12 +3894,12 @@ fn airEquality( |
| 3907 | 3894 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3908 | 3895 | |
| 3909 | 3896 | const writer = f.object.writer(); |
| 3910 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3897 | const inst_ty = f.typeOfIndex(inst); | |
| 3911 | 3898 | const local = try f.allocLocal(inst, inst_ty); |
| 3912 | 3899 | try f.writeCValue(writer, local, .Other); |
| 3913 | 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 | 3903 | // (A && B) || (C && (A == B)) |
| 3917 | 3904 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload |
| 3918 | 3905 | |
| ... | ... | @@ -3951,7 +3938,7 @@ fn airEquality( |
| 3951 | 3938 | fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3952 | 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 | 3942 | const operand = try f.resolveInst(un_op); |
| 3956 | 3943 | try reap(f, inst, &.{un_op}); |
| 3957 | 3944 | |
| ... | ... | @@ -3965,6 +3952,7 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3965 | 3952 | } |
| 3966 | 3953 | |
| 3967 | 3954 | fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 3955 | const mod = f.object.dg.module; | |
| 3968 | 3956 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3969 | 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 | 3960 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3973 | 3961 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3974 | 3962 | |
| 3975 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3976 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 3977 | const elem_ty = inst_scalar_ty.elemType2(); | |
| 3963 | const inst_ty = f.typeOfIndex(inst); | |
| 3964 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 3965 | const elem_ty = inst_scalar_ty.elemType2(mod); | |
| 3978 | 3966 | |
| 3979 | 3967 | const local = try f.allocLocal(inst, inst_ty); |
| 3980 | 3968 | const writer = f.object.writer(); |
| ... | ... | @@ -3983,7 +3971,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 3983 | 3971 | try v.elem(f, writer); |
| 3984 | 3972 | try writer.writeAll(" = "); |
| 3985 | 3973 | |
| 3986 | if (elem_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3974 | if (elem_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3987 | 3975 | // We must convert to and from integer types to prevent UB if the operation |
| 3988 | 3976 | // results in a NULL pointer, or if LHS is NULL. The operation is only UB |
| 3989 | 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 | 4000 | } |
| 4013 | 4001 | |
| 4014 | 4002 | fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue { |
| 4003 | const mod = f.object.dg.module; | |
| 4015 | 4004 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 4016 | 4005 | |
| 4017 | const inst_ty = f.air.typeOfIndex(inst); | |
| 4018 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 4006 | const inst_ty = f.typeOfIndex(inst); | |
| 4007 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 4019 | 4008 | |
| 4020 | const target = f.object.dg.module.getTarget(); | |
| 4021 | if (inst_scalar_ty.isInt() and inst_scalar_ty.bitSize(target) > 64) | |
| 4009 | if (inst_scalar_ty.isInt(mod) and inst_scalar_ty.bitSize(mod) > 64) | |
| 4022 | 4010 | return try airBinBuiltinCall(f, inst, operation[1..], .none); |
| 4023 | 4011 | if (inst_scalar_ty.isRuntimeFloat()) |
| 4024 | 4012 | return try airBinFloatOp(f, inst, operation); |
| ... | ... | @@ -4054,6 +4042,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons |
| 4054 | 4042 | } |
| 4055 | 4043 | |
| 4056 | 4044 | fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4045 | const mod = f.object.dg.module; | |
| 4057 | 4046 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4058 | 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 | 4050 | const len = try f.resolveInst(bin_op.rhs); |
| 4062 | 4051 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 4063 | 4052 | |
| 4064 | const inst_ty = f.air.typeOfIndex(inst); | |
| 4065 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 4066 | const ptr_ty = inst_ty.slicePtrFieldType(&buf); | |
| 4053 | const inst_ty = f.typeOfIndex(inst); | |
| 4054 | const ptr_ty = inst_ty.slicePtrFieldType(mod); | |
| 4067 | 4055 | |
| 4068 | 4056 | const writer = f.object.writer(); |
| 4069 | 4057 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -4092,12 +4080,11 @@ fn airCall( |
| 4092 | 4080 | inst: Air.Inst.Index, |
| 4093 | 4081 | modifier: std.builtin.CallModifier, |
| 4094 | 4082 | ) !CValue { |
| 4083 | const mod = f.object.dg.module; | |
| 4095 | 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 | 4087 | const gpa = f.object.dg.gpa; |
| 4099 | const module = f.object.dg.module; | |
| 4100 | const target = module.getTarget(); | |
| 4101 | 4088 | const writer = f.object.writer(); |
| 4102 | 4089 | |
| 4103 | 4090 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| ... | ... | @@ -4107,7 +4094,7 @@ fn airCall( |
| 4107 | 4094 | const resolved_args = try gpa.alloc(CValue, args.len); |
| 4108 | 4095 | defer gpa.free(resolved_args); |
| 4109 | 4096 | for (resolved_args, args) |*resolved_arg, arg| { |
| 4110 | const arg_ty = f.air.typeOf(arg); | |
| 4097 | const arg_ty = f.typeOf(arg); | |
| 4111 | 4098 | const arg_cty = try f.typeToIndex(arg_ty, .parameter); |
| 4112 | 4099 | if (f.indexToCType(arg_cty).tag() == .void) { |
| 4113 | 4100 | resolved_arg.* = .none; |
| ... | ... | @@ -4115,8 +4102,7 @@ fn airCall( |
| 4115 | 4102 | } |
| 4116 | 4103 | resolved_arg.* = try f.resolveInst(arg); |
| 4117 | 4104 | if (arg_cty != try f.typeToIndex(arg_ty, .complete)) { |
| 4118 | var lowered_arg_buf: LowerFnRetTyBuffer = undefined; | |
| 4119 | const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target); | |
| 4105 | const lowered_arg_ty = try lowerFnRetTy(arg_ty, mod); | |
| 4120 | 4106 | |
| 4121 | 4107 | const array_local = try f.allocLocal(inst, lowered_arg_ty); |
| 4122 | 4108 | try writer.writeAll("memcpy("); |
| ... | ... | @@ -4138,22 +4124,21 @@ fn airCall( |
| 4138 | 4124 | for (args) |arg| try bt.feed(arg); |
| 4139 | 4125 | } |
| 4140 | 4126 | |
| 4141 | const callee_ty = f.air.typeOf(pl_op.operand); | |
| 4142 | const fn_ty = switch (callee_ty.zigTypeTag()) { | |
| 4127 | const callee_ty = f.typeOf(pl_op.operand); | |
| 4128 | const fn_ty = switch (callee_ty.zigTypeTag(mod)) { | |
| 4143 | 4129 | .Fn => callee_ty, |
| 4144 | .Pointer => callee_ty.childType(), | |
| 4130 | .Pointer => callee_ty.childType(mod), | |
| 4145 | 4131 | else => unreachable, |
| 4146 | 4132 | }; |
| 4147 | 4133 | |
| 4148 | const ret_ty = fn_ty.fnReturnType(); | |
| 4149 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | |
| 4150 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); | |
| 4134 | const ret_ty = fn_ty.fnReturnType(mod); | |
| 4135 | const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod); | |
| 4151 | 4136 | |
| 4152 | 4137 | const result_local = result: { |
| 4153 | 4138 | if (modifier == .always_tail) { |
| 4154 | 4139 | try writer.writeAll("zig_always_tail return "); |
| 4155 | 4140 | break :result .none; |
| 4156 | } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 4141 | } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4157 | 4142 | break :result .none; |
| 4158 | 4143 | } else if (f.liveness.isUnused(inst)) { |
| 4159 | 4144 | try writer.writeByte('('); |
| ... | ... | @@ -4171,19 +4156,22 @@ fn airCall( |
| 4171 | 4156 | callee: { |
| 4172 | 4157 | known: { |
| 4173 | 4158 | const fn_decl = fn_decl: { |
| 4174 | const callee_val = f.air.value(pl_op.operand) orelse break :known; | |
| 4175 | break :fn_decl switch (callee_val.tag()) { | |
| 4176 | .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl, | |
| 4177 | .function => callee_val.castTag(.function).?.data.owner_decl, | |
| 4178 | .decl_ref => callee_val.castTag(.decl_ref).?.data, | |
| 4159 | const callee_val = (try f.air.value(pl_op.operand, mod)) orelse break :known; | |
| 4160 | break :fn_decl switch (mod.intern_pool.indexToKey(callee_val.ip_index)) { | |
| 4161 | .extern_func => |extern_func| extern_func.decl, | |
| 4162 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 4163 | .ptr => |ptr| switch (ptr.addr) { | |
| 4164 | .decl => |decl| decl, | |
| 4165 | else => break :known, | |
| 4166 | }, | |
| 4179 | 4167 | else => break :known, |
| 4180 | 4168 | }; |
| 4181 | 4169 | }; |
| 4182 | 4170 | switch (modifier) { |
| 4183 | 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( | |
| 4185 | @unionInit(LazyFnKey, @tagName(mod), fn_decl), | |
| 4186 | @unionInit(LazyFnValue.Data, @tagName(mod), {}), | |
| 4172 | inline .never_tail, .never_inline => |m| try writer.writeAll(try f.getLazyFnName( | |
| 4173 | @unionInit(LazyFnKey, @tagName(m), fn_decl), | |
| 4174 | @unionInit(LazyFnValue.Data, @tagName(m), {}), | |
| 4187 | 4175 | )), |
| 4188 | 4176 | else => unreachable, |
| 4189 | 4177 | } |
| ... | ... | @@ -4211,7 +4199,7 @@ fn airCall( |
| 4211 | 4199 | try writer.writeAll(");\n"); |
| 4212 | 4200 | |
| 4213 | 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 | 4203 | break :result result_local; |
| 4216 | 4204 | |
| 4217 | 4205 | const array_local = try f.allocLocal(inst, ret_ty); |
| ... | ... | @@ -4245,18 +4233,21 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4245 | 4233 | } |
| 4246 | 4234 | |
| 4247 | 4235 | fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4248 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | |
| 4249 | const writer = f.object.writer(); | |
| 4250 | const function = f.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 4236 | const ty_fn = f.air.instructions.items(.data)[inst].ty_fn; | |
| 4251 | 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 | 4243 | return .none; |
| 4254 | 4244 | } |
| 4255 | 4245 | |
| 4256 | 4246 | fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4247 | const mod = f.object.dg.module; | |
| 4257 | 4248 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4258 | 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 | 4251 | if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand); |
| 4261 | 4252 | |
| 4262 | 4253 | try reap(f, inst, &.{pl_op.operand}); |
| ... | ... | @@ -4266,6 +4257,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4266 | 4257 | } |
| 4267 | 4258 | |
| 4268 | 4259 | fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4260 | const mod = f.object.dg.module; | |
| 4269 | 4261 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4270 | 4262 | const extra = f.air.extraData(Air.Block, ty_pl.payload); |
| 4271 | 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 | 4267 | f.next_block_index += 1; |
| 4276 | 4268 | const writer = f.object.writer(); |
| 4277 | 4269 | |
| 4278 | const inst_ty = f.air.typeOfIndex(inst); | |
| 4279 | const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst)) | |
| 4270 | const inst_ty = f.typeOfIndex(inst); | |
| 4271 | const result = if (inst_ty.ip_index != .void_type and !f.liveness.isUnused(inst)) | |
| 4280 | 4272 | try f.allocLocal(inst, inst_ty) |
| 4281 | 4273 | else |
| 4282 | 4274 | .none; |
| ... | ... | @@ -4298,7 +4290,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4298 | 4290 | try f.object.indent_writer.insertNewline(); |
| 4299 | 4291 | |
| 4300 | 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 | 4294 | // label must be followed by an expression, include an empty one. |
| 4303 | 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 | 4302 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4311 | 4303 | const extra = f.air.extraData(Air.Try, pl_op.payload); |
| 4312 | 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 | 4306 | return lowerTry(f, inst, pl_op.operand, body, err_union_ty, false); |
| 4315 | 4307 | } |
| 4316 | 4308 | |
| 4317 | 4309 | fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4310 | const mod = f.object.dg.module; | |
| 4318 | 4311 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4319 | 4312 | const extra = f.air.extraData(Air.TryPtr, ty_pl.payload); |
| 4320 | 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 | 4315 | return lowerTry(f, inst, extra.data.ptr, body, err_union_ty, true); |
| 4323 | 4316 | } |
| 4324 | 4317 | |
| ... | ... | @@ -4330,14 +4323,15 @@ fn lowerTry( |
| 4330 | 4323 | err_union_ty: Type, |
| 4331 | 4324 | is_ptr: bool, |
| 4332 | 4325 | ) !CValue { |
| 4326 | const mod = f.object.dg.module; | |
| 4333 | 4327 | const err_union = try f.resolveInst(operand); |
| 4334 | const inst_ty = f.air.typeOfIndex(inst); | |
| 4328 | const inst_ty = f.typeOfIndex(inst); | |
| 4335 | 4329 | const liveness_condbr = f.liveness.getCondBr(inst); |
| 4336 | 4330 | const writer = f.object.writer(); |
| 4337 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 4338 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(); | |
| 4331 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 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 | 4335 | try writer.writeAll("if ("); |
| 4342 | 4336 | if (!payload_has_bits) { |
| 4343 | 4337 | if (is_ptr) |
| ... | ... | @@ -4399,7 +4393,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4399 | 4393 | |
| 4400 | 4394 | // If result is .none then the value of the block is unused. |
| 4401 | 4395 | if (result != .none) { |
| 4402 | const operand_ty = f.air.typeOf(branch.operand); | |
| 4396 | const operand_ty = f.typeOf(branch.operand); | |
| 4403 | 4397 | const operand = try f.resolveInst(branch.operand); |
| 4404 | 4398 | try reap(f, inst, &.{branch.operand}); |
| 4405 | 4399 | |
| ... | ... | @@ -4416,10 +4410,10 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4416 | 4410 | |
| 4417 | 4411 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4418 | 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 | 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 | 4418 | const bitcasted = try bitcast(f, dest_ty, operand, operand_ty); |
| 4425 | 4419 | try reap(f, inst, &.{ty_op.operand}); |
| ... | ... | @@ -4431,6 +4425,8 @@ const LocalResult = struct { |
| 4431 | 4425 | need_free: bool, |
| 4432 | 4426 | |
| 4433 | 4427 | fn move(lr: LocalResult, f: *Function, inst: Air.Inst.Index, dest_ty: Type) !CValue { |
| 4428 | const mod = f.object.dg.module; | |
| 4429 | ||
| 4434 | 4430 | if (lr.need_free) { |
| 4435 | 4431 | // Move the freshly allocated local to be owned by this instruction, |
| 4436 | 4432 | // by returning it here instead of freeing it. |
| ... | ... | @@ -4441,7 +4437,7 @@ const LocalResult = struct { |
| 4441 | 4437 | try lr.free(f); |
| 4442 | 4438 | const writer = f.object.writer(); |
| 4443 | 4439 | try f.writeCValue(writer, local, .Other); |
| 4444 | if (dest_ty.isAbiInt()) { | |
| 4440 | if (dest_ty.isAbiInt(mod)) { | |
| 4445 | 4441 | try writer.writeAll(" = "); |
| 4446 | 4442 | } else { |
| 4447 | 4443 | try writer.writeAll(" = ("); |
| ... | ... | @@ -4461,12 +4457,13 @@ const LocalResult = struct { |
| 4461 | 4457 | }; |
| 4462 | 4458 | |
| 4463 | 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 | 4462 | const writer = f.object.writer(); |
| 4466 | 4463 | |
| 4467 | if (operand_ty.isAbiInt() and dest_ty.isAbiInt()) { | |
| 4468 | const src_info = dest_ty.intInfo(target); | |
| 4469 | const dest_info = operand_ty.intInfo(target); | |
| 4464 | if (operand_ty.isAbiInt(mod) and dest_ty.isAbiInt(mod)) { | |
| 4465 | const src_info = dest_ty.intInfo(mod); | |
| 4466 | const dest_info = operand_ty.intInfo(mod); | |
| 4470 | 4467 | if (src_info.signedness == dest_info.signedness and |
| 4471 | 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 | 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 | 4478 | const local = try f.allocLocal(0, dest_ty); |
| 4482 | 4479 | try f.writeCValue(writer, local, .Other); |
| 4483 | 4480 | try writer.writeAll(" = ("); |
| ... | ... | @@ -4494,7 +4491,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4494 | 4491 | const operand_lval = if (operand == .constant) blk: { |
| 4495 | 4492 | const operand_local = try f.allocLocal(0, operand_ty); |
| 4496 | 4493 | try f.writeCValue(writer, operand_local, .Other); |
| 4497 | if (operand_ty.isAbiInt()) { | |
| 4494 | if (operand_ty.isAbiInt(mod)) { | |
| 4498 | 4495 | try writer.writeAll(" = "); |
| 4499 | 4496 | } else { |
| 4500 | 4497 | try writer.writeAll(" = ("); |
| ... | ... | @@ -4516,13 +4513,10 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4516 | 4513 | try writer.writeAll("));\n"); |
| 4517 | 4514 | |
| 4518 | 4515 | // Ensure padding bits have the expected value. |
| 4519 | if (dest_ty.isAbiInt()) { | |
| 4516 | if (dest_ty.isAbiInt(mod)) { | |
| 4520 | 4517 | const dest_cty = try f.typeToCType(dest_ty, .complete); |
| 4521 | const dest_info = dest_ty.intInfo(target); | |
| 4522 | var info_ty_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dest_info.signedness) { | |
| 4523 | .unsigned => .int_unsigned, | |
| 4524 | .signed => .int_signed, | |
| 4525 | } }, .data = dest_info.bits }; | |
| 4518 | const dest_info = dest_ty.intInfo(mod); | |
| 4519 | var bits: u16 = dest_info.bits; | |
| 4526 | 4520 | var wrap_cty: ?CType = null; |
| 4527 | 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 | 4529 | const elem_cty = f.indexToCType(pl.data.elem_type); |
| 4536 | 4530 | wrap_cty = elem_cty.toSignedness(dest_info.signedness); |
| 4537 | 4531 | need_bitcasts = wrap_cty.?.tag() == .zig_i128; |
| 4538 | info_ty_pl.data -= 1; | |
| 4539 | info_ty_pl.data %= @intCast(u16, f.byteSize(elem_cty) * 8); | |
| 4540 | info_ty_pl.data += 1; | |
| 4532 | bits -= 1; | |
| 4533 | bits %= @intCast(u16, f.byteSize(elem_cty) * 8); | |
| 4534 | bits += 1; | |
| 4541 | 4535 | } |
| 4542 | 4536 | try writer.writeAll(" = "); |
| 4543 | 4537 | if (need_bitcasts) { |
| ... | ... | @@ -4546,7 +4540,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4546 | 4540 | try writer.writeByte('('); |
| 4547 | 4541 | } |
| 4548 | 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 | 4544 | if (wrap_cty) |cty| |
| 4551 | 4545 | try f.object.dg.renderCTypeForBuiltinFnName(writer, cty) |
| 4552 | 4546 | else |
| ... | ... | @@ -4622,8 +4616,9 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4622 | 4616 | } |
| 4623 | 4617 | |
| 4624 | 4618 | fn airUnreach(f: *Function) !CValue { |
| 4619 | const mod = f.object.dg.module; | |
| 4625 | 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 | 4623 | try f.object.writer().writeAll("zig_unreachable();\n"); |
| 4629 | 4624 | return .none; |
| ... | ... | @@ -4657,6 +4652,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4657 | 4652 | try writer.writeAll(") "); |
| 4658 | 4653 | |
| 4659 | 4654 | try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false); |
| 4655 | try writer.writeByte('\n'); | |
| 4660 | 4656 | |
| 4661 | 4657 | // We don't need to use `genBodyResolveState` for the else block, because this instruction is |
| 4662 | 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 | 4671 | } |
| 4676 | 4672 | |
| 4677 | 4673 | fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4674 | const mod = f.object.dg.module; | |
| 4678 | 4675 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4679 | 4676 | const condition = try f.resolveInst(pl_op.operand); |
| 4680 | 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 | 4679 | const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload); |
| 4683 | 4680 | const writer = f.object.writer(); |
| 4684 | 4681 | |
| 4685 | 4682 | try writer.writeAll("switch ("); |
| 4686 | if (condition_ty.zigTypeTag() == .Bool) { | |
| 4683 | if (condition_ty.zigTypeTag(mod) == .Bool) { | |
| 4687 | 4684 | try writer.writeByte('('); |
| 4688 | 4685 | try f.renderType(writer, Type.u1); |
| 4689 | 4686 | try writer.writeByte(')'); |
| 4690 | } else if (condition_ty.isPtrAtRuntime()) { | |
| 4687 | } else if (condition_ty.isPtrAtRuntime(mod)) { | |
| 4691 | 4688 | try writer.writeByte('('); |
| 4692 | 4689 | try f.renderType(writer, Type.usize); |
| 4693 | 4690 | try writer.writeByte(')'); |
| ... | ... | @@ -4714,12 +4711,12 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4714 | 4711 | for (items) |item| { |
| 4715 | 4712 | try f.object.indent_writer.insertNewline(); |
| 4716 | 4713 | try writer.writeAll("case "); |
| 4717 | if (condition_ty.isPtrAtRuntime()) { | |
| 4714 | if (condition_ty.isPtrAtRuntime(mod)) { | |
| 4718 | 4715 | try writer.writeByte('('); |
| 4719 | 4716 | try f.renderType(writer, Type.usize); |
| 4720 | 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 | 4720 | try writer.writeByte(':'); |
| 4724 | 4721 | } |
| 4725 | 4722 | try writer.writeByte(' '); |
| ... | ... | @@ -4764,6 +4761,7 @@ fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool { |
| 4764 | 4761 | } |
| 4765 | 4762 | |
| 4766 | 4763 | fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4764 | const mod = f.object.dg.module; | |
| 4767 | 4765 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4768 | 4766 | const extra = f.air.extraData(Air.Asm, ty_pl.payload); |
| 4769 | 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 | 4775 | |
| 4778 | 4776 | const result = result: { |
| 4779 | 4777 | const writer = f.object.writer(); |
| 4780 | const inst_ty = f.air.typeOfIndex(inst); | |
| 4781 | const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: { | |
| 4778 | const inst_ty = f.typeOfIndex(inst); | |
| 4779 | const local = if (inst_ty.hasRuntimeBitsIgnoreComptime(mod)) local: { | |
| 4782 | 4780 | const local = try f.allocLocal(inst, inst_ty); |
| 4783 | 4781 | if (f.wantSafety()) { |
| 4784 | 4782 | try f.writeCValue(writer, local, .Other); |
| ... | ... | @@ -4807,7 +4805,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4807 | 4805 | |
| 4808 | 4806 | const is_reg = constraint[1] == '{'; |
| 4809 | 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 | 4809 | try writer.writeAll("register "); |
| 4812 | 4810 | const alignment = 0; |
| 4813 | 4811 | const local_value = try f.allocLocalValue(output_ty, alignment); |
| ... | ... | @@ -4840,7 +4838,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4840 | 4838 | const is_reg = constraint[0] == '{'; |
| 4841 | 4839 | const input_val = try f.resolveInst(input); |
| 4842 | 4840 | if (asmInputNeedsLocal(constraint, input_val)) { |
| 4843 | const input_ty = f.air.typeOf(input); | |
| 4841 | const input_ty = f.typeOf(input); | |
| 4844 | 4842 | if (is_reg) try writer.writeAll("register "); |
| 4845 | 4843 | const alignment = 0; |
| 4846 | 4844 | const local_value = try f.allocLocalValue(input_ty, alignment); |
| ... | ... | @@ -5025,6 +5023,7 @@ fn airIsNull( |
| 5025 | 5023 | operator: []const u8, |
| 5026 | 5024 | is_ptr: bool, |
| 5027 | 5025 | ) !CValue { |
| 5026 | const mod = f.object.dg.module; | |
| 5028 | 5027 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 5029 | 5028 | |
| 5030 | 5029 | const writer = f.object.writer(); |
| ... | ... | @@ -5040,23 +5039,22 @@ fn airIsNull( |
| 5040 | 5039 | try f.writeCValue(writer, operand, .Other); |
| 5041 | 5040 | } |
| 5042 | 5041 | |
| 5043 | const operand_ty = f.air.typeOf(un_op); | |
| 5044 | const optional_ty = if (is_ptr) operand_ty.childType() else operand_ty; | |
| 5045 | var payload_buf: Type.Payload.ElemType = undefined; | |
| 5046 | const payload_ty = optional_ty.optionalChild(&payload_buf); | |
| 5047 | var slice_ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 5042 | const operand_ty = f.typeOf(un_op); | |
| 5043 | const optional_ty = if (is_ptr) operand_ty.childType(mod) else operand_ty; | |
| 5044 | const payload_ty = optional_ty.optionalChild(mod); | |
| 5048 | 5045 | |
| 5049 | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime()) | |
| 5046 | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 5050 | 5047 | TypedValue{ .ty = Type.bool, .val = Value.true } |
| 5051 | else if (optional_ty.isPtrLikeOptional()) | |
| 5048 | else if (optional_ty.isPtrLikeOptional(mod)) | |
| 5052 | 5049 | // operand is a regular pointer, test `operand !=/== NULL` |
| 5053 | TypedValue{ .ty = optional_ty, .val = Value.null } | |
| 5054 | else if (payload_ty.zigTypeTag() == .ErrorSet) | |
| 5055 | TypedValue{ .ty = payload_ty, .val = Value.zero } | |
| 5056 | else if (payload_ty.isSlice() and optional_ty.optionalReprIsPayload()) rhs: { | |
| 5050 | TypedValue{ .ty = optional_ty, .val = try mod.getCoerced(Value.null, optional_ty) } | |
| 5051 | else if (payload_ty.zigTypeTag(mod) == .ErrorSet) | |
| 5052 | TypedValue{ .ty = Type.err_int, .val = try mod.intValue(Type.err_int, 0) } | |
| 5053 | else if (payload_ty.isSlice(mod) and optional_ty.optionalReprIsPayload(mod)) rhs: { | |
| 5057 | 5054 | try writer.writeAll(".ptr"); |
| 5058 | const slice_ptr_ty = payload_ty.slicePtrFieldType(&slice_ptr_buf); | |
| 5059 | break :rhs TypedValue{ .ty = slice_ptr_ty, .val = Value.null }; | |
| 5055 | const slice_ptr_ty = payload_ty.slicePtrFieldType(mod); | |
| 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 | 5058 | } else rhs: { |
| 5061 | 5059 | try writer.writeAll(".is_null"); |
| 5062 | 5060 | break :rhs TypedValue{ .ty = Type.bool, .val = Value.true }; |
| ... | ... | @@ -5070,24 +5068,24 @@ fn airIsNull( |
| 5070 | 5068 | } |
| 5071 | 5069 | |
| 5072 | 5070 | fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5071 | const mod = f.object.dg.module; | |
| 5073 | 5072 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5074 | 5073 | |
| 5075 | 5074 | const operand = try f.resolveInst(ty_op.operand); |
| 5076 | 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; | |
| 5080 | const payload_ty = opt_ty.optionalChild(&buf); | |
| 5078 | const payload_ty = opt_ty.optionalChild(mod); | |
| 5081 | 5079 | |
| 5082 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5080 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 5083 | 5081 | return .none; |
| 5084 | 5082 | } |
| 5085 | 5083 | |
| 5086 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5084 | const inst_ty = f.typeOfIndex(inst); | |
| 5087 | 5085 | const writer = f.object.writer(); |
| 5088 | 5086 | const local = try f.allocLocal(inst, inst_ty); |
| 5089 | 5087 | |
| 5090 | if (opt_ty.optionalReprIsPayload()) { | |
| 5088 | if (opt_ty.optionalReprIsPayload(mod)) { | |
| 5091 | 5089 | try f.writeCValue(writer, local, .Other); |
| 5092 | 5090 | try writer.writeAll(" = "); |
| 5093 | 5091 | try f.writeCValue(writer, operand, .Other); |
| ... | ... | @@ -5104,23 +5102,24 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5104 | 5102 | } |
| 5105 | 5103 | |
| 5106 | 5104 | fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5105 | const mod = f.object.dg.module; | |
| 5107 | 5106 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5108 | 5107 | |
| 5109 | 5108 | const writer = f.object.writer(); |
| 5110 | 5109 | const operand = try f.resolveInst(ty_op.operand); |
| 5111 | 5110 | try reap(f, inst, &.{ty_op.operand}); |
| 5112 | const ptr_ty = f.air.typeOf(ty_op.operand); | |
| 5113 | const opt_ty = ptr_ty.childType(); | |
| 5114 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5111 | const ptr_ty = f.typeOf(ty_op.operand); | |
| 5112 | const opt_ty = ptr_ty.childType(mod); | |
| 5113 | const inst_ty = f.typeOfIndex(inst); | |
| 5115 | 5114 | |
| 5116 | if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) { | |
| 5115 | if (!inst_ty.childType(mod).hasRuntimeBitsIgnoreComptime(mod)) { | |
| 5117 | 5116 | return .{ .undef = inst_ty }; |
| 5118 | 5117 | } |
| 5119 | 5118 | |
| 5120 | 5119 | const local = try f.allocLocal(inst, inst_ty); |
| 5121 | 5120 | try f.writeCValue(writer, local, .Other); |
| 5122 | 5121 | |
| 5123 | if (opt_ty.optionalReprIsPayload()) { | |
| 5122 | if (opt_ty.optionalReprIsPayload(mod)) { | |
| 5124 | 5123 | // the operand is just a regular pointer, no need to do anything special. |
| 5125 | 5124 | // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C |
| 5126 | 5125 | try writer.writeAll(" = "); |
| ... | ... | @@ -5134,17 +5133,18 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5134 | 5133 | } |
| 5135 | 5134 | |
| 5136 | 5135 | fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5136 | const mod = f.object.dg.module; | |
| 5137 | 5137 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5138 | 5138 | const writer = f.object.writer(); |
| 5139 | 5139 | const operand = try f.resolveInst(ty_op.operand); |
| 5140 | 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 | 5148 | if (f.liveness.isUnused(inst)) { |
| 5149 | 5149 | return .none; |
| 5150 | 5150 | } |
| ... | ... | @@ -5179,48 +5179,49 @@ fn fieldLocation( |
| 5179 | 5179 | container_ty: Type, |
| 5180 | 5180 | field_ptr_ty: Type, |
| 5181 | 5181 | field_index: u32, |
| 5182 | target: std.Target, | |
| 5182 | mod: *Module, | |
| 5183 | 5183 | ) union(enum) { |
| 5184 | 5184 | begin: void, |
| 5185 | 5185 | field: CValue, |
| 5186 | 5186 | byte_offset: u32, |
| 5187 | 5187 | end: void, |
| 5188 | 5188 | } { |
| 5189 | return switch (container_ty.zigTypeTag()) { | |
| 5190 | .Struct => switch (container_ty.containerLayout()) { | |
| 5191 | .Auto, .Extern => for (field_index..container_ty.structFieldCount()) |next_field_index| { | |
| 5192 | if (container_ty.structFieldIsComptime(next_field_index)) continue; | |
| 5193 | const field_ty = container_ty.structFieldType(next_field_index); | |
| 5194 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 5195 | ||
| 5196 | break .{ .field = if (container_ty.isSimpleTuple()) | |
| 5189 | const ip = &mod.intern_pool; | |
| 5190 | return switch (container_ty.zigTypeTag(mod)) { | |
| 5191 | .Struct => switch (container_ty.containerLayout(mod)) { | |
| 5192 | .Auto, .Extern => for (field_index..container_ty.structFieldCount(mod)) |next_field_index| { | |
| 5193 | if (container_ty.structFieldIsComptime(next_field_index, mod)) continue; | |
| 5194 | const field_ty = container_ty.structFieldType(next_field_index, mod); | |
| 5195 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 5196 | ||
| 5197 | break .{ .field = if (container_ty.isSimpleTuple(mod)) | |
| 5197 | 5198 | .{ .field = next_field_index } |
| 5198 | 5199 | else |
| 5199 | .{ .identifier = container_ty.structFieldName(next_field_index) } }; | |
| 5200 | } else if (container_ty.hasRuntimeBitsIgnoreComptime()) .end else .begin, | |
| 5201 | .Packed => if (field_ptr_ty.ptrInfo().data.host_size == 0) | |
| 5202 | .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, target) } | |
| 5200 | .{ .identifier = ip.stringToSlice(container_ty.structFieldName(next_field_index, mod)) } }; | |
| 5201 | } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin, | |
| 5202 | .Packed => if (field_ptr_ty.ptrInfo(mod).host_size == 0) | |
| 5203 | .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, mod) } | |
| 5203 | 5204 | else |
| 5204 | 5205 | .begin, |
| 5205 | 5206 | }, |
| 5206 | .Union => switch (container_ty.containerLayout()) { | |
| 5207 | .Union => switch (container_ty.containerLayout(mod)) { | |
| 5207 | 5208 | .Auto, .Extern => { |
| 5208 | const field_ty = container_ty.structFieldType(field_index); | |
| 5209 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) | |
| 5210 | return if (container_ty.unionTagTypeSafety() != null and | |
| 5211 | !container_ty.unionHasAllZeroBitFieldTypes()) | |
| 5209 | const field_ty = container_ty.structFieldType(field_index, mod); | |
| 5210 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 5211 | return if (container_ty.unionTagTypeSafety(mod) != null and | |
| 5212 | !container_ty.unionHasAllZeroBitFieldTypes(mod)) | |
| 5212 | 5213 | .{ .field = .{ .identifier = "payload" } } |
| 5213 | 5214 | else |
| 5214 | 5215 | .begin; |
| 5215 | const field_name = container_ty.unionFields().keys()[field_index]; | |
| 5216 | return .{ .field = if (container_ty.unionTagTypeSafety()) |_| | |
| 5217 | .{ .payload_identifier = field_name } | |
| 5216 | const field_name = container_ty.unionFields(mod).keys()[field_index]; | |
| 5217 | return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_| | |
| 5218 | .{ .payload_identifier = ip.stringToSlice(field_name) } | |
| 5218 | 5219 | else |
| 5219 | .{ .identifier = field_name } }; | |
| 5220 | .{ .identifier = ip.stringToSlice(field_name) } }; | |
| 5220 | 5221 | }, |
| 5221 | 5222 | .Packed => .begin, |
| 5222 | 5223 | }, |
| 5223 | .Pointer => switch (container_ty.ptrSize()) { | |
| 5224 | .Pointer => switch (container_ty.ptrSize(mod)) { | |
| 5224 | 5225 | .Slice => switch (field_index) { |
| 5225 | 5226 | 0 => .{ .field = .{ .identifier = "ptr" } }, |
| 5226 | 5227 | 1 => .{ .field = .{ .identifier = "len" } }, |
| ... | ... | @@ -5238,7 +5239,7 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5238 | 5239 | |
| 5239 | 5240 | const container_ptr_val = try f.resolveInst(extra.struct_operand); |
| 5240 | 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 | 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 | 5248 | |
| 5248 | 5249 | const container_ptr_val = try f.resolveInst(ty_op.operand); |
| 5249 | 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 | 5252 | return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, index); |
| 5252 | 5253 | } |
| 5253 | 5254 | |
| 5254 | 5255 | fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5256 | const mod = f.object.dg.module; | |
| 5255 | 5257 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 5256 | 5258 | const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 5257 | 5259 | |
| 5258 | const target = f.object.dg.module.getTarget(); | |
| 5259 | const container_ptr_ty = f.air.typeOfIndex(inst); | |
| 5260 | const container_ty = container_ptr_ty.childType(); | |
| 5260 | const container_ptr_ty = f.typeOfIndex(inst); | |
| 5261 | const container_ty = container_ptr_ty.childType(mod); | |
| 5261 | 5262 | |
| 5262 | const field_ptr_ty = f.air.typeOf(extra.field_ptr); | |
| 5263 | const field_ptr_ty = f.typeOf(extra.field_ptr); | |
| 5263 | 5264 | const field_ptr_val = try f.resolveInst(extra.field_ptr); |
| 5264 | 5265 | try reap(f, inst, &.{extra.field_ptr}); |
| 5265 | 5266 | |
| ... | ... | @@ -5270,12 +5271,10 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5270 | 5271 | try f.renderType(writer, container_ptr_ty); |
| 5271 | 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 | 5275 | .begin => try f.writeCValue(writer, field_ptr_val, .Initializer), |
| 5275 | 5276 | .field => |field| { |
| 5276 | var u8_ptr_pl = field_ptr_ty.ptrInfo(); | |
| 5277 | u8_ptr_pl.data.pointee_type = Type.u8; | |
| 5278 | const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); | |
| 5277 | const u8_ptr_ty = try mod.adjustPtrTypeChild(field_ptr_ty, Type.u8); | |
| 5279 | 5278 | |
| 5280 | 5279 | try writer.writeAll("(("); |
| 5281 | 5280 | try f.renderType(writer, u8_ptr_ty); |
| ... | ... | @@ -5288,15 +5287,9 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5288 | 5287 | try writer.writeAll("))"); |
| 5289 | 5288 | }, |
| 5290 | 5289 | .byte_offset => |byte_offset| { |
| 5291 | var u8_ptr_pl = field_ptr_ty.ptrInfo(); | |
| 5292 | u8_ptr_pl.data.pointee_type = Type.u8; | |
| 5293 | const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); | |
| 5290 | const u8_ptr_ty = try mod.adjustPtrTypeChild(field_ptr_ty, Type.u8); | |
| 5294 | 5291 | |
| 5295 | var byte_offset_pl = Value.Payload.U64{ | |
| 5296 | .base = .{ .tag = .int_u64 }, | |
| 5297 | .data = byte_offset, | |
| 5298 | }; | |
| 5299 | const byte_offset_val = Value.initPayload(&byte_offset_pl.base); | |
| 5292 | const byte_offset_val = try mod.intValue(Type.usize, byte_offset); | |
| 5300 | 5293 | |
| 5301 | 5294 | try writer.writeAll("(("); |
| 5302 | 5295 | try f.renderType(writer, u8_ptr_ty); |
| ... | ... | @@ -5306,7 +5299,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5306 | 5299 | }, |
| 5307 | 5300 | .end => { |
| 5308 | 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 | 5314 | container_ptr_val: CValue, |
| 5322 | 5315 | field_index: u32, |
| 5323 | 5316 | ) !CValue { |
| 5324 | const target = f.object.dg.module.getTarget(); | |
| 5325 | const container_ty = container_ptr_ty.elemType(); | |
| 5326 | const field_ptr_ty = f.air.typeOfIndex(inst); | |
| 5317 | const mod = f.object.dg.module; | |
| 5318 | const container_ty = container_ptr_ty.childType(mod); | |
| 5319 | const field_ptr_ty = f.typeOfIndex(inst); | |
| 5327 | 5320 | |
| 5328 | 5321 | // Ensure complete type definition is visible before accessing fields. |
| 5329 | 5322 | _ = try f.typeToIndex(container_ty, .complete); |
| ... | ... | @@ -5335,22 +5328,16 @@ fn fieldPtr( |
| 5335 | 5328 | try f.renderType(writer, field_ptr_ty); |
| 5336 | 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 | 5332 | .begin => try f.writeCValue(writer, container_ptr_val, .Initializer), |
| 5340 | 5333 | .field => |field| { |
| 5341 | 5334 | try writer.writeByte('&'); |
| 5342 | 5335 | try f.writeCValueDerefMember(writer, container_ptr_val, field); |
| 5343 | 5336 | }, |
| 5344 | 5337 | .byte_offset => |byte_offset| { |
| 5345 | var u8_ptr_pl = field_ptr_ty.ptrInfo(); | |
| 5346 | u8_ptr_pl.data.pointee_type = Type.u8; | |
| 5347 | const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); | |
| 5338 | const u8_ptr_ty = try mod.adjustPtrTypeChild(field_ptr_ty, Type.u8); | |
| 5348 | 5339 | |
| 5349 | var byte_offset_pl = Value.Payload.U64{ | |
| 5350 | .base = .{ .tag = .int_u64 }, | |
| 5351 | .data = byte_offset, | |
| 5352 | }; | |
| 5353 | const byte_offset_val = Value.initPayload(&byte_offset_pl.base); | |
| 5340 | const byte_offset_val = try mod.intValue(Type.usize, byte_offset); | |
| 5354 | 5341 | |
| 5355 | 5342 | try writer.writeAll("(("); |
| 5356 | 5343 | try f.renderType(writer, u8_ptr_ty); |
| ... | ... | @@ -5361,7 +5348,7 @@ fn fieldPtr( |
| 5361 | 5348 | .end => { |
| 5362 | 5349 | try writer.writeByte('('); |
| 5363 | 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 | 5357 | } |
| 5371 | 5358 | |
| 5372 | 5359 | fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5360 | const mod = f.object.dg.module; | |
| 5361 | const ip = &mod.intern_pool; | |
| 5373 | 5362 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 5374 | 5363 | const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; |
| 5375 | 5364 | |
| 5376 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5377 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5365 | const inst_ty = f.typeOfIndex(inst); | |
| 5366 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 5378 | 5367 | try reap(f, inst, &.{extra.struct_operand}); |
| 5379 | 5368 | return .none; |
| 5380 | 5369 | } |
| 5381 | 5370 | |
| 5382 | const target = f.object.dg.module.getTarget(); | |
| 5383 | 5371 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 5384 | 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 | 5374 | const writer = f.object.writer(); |
| 5387 | 5375 | |
| 5388 | 5376 | // Ensure complete type definition is visible before accessing fields. |
| 5389 | 5377 | _ = try f.typeToIndex(struct_ty, .complete); |
| 5390 | 5378 | |
| 5391 | const field_name: CValue = switch (struct_ty.tag()) { | |
| 5392 | .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) { | |
| 5393 | .Auto, .Extern => if (struct_ty.isSimpleTuple()) | |
| 5379 | const field_name: CValue = switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { | |
| 5380 | .struct_type => switch (struct_ty.containerLayout(mod)) { | |
| 5381 | .Auto, .Extern => if (struct_ty.isSimpleTuple(mod)) | |
| 5394 | 5382 | .{ .field = extra.field_index } |
| 5395 | 5383 | else |
| 5396 | .{ .identifier = struct_ty.structFieldName(extra.field_index) }, | |
| 5384 | .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, | |
| 5397 | 5385 | .Packed => { |
| 5398 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | |
| 5399 | const int_info = struct_ty.intInfo(target); | |
| 5386 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 5387 | const int_info = struct_ty.intInfo(mod); | |
| 5400 | 5388 | |
| 5401 | var bit_offset_ty_pl = Type.Payload.Bits{ | |
| 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); | |
| 5389 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1)); | |
| 5406 | 5390 | |
| 5407 | var bit_offset_val_pl: Value.Payload.U64 = .{ | |
| 5408 | .base = .{ .tag = .int_u64 }, | |
| 5409 | .data = struct_obj.packedFieldBitOffset(target, extra.field_index), | |
| 5410 | }; | |
| 5411 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | |
| 5391 | const bit_offset = struct_obj.packedFieldBitOffset(mod, extra.field_index); | |
| 5392 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | |
| 5412 | 5393 | |
| 5413 | const field_int_signedness = if (inst_ty.isAbiInt()) | |
| 5414 | inst_ty.intInfo(target).signedness | |
| 5394 | const field_int_signedness = if (inst_ty.isAbiInt(mod)) | |
| 5395 | inst_ty.intInfo(mod).signedness | |
| 5415 | 5396 | else |
| 5416 | 5397 | .unsigned; |
| 5417 | var field_int_pl = Type.Payload.Bits{ | |
| 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); | |
| 5398 | const field_int_ty = try mod.intType(field_int_signedness, @intCast(u16, inst_ty.bitSize(mod))); | |
| 5425 | 5399 | |
| 5426 | 5400 | const temp_local = try f.allocLocal(inst, field_int_ty); |
| 5427 | 5401 | try f.writeCValue(writer, temp_local, .Other); |
| ... | ... | @@ -5432,18 +5406,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5432 | 5406 | try writer.writeByte(')'); |
| 5433 | 5407 | const cant_cast = int_info.bits > 64; |
| 5434 | 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 | 5410 | try writer.writeAll("zig_lo_"); |
| 5437 | 5411 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); |
| 5438 | 5412 | try writer.writeByte('('); |
| 5439 | 5413 | } |
| 5440 | if (bit_offset_val_pl.data > 0) { | |
| 5414 | if (bit_offset > 0) { | |
| 5441 | 5415 | try writer.writeAll("zig_shr_"); |
| 5442 | 5416 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); |
| 5443 | 5417 | try writer.writeByte('('); |
| 5444 | 5418 | } |
| 5445 | 5419 | try f.writeCValue(writer, struct_byval, .Other); |
| 5446 | if (bit_offset_val_pl.data > 0) { | |
| 5420 | if (bit_offset > 0) { | |
| 5447 | 5421 | try writer.writeAll(", "); |
| 5448 | 5422 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 5449 | 5423 | try writer.writeByte(')'); |
| ... | ... | @@ -5465,36 +5439,46 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5465 | 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); | |
| 5479 | try writer.writeAll("memcpy(&"); | |
| 5480 | try f.writeCValue(writer, local, .Other); | |
| 5481 | try writer.writeAll(", &"); | |
| 5482 | try f.writeCValue(writer, operand_lval, .Other); | |
| 5483 | try writer.writeAll(", sizeof("); | |
| 5484 | try f.renderType(writer, inst_ty); | |
| 5485 | try writer.writeAll("));\n"); | |
| 5443 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0) | |
| 5444 | .{ .field = extra.field_index } | |
| 5445 | else | |
| 5446 | .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, | |
| 5447 | ||
| 5448 | .union_type => |union_type| field_name: { | |
| 5449 | const union_obj = mod.unionPtr(union_type.index); | |
| 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) { | |
| 5488 | try freeLocal(f, inst, operand_lval.new_local, 0); | |
| 5489 | } | |
| 5460 | const local = try f.allocLocal(inst, inst_ty); | |
| 5461 | try writer.writeAll("memcpy(&"); | |
| 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; | |
| 5492 | } else field_name: { | |
| 5493 | const name = struct_ty.unionFields().keys()[extra.field_index]; | |
| 5494 | break :field_name if (struct_ty.unionTagTypeSafety()) |_| | |
| 5495 | .{ .payload_identifier = name } | |
| 5496 | else | |
| 5497 | .{ .identifier = name }; | |
| 5469 | if (struct_byval == .constant) { | |
| 5470 | try freeLocal(f, inst, operand_lval.new_local, 0); | |
| 5471 | } | |
| 5472 | ||
| 5473 | return local; | |
| 5474 | } else { | |
| 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 | 5483 | else => unreachable, |
| 5500 | 5484 | }; |
| ... | ... | @@ -5511,20 +5495,21 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5511 | 5495 | /// *(E!T) -> E |
| 5512 | 5496 | /// Note that the result is never a pointer. |
| 5513 | 5497 | fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5498 | const mod = f.object.dg.module; | |
| 5514 | 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 | 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 | 5504 | try reap(f, inst, &.{ty_op.operand}); |
| 5520 | 5505 | |
| 5521 | const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; | |
| 5522 | const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | |
| 5523 | const error_ty = error_union_ty.errorUnionSet(); | |
| 5524 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 5506 | const operand_is_ptr = operand_ty.zigTypeTag(mod) == .Pointer; | |
| 5507 | const error_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; | |
| 5508 | const error_ty = error_union_ty.errorUnionSet(mod); | |
| 5509 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 5525 | 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 | 5513 | // The store will be 'x = x'; elide it. |
| 5529 | 5514 | return local; |
| 5530 | 5515 | } |
| ... | ... | @@ -5533,32 +5518,33 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5533 | 5518 | try f.writeCValue(writer, local, .Other); |
| 5534 | 5519 | try writer.writeAll(" = "); |
| 5535 | 5520 | |
| 5536 | if (!payload_ty.hasRuntimeBits()) { | |
| 5521 | if (!payload_ty.hasRuntimeBits(mod)) { | |
| 5537 | 5522 | try f.writeCValue(writer, operand, .Other); |
| 5538 | 5523 | } else { |
| 5539 | if (!error_ty.errorSetIsEmpty()) | |
| 5524 | if (!error_ty.errorSetIsEmpty(mod)) | |
| 5540 | 5525 | if (operand_is_ptr) |
| 5541 | 5526 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) |
| 5542 | 5527 | else |
| 5543 | 5528 | try f.writeCValueMember(writer, operand, .{ .identifier = "error" }) |
| 5544 | 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 | 5532 | try writer.writeAll(";\n"); |
| 5548 | 5533 | return local; |
| 5549 | 5534 | } |
| 5550 | 5535 | |
| 5551 | 5536 | fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 5537 | const mod = f.object.dg.module; | |
| 5552 | 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 | 5541 | const operand = try f.resolveInst(ty_op.operand); |
| 5556 | 5542 | try reap(f, inst, &.{ty_op.operand}); |
| 5557 | const operand_ty = f.air.typeOf(ty_op.operand); | |
| 5558 | const error_union_ty = if (is_ptr) operand_ty.childType() else operand_ty; | |
| 5543 | const operand_ty = f.typeOf(ty_op.operand); | |
| 5544 | const error_union_ty = if (is_ptr) operand_ty.childType(mod) else operand_ty; | |
| 5559 | 5545 | |
| 5560 | 5546 | const writer = f.object.writer(); |
| 5561 | if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { | |
| 5547 | if (!error_union_ty.errorUnionPayload(mod).hasRuntimeBits(mod)) { | |
| 5562 | 5548 | if (!is_ptr) return .none; |
| 5563 | 5549 | |
| 5564 | 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 | 5570 | } |
| 5585 | 5571 | |
| 5586 | 5572 | fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5573 | const mod = f.object.dg.module; | |
| 5587 | 5574 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5588 | 5575 | |
| 5589 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5590 | const repr_is_payload = inst_ty.optionalReprIsPayload(); | |
| 5591 | const payload_ty = f.air.typeOf(ty_op.operand); | |
| 5576 | const inst_ty = f.typeOfIndex(inst); | |
| 5577 | const repr_is_payload = inst_ty.optionalReprIsPayload(mod); | |
| 5578 | const payload_ty = f.typeOf(ty_op.operand); | |
| 5592 | 5579 | const payload = try f.resolveInst(ty_op.operand); |
| 5593 | 5580 | try reap(f, inst, &.{ty_op.operand}); |
| 5594 | 5581 | |
| ... | ... | @@ -5615,12 +5602,13 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5615 | 5602 | } |
| 5616 | 5603 | |
| 5617 | 5604 | fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5605 | const mod = f.object.dg.module; | |
| 5618 | 5606 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5619 | 5607 | |
| 5620 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5621 | const payload_ty = inst_ty.errorUnionPayload(); | |
| 5622 | const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(); | |
| 5623 | const err_ty = inst_ty.errorUnionSet(); | |
| 5608 | const inst_ty = f.typeOfIndex(inst); | |
| 5609 | const payload_ty = inst_ty.errorUnionPayload(mod); | |
| 5610 | const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(mod); | |
| 5611 | const err_ty = inst_ty.errorUnionSet(mod); | |
| 5624 | 5612 | const err = try f.resolveInst(ty_op.operand); |
| 5625 | 5613 | try reap(f, inst, &.{ty_op.operand}); |
| 5626 | 5614 | |
| ... | ... | @@ -5653,19 +5641,20 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5653 | 5641 | } |
| 5654 | 5642 | |
| 5655 | 5643 | fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5644 | const mod = f.object.dg.module; | |
| 5656 | 5645 | const writer = f.object.writer(); |
| 5657 | 5646 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5658 | 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(); | |
| 5662 | const payload_ty = error_union_ty.errorUnionPayload(); | |
| 5650 | const error_ty = error_union_ty.errorUnionSet(mod); | |
| 5651 | const payload_ty = error_union_ty.errorUnionPayload(mod); | |
| 5663 | 5652 | |
| 5664 | 5653 | // First, set the non-error value. |
| 5665 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5654 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 5666 | 5655 | try f.writeCValueDeref(writer, operand); |
| 5667 | 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 | 5658 | try writer.writeAll(";\n "); |
| 5670 | 5659 | |
| 5671 | 5660 | return operand; |
| ... | ... | @@ -5673,13 +5662,13 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5673 | 5662 | try reap(f, inst, &.{ty_op.operand}); |
| 5674 | 5663 | try f.writeCValueDeref(writer, operand); |
| 5675 | 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 | 5666 | try writer.writeAll(";\n"); |
| 5678 | 5667 | |
| 5679 | 5668 | // Then return the payload pointer (only if it is used) |
| 5680 | 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 | 5672 | try f.writeCValue(writer, local, .Other); |
| 5684 | 5673 | try writer.writeAll(" = &("); |
| 5685 | 5674 | try f.writeCValueDeref(writer, operand); |
| ... | ... | @@ -5703,13 +5692,14 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5703 | 5692 | } |
| 5704 | 5693 | |
| 5705 | 5694 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5695 | const mod = f.object.dg.module; | |
| 5706 | 5696 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5707 | 5697 | |
| 5708 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5709 | const payload_ty = inst_ty.errorUnionPayload(); | |
| 5698 | const inst_ty = f.typeOfIndex(inst); | |
| 5699 | const payload_ty = inst_ty.errorUnionPayload(mod); | |
| 5710 | 5700 | const payload = try f.resolveInst(ty_op.operand); |
| 5711 | const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(); | |
| 5712 | const err_ty = inst_ty.errorUnionSet(); | |
| 5701 | const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(mod); | |
| 5702 | const err_ty = inst_ty.errorUnionSet(mod); | |
| 5713 | 5703 | try reap(f, inst, &.{ty_op.operand}); |
| 5714 | 5704 | |
| 5715 | 5705 | const writer = f.object.writer(); |
| ... | ... | @@ -5728,29 +5718,30 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5728 | 5718 | else |
| 5729 | 5719 | try f.writeCValueMember(writer, local, .{ .identifier = "error" }); |
| 5730 | 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 | 5722 | try a.end(f, writer); |
| 5733 | 5723 | } |
| 5734 | 5724 | return local; |
| 5735 | 5725 | } |
| 5736 | 5726 | |
| 5737 | 5727 | fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue { |
| 5728 | const mod = f.object.dg.module; | |
| 5738 | 5729 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 5739 | 5730 | |
| 5740 | 5731 | const writer = f.object.writer(); |
| 5741 | 5732 | const operand = try f.resolveInst(un_op); |
| 5742 | 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 | 5735 | const local = try f.allocLocal(inst, Type.bool); |
| 5745 | const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty; | |
| 5746 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 5747 | const error_ty = err_union_ty.errorUnionSet(); | |
| 5736 | const err_union_ty = if (is_ptr) operand_ty.childType(mod) else operand_ty; | |
| 5737 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 5738 | const error_ty = err_union_ty.errorUnionSet(mod); | |
| 5748 | 5739 | |
| 5749 | 5740 | try f.writeCValue(writer, local, .Other); |
| 5750 | 5741 | try writer.writeAll(" = "); |
| 5751 | 5742 | |
| 5752 | if (!error_ty.errorSetIsEmpty()) | |
| 5753 | if (payload_ty.hasRuntimeBits()) | |
| 5743 | if (!error_ty.errorSetIsEmpty(mod)) | |
| 5744 | if (payload_ty.hasRuntimeBits(mod)) | |
| 5754 | 5745 | if (is_ptr) |
| 5755 | 5746 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) |
| 5756 | 5747 | else |
| ... | ... | @@ -5758,42 +5749,40 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const |
| 5758 | 5749 | else |
| 5759 | 5750 | try f.writeCValue(writer, operand, .Other) |
| 5760 | 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 | 5753 | try writer.writeByte(' '); |
| 5763 | 5754 | try writer.writeAll(operator); |
| 5764 | 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 | 5757 | try writer.writeAll(";\n"); |
| 5767 | 5758 | return local; |
| 5768 | 5759 | } |
| 5769 | 5760 | |
| 5770 | 5761 | fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5762 | const mod = f.object.dg.module; | |
| 5771 | 5763 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5772 | 5764 | |
| 5773 | 5765 | const operand = try f.resolveInst(ty_op.operand); |
| 5774 | 5766 | try reap(f, inst, &.{ty_op.operand}); |
| 5775 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5767 | const inst_ty = f.typeOfIndex(inst); | |
| 5776 | 5768 | const writer = f.object.writer(); |
| 5777 | 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 | 5772 | try f.writeCValueMember(writer, local, .{ .identifier = "ptr" }); |
| 5781 | 5773 | try writer.writeAll(" = "); |
| 5782 | 5774 | // Unfortunately, C does not support any equivalent to |
| 5783 | 5775 | // &(*(void *)p)[0], although LLVM does via GetElementPtr |
| 5784 | 5776 | if (operand == .undef) { |
| 5785 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 5786 | try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer); | |
| 5787 | } else if (array_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5777 | try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(mod) }, .Initializer); | |
| 5778 | } else if (array_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 5788 | 5779 | try writer.writeAll("&("); |
| 5789 | 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 | 5782 | } else try f.writeCValue(writer, operand, .Initializer); |
| 5792 | 5783 | try writer.writeAll("; "); |
| 5793 | 5784 | |
| 5794 | const array_len = array_ty.arrayLen(); | |
| 5795 | var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len }; | |
| 5796 | const len_val = Value.initPayload(&len_pl.base); | |
| 5785 | const len_val = try mod.intValue(Type.usize, array_ty.arrayLen(mod)); | |
| 5797 | 5786 | try f.writeCValueMember(writer, local, .{ .identifier = "len" }); |
| 5798 | 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 | 5790 | } |
| 5802 | 5791 | |
| 5803 | 5792 | fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5793 | const mod = f.object.dg.module; | |
| 5804 | 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 | 5797 | const operand = try f.resolveInst(ty_op.operand); |
| 5808 | 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 | 5800 | const target = f.object.dg.module.getTarget(); |
| 5811 | 5801 | const operation = if (inst_ty.isRuntimeFloat() and operand_ty.isRuntimeFloat()) |
| 5812 | 5802 | if (inst_ty.floatBits(target) < operand_ty.floatBits(target)) "trunc" else "extend" |
| 5813 | else if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) | |
| 5814 | if (inst_ty.isSignedInt()) "fix" else "fixuns" | |
| 5815 | else if (inst_ty.isRuntimeFloat() and operand_ty.isInt()) | |
| 5816 | if (operand_ty.isSignedInt()) "float" else "floatun" | |
| 5803 | else if (inst_ty.isInt(mod) and operand_ty.isRuntimeFloat()) | |
| 5804 | if (inst_ty.isSignedInt(mod)) "fix" else "fixuns" | |
| 5805 | else if (inst_ty.isRuntimeFloat() and operand_ty.isInt(mod)) | |
| 5806 | if (operand_ty.isSignedInt(mod)) "float" else "floatun" | |
| 5817 | 5807 | else |
| 5818 | 5808 | unreachable; |
| 5819 | 5809 | |
| ... | ... | @@ -5822,19 +5812,19 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5822 | 5812 | try f.writeCValue(writer, local, .Other); |
| 5823 | 5813 | |
| 5824 | 5814 | try writer.writeAll(" = "); |
| 5825 | if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) { | |
| 5815 | if (inst_ty.isInt(mod) and operand_ty.isRuntimeFloat()) { | |
| 5826 | 5816 | try writer.writeAll("zig_wrap_"); |
| 5827 | 5817 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 5828 | 5818 | try writer.writeByte('('); |
| 5829 | 5819 | } |
| 5830 | 5820 | try writer.writeAll("zig_"); |
| 5831 | 5821 | try writer.writeAll(operation); |
| 5832 | try writer.writeAll(compilerRtAbbrev(operand_ty, target)); | |
| 5833 | try writer.writeAll(compilerRtAbbrev(inst_ty, target)); | |
| 5822 | try writer.writeAll(compilerRtAbbrev(operand_ty, mod)); | |
| 5823 | try writer.writeAll(compilerRtAbbrev(inst_ty, mod)); | |
| 5834 | 5824 | try writer.writeByte('('); |
| 5835 | 5825 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 5836 | 5826 | try writer.writeByte(')'); |
| 5837 | if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) { | |
| 5827 | if (inst_ty.isInt(mod) and operand_ty.isRuntimeFloat()) { | |
| 5838 | 5828 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); |
| 5839 | 5829 | try writer.writeByte(')'); |
| 5840 | 5830 | } |
| ... | ... | @@ -5843,12 +5833,13 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5843 | 5833 | } |
| 5844 | 5834 | |
| 5845 | 5835 | fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5836 | const mod = f.object.dg.module; | |
| 5846 | 5837 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 5847 | 5838 | |
| 5848 | 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 | 5841 | try reap(f, inst, &.{un_op}); |
| 5851 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5842 | const inst_ty = f.typeOfIndex(inst); | |
| 5852 | 5843 | const writer = f.object.writer(); |
| 5853 | 5844 | const local = try f.allocLocal(inst, inst_ty); |
| 5854 | 5845 | try f.writeCValue(writer, local, .Other); |
| ... | ... | @@ -5856,7 +5847,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5856 | 5847 | try writer.writeAll(" = ("); |
| 5857 | 5848 | try f.renderType(writer, inst_ty); |
| 5858 | 5849 | try writer.writeByte(')'); |
| 5859 | if (operand_ty.isSlice()) { | |
| 5850 | if (operand_ty.isSlice(mod)) { | |
| 5860 | 5851 | try f.writeCValueMember(writer, operand, .{ .identifier = "len" }); |
| 5861 | 5852 | } else { |
| 5862 | 5853 | try f.writeCValue(writer, operand, .Other); |
| ... | ... | @@ -5871,14 +5862,15 @@ fn airUnBuiltinCall( |
| 5871 | 5862 | operation: []const u8, |
| 5872 | 5863 | info: BuiltinInfo, |
| 5873 | 5864 | ) !CValue { |
| 5865 | const mod = f.object.dg.module; | |
| 5874 | 5866 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5875 | 5867 | |
| 5876 | 5868 | const operand = try f.resolveInst(ty_op.operand); |
| 5877 | 5869 | try reap(f, inst, &.{ty_op.operand}); |
| 5878 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5879 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 5880 | const operand_ty = f.air.typeOf(ty_op.operand); | |
| 5881 | const scalar_ty = operand_ty.scalarType(); | |
| 5870 | const inst_ty = f.typeOfIndex(inst); | |
| 5871 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 5872 | const operand_ty = f.typeOf(ty_op.operand); | |
| 5873 | const scalar_ty = operand_ty.scalarType(mod); | |
| 5882 | 5874 | |
| 5883 | 5875 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); |
| 5884 | 5876 | const ref_ret = inst_scalar_cty.tag() == .array; |
| ... | ... | @@ -5914,9 +5906,10 @@ fn airBinBuiltinCall( |
| 5914 | 5906 | operation: []const u8, |
| 5915 | 5907 | info: BuiltinInfo, |
| 5916 | 5908 | ) !CValue { |
| 5909 | const mod = f.object.dg.module; | |
| 5917 | 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 | 5913 | const operand_cty = try f.typeToCType(operand_ty, .complete); |
| 5921 | 5914 | const is_big = operand_cty.tag() == .array; |
| 5922 | 5915 | |
| ... | ... | @@ -5924,9 +5917,9 @@ fn airBinBuiltinCall( |
| 5924 | 5917 | const rhs = try f.resolveInst(bin_op.rhs); |
| 5925 | 5918 | if (!is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 5926 | 5919 | |
| 5927 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5928 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 5929 | const scalar_ty = operand_ty.scalarType(); | |
| 5920 | const inst_ty = f.typeOfIndex(inst); | |
| 5921 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 5922 | const scalar_ty = operand_ty.scalarType(mod); | |
| 5930 | 5923 | |
| 5931 | 5924 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); |
| 5932 | 5925 | const ref_ret = inst_scalar_cty.tag() == .array; |
| ... | ... | @@ -5968,14 +5961,15 @@ fn airCmpBuiltinCall( |
| 5968 | 5961 | operation: enum { cmp, operator }, |
| 5969 | 5962 | info: BuiltinInfo, |
| 5970 | 5963 | ) !CValue { |
| 5964 | const mod = f.object.dg.module; | |
| 5971 | 5965 | const lhs = try f.resolveInst(data.lhs); |
| 5972 | 5966 | const rhs = try f.resolveInst(data.rhs); |
| 5973 | 5967 | try reap(f, inst, &.{ data.lhs, data.rhs }); |
| 5974 | 5968 | |
| 5975 | const inst_ty = f.air.typeOfIndex(inst); | |
| 5976 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 5977 | const operand_ty = f.air.typeOf(data.lhs); | |
| 5978 | const scalar_ty = operand_ty.scalarType(); | |
| 5969 | const inst_ty = f.typeOfIndex(inst); | |
| 5970 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 5971 | const operand_ty = f.typeOf(data.lhs); | |
| 5972 | const scalar_ty = operand_ty.scalarType(mod); | |
| 5979 | 5973 | |
| 5980 | 5974 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); |
| 5981 | 5975 | const ref_ret = inst_scalar_cty.tag() == .array; |
| ... | ... | @@ -6008,7 +6002,7 @@ fn airCmpBuiltinCall( |
| 6008 | 6002 | try writer.writeByte(')'); |
| 6009 | 6003 | if (!ref_ret) try writer.print(" {s} {}", .{ |
| 6010 | 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 | 6007 | try writer.writeAll(";\n"); |
| 6014 | 6008 | try v.end(f, inst, writer); |
| ... | ... | @@ -6017,28 +6011,27 @@ fn airCmpBuiltinCall( |
| 6017 | 6011 | } |
| 6018 | 6012 | |
| 6019 | 6013 | fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { |
| 6014 | const mod = f.object.dg.module; | |
| 6020 | 6015 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 6021 | 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 | 6018 | const ptr = try f.resolveInst(extra.ptr); |
| 6024 | 6019 | const expected_value = try f.resolveInst(extra.expected_value); |
| 6025 | 6020 | const new_value = try f.resolveInst(extra.new_value); |
| 6026 | const ptr_ty = f.air.typeOf(extra.ptr); | |
| 6027 | const ty = ptr_ty.childType(); | |
| 6021 | const ptr_ty = f.typeOf(extra.ptr); | |
| 6022 | const ty = ptr_ty.childType(mod); | |
| 6028 | 6023 | |
| 6029 | 6024 | const writer = f.object.writer(); |
| 6030 | 6025 | const new_value_mat = try Materialize.start(f, inst, writer, ty, new_value); |
| 6031 | 6026 | try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value }); |
| 6032 | 6027 | |
| 6033 | const target = f.object.dg.module.getTarget(); | |
| 6034 | var repr_pl = Type.Payload.Bits{ | |
| 6035 | .base = .{ .tag = .int_unsigned }, | |
| 6036 | .data = @intCast(u16, ty.abiSize(target) * 8), | |
| 6037 | }; | |
| 6038 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | |
| 6028 | const repr_ty = if (ty.isRuntimeFloat()) | |
| 6029 | mod.intType(.unsigned, @intCast(u16, ty.abiSize(mod) * 8)) catch unreachable | |
| 6030 | else | |
| 6031 | ty; | |
| 6039 | 6032 | |
| 6040 | 6033 | const local = try f.allocLocal(inst, inst_ty); |
| 6041 | if (inst_ty.isPtrLikeOptional()) { | |
| 6034 | if (inst_ty.isPtrLikeOptional(mod)) { | |
| 6042 | 6035 | { |
| 6043 | 6036 | const a = try Assignment.start(f, writer, ty); |
| 6044 | 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 | 6044 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 6052 | 6045 | try f.renderType(writer, ty); |
| 6053 | 6046 | try writer.writeByte(')'); |
| 6054 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | |
| 6047 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); | |
| 6055 | 6048 | try writer.writeAll(" *)"); |
| 6056 | 6049 | try f.writeCValue(writer, ptr, .Other); |
| 6057 | 6050 | try writer.writeAll(", "); |
| ... | ... | @@ -6093,7 +6086,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6093 | 6086 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 6094 | 6087 | try f.renderType(writer, ty); |
| 6095 | 6088 | try writer.writeByte(')'); |
| 6096 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | |
| 6089 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); | |
| 6097 | 6090 | try writer.writeAll(" *)"); |
| 6098 | 6091 | try f.writeCValue(writer, ptr, .Other); |
| 6099 | 6092 | try writer.writeAll(", "); |
| ... | ... | @@ -6123,11 +6116,12 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6123 | 6116 | } |
| 6124 | 6117 | |
| 6125 | 6118 | fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6119 | const mod = f.object.dg.module; | |
| 6126 | 6120 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 6127 | 6121 | const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 6128 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6129 | const ptr_ty = f.air.typeOf(pl_op.operand); | |
| 6130 | const ty = ptr_ty.childType(); | |
| 6122 | const inst_ty = f.typeOfIndex(inst); | |
| 6123 | const ptr_ty = f.typeOf(pl_op.operand); | |
| 6124 | const ty = ptr_ty.childType(mod); | |
| 6131 | 6125 | const ptr = try f.resolveInst(pl_op.operand); |
| 6132 | 6126 | const operand = try f.resolveInst(extra.operand); |
| 6133 | 6127 | |
| ... | ... | @@ -6135,14 +6129,10 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6135 | 6129 | const operand_mat = try Materialize.start(f, inst, writer, ty, operand); |
| 6136 | 6130 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); |
| 6137 | 6131 | |
| 6138 | const target = f.object.dg.module.getTarget(); | |
| 6139 | var repr_pl = Type.Payload.Bits{ | |
| 6140 | .base = .{ .tag = .int_unsigned }, | |
| 6141 | .data = @intCast(u16, ty.abiSize(target) * 8), | |
| 6142 | }; | |
| 6132 | const repr_bits = @intCast(u16, ty.abiSize(mod) * 8); | |
| 6143 | 6133 | const is_float = ty.isRuntimeFloat(); |
| 6144 | const is_128 = repr_pl.data == 128; | |
| 6145 | const repr_ty = if (is_float) Type.initPayload(&repr_pl.base) else ty; | |
| 6134 | const is_128 = repr_bits == 128; | |
| 6135 | const repr_ty = if (is_float) mod.intType(.unsigned, repr_bits) catch unreachable else ty; | |
| 6146 | 6136 | |
| 6147 | 6137 | const local = try f.allocLocal(inst, inst_ty); |
| 6148 | 6138 | try writer.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())}); |
| ... | ... | @@ -6158,7 +6148,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6158 | 6148 | if (use_atomic) try writer.writeAll("zig_atomic("); |
| 6159 | 6149 | try f.renderType(writer, ty); |
| 6160 | 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 | 6152 | try writer.writeAll(" *)"); |
| 6163 | 6153 | try f.writeCValue(writer, ptr, .Other); |
| 6164 | 6154 | try writer.writeAll(", "); |
| ... | ... | @@ -6181,20 +6171,19 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6181 | 6171 | } |
| 6182 | 6172 | |
| 6183 | 6173 | fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6174 | const mod = f.object.dg.module; | |
| 6184 | 6175 | const atomic_load = f.air.instructions.items(.data)[inst].atomic_load; |
| 6185 | 6176 | const ptr = try f.resolveInst(atomic_load.ptr); |
| 6186 | 6177 | try reap(f, inst, &.{atomic_load.ptr}); |
| 6187 | const ptr_ty = f.air.typeOf(atomic_load.ptr); | |
| 6188 | const ty = ptr_ty.childType(); | |
| 6178 | const ptr_ty = f.typeOf(atomic_load.ptr); | |
| 6179 | const ty = ptr_ty.childType(mod); | |
| 6189 | 6180 | |
| 6190 | const target = f.object.dg.module.getTarget(); | |
| 6191 | var repr_pl = Type.Payload.Bits{ | |
| 6192 | .base = .{ .tag = .int_unsigned }, | |
| 6193 | .data = @intCast(u16, ty.abiSize(target) * 8), | |
| 6194 | }; | |
| 6195 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | |
| 6181 | const repr_ty = if (ty.isRuntimeFloat()) | |
| 6182 | mod.intType(.unsigned, @intCast(u16, ty.abiSize(mod) * 8)) catch unreachable | |
| 6183 | else | |
| 6184 | ty; | |
| 6196 | 6185 | |
| 6197 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6186 | const inst_ty = f.typeOfIndex(inst); | |
| 6198 | 6187 | const writer = f.object.writer(); |
| 6199 | 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 | 6192 | try writer.writeAll(", (zig_atomic("); |
| 6204 | 6193 | try f.renderType(writer, ty); |
| 6205 | 6194 | try writer.writeByte(')'); |
| 6206 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | |
| 6195 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); | |
| 6207 | 6196 | try writer.writeAll(" *)"); |
| 6208 | 6197 | try f.writeCValue(writer, ptr, .Other); |
| 6209 | 6198 | try writer.writeAll(", "); |
| ... | ... | @@ -6218,9 +6207,10 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6218 | 6207 | } |
| 6219 | 6208 | |
| 6220 | 6209 | fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue { |
| 6210 | const mod = f.object.dg.module; | |
| 6221 | 6211 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 6222 | const ptr_ty = f.air.typeOf(bin_op.lhs); | |
| 6223 | const ty = ptr_ty.childType(); | |
| 6212 | const ptr_ty = f.typeOf(bin_op.lhs); | |
| 6213 | const ty = ptr_ty.childType(mod); | |
| 6224 | 6214 | const ptr = try f.resolveInst(bin_op.lhs); |
| 6225 | 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 | 6218 | const element_mat = try Materialize.start(f, inst, writer, ty, element); |
| 6229 | 6219 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 6230 | 6220 | |
| 6231 | const target = f.object.dg.module.getTarget(); | |
| 6232 | var repr_pl = Type.Payload.Bits{ | |
| 6233 | .base = .{ .tag = .int_unsigned }, | |
| 6234 | .data = @intCast(u16, ty.abiSize(target) * 8), | |
| 6235 | }; | |
| 6236 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | |
| 6221 | const repr_ty = if (ty.isRuntimeFloat()) | |
| 6222 | mod.intType(.unsigned, @intCast(u16, ty.abiSize(mod) * 8)) catch unreachable | |
| 6223 | else | |
| 6224 | ty; | |
| 6237 | 6225 | |
| 6238 | 6226 | try writer.writeAll("zig_atomic_store((zig_atomic("); |
| 6239 | 6227 | try f.renderType(writer, ty); |
| 6240 | 6228 | try writer.writeByte(')'); |
| 6241 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | |
| 6229 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); | |
| 6242 | 6230 | try writer.writeAll(" *)"); |
| 6243 | 6231 | try f.writeCValue(writer, ptr, .Other); |
| 6244 | 6232 | try writer.writeAll(", "); |
| ... | ... | @@ -6254,7 +6242,8 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa |
| 6254 | 6242 | } |
| 6255 | 6243 | |
| 6256 | 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 | 6247 | try f.writeCValueMember(writer, ptr, .{ .identifier = "ptr" }); |
| 6259 | 6248 | } else { |
| 6260 | 6249 | try f.writeCValue(writer, ptr, .FunctionArgument); |
| ... | ... | @@ -6262,14 +6251,14 @@ fn writeSliceOrPtr(f: *Function, writer: anytype, ptr: CValue, ptr_ty: Type) !vo |
| 6262 | 6251 | } |
| 6263 | 6252 | |
| 6264 | 6253 | fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6254 | const mod = f.object.dg.module; | |
| 6265 | 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 | 6257 | const dest_slice = try f.resolveInst(bin_op.lhs); |
| 6268 | 6258 | const value = try f.resolveInst(bin_op.rhs); |
| 6269 | const elem_ty = f.air.typeOf(bin_op.rhs); | |
| 6270 | const target = f.object.dg.module.getTarget(); | |
| 6271 | const elem_abi_size = elem_ty.abiSize(target); | |
| 6272 | const val_is_undef = if (f.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; | |
| 6259 | const elem_ty = f.typeOf(bin_op.rhs); | |
| 6260 | const elem_abi_size = elem_ty.abiSize(mod); | |
| 6261 | const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false; | |
| 6273 | 6262 | const writer = f.object.writer(); |
| 6274 | 6263 | |
| 6275 | 6264 | if (val_is_undef) { |
| ... | ... | @@ -6279,7 +6268,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6279 | 6268 | } |
| 6280 | 6269 | |
| 6281 | 6270 | try writer.writeAll("memset("); |
| 6282 | switch (dest_ty.ptrSize()) { | |
| 6271 | switch (dest_ty.ptrSize(mod)) { | |
| 6283 | 6272 | .Slice => { |
| 6284 | 6273 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); |
| 6285 | 6274 | try writer.writeAll(", 0xaa, "); |
| ... | ... | @@ -6291,8 +6280,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6291 | 6280 | } |
| 6292 | 6281 | }, |
| 6293 | 6282 | .One => { |
| 6294 | const array_ty = dest_ty.childType(); | |
| 6295 | const len = array_ty.arrayLen() * elem_abi_size; | |
| 6283 | const array_ty = dest_ty.childType(mod); | |
| 6284 | const len = array_ty.arrayLen(mod) * elem_abi_size; | |
| 6296 | 6285 | |
| 6297 | 6286 | try f.writeCValue(writer, dest_slice, .FunctionArgument); |
| 6298 | 6287 | try writer.print(", 0xaa, {d});\n", .{len}); |
| ... | ... | @@ -6303,32 +6292,33 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6303 | 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 | 6296 | // For the assignment in this loop, the array pointer needs to get |
| 6308 | 6297 | // casted to a regular pointer, otherwise an error like this occurs: |
| 6309 | 6298 | // error: array type 'uint32_t[20]' (aka 'unsigned int[20]') is not assignable |
| 6310 | var elem_ptr_ty_pl: Type.Payload.ElemType = .{ | |
| 6311 | .base = .{ .tag = .c_mut_pointer }, | |
| 6312 | .data = elem_ty, | |
| 6313 | }; | |
| 6314 | const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base); | |
| 6299 | const elem_ptr_ty = try mod.ptrType(.{ | |
| 6300 | .child = elem_ty.ip_index, | |
| 6301 | .flags = .{ | |
| 6302 | .size = .C, | |
| 6303 | }, | |
| 6304 | }); | |
| 6315 | 6305 | |
| 6316 | 6306 | const index = try f.allocLocal(inst, Type.usize); |
| 6317 | 6307 | |
| 6318 | 6308 | try writer.writeAll("for ("); |
| 6319 | 6309 | try f.writeCValue(writer, index, .Other); |
| 6320 | 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 | 6312 | try writer.writeAll("; "); |
| 6323 | 6313 | try f.writeCValue(writer, index, .Other); |
| 6324 | 6314 | try writer.writeAll(" != "); |
| 6325 | switch (dest_ty.ptrSize()) { | |
| 6315 | switch (dest_ty.ptrSize(mod)) { | |
| 6326 | 6316 | .Slice => { |
| 6327 | 6317 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" }); |
| 6328 | 6318 | }, |
| 6329 | 6319 | .One => { |
| 6330 | const array_ty = dest_ty.childType(); | |
| 6331 | try writer.print("{d}", .{array_ty.arrayLen()}); | |
| 6320 | const array_ty = dest_ty.childType(mod); | |
| 6321 | try writer.print("{d}", .{array_ty.arrayLen(mod)}); | |
| 6332 | 6322 | }, |
| 6333 | 6323 | .Many, .C => unreachable, |
| 6334 | 6324 | } |
| ... | ... | @@ -6357,7 +6347,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6357 | 6347 | const bitcasted = try bitcast(f, Type.u8, value, elem_ty); |
| 6358 | 6348 | |
| 6359 | 6349 | try writer.writeAll("memset("); |
| 6360 | switch (dest_ty.ptrSize()) { | |
| 6350 | switch (dest_ty.ptrSize(mod)) { | |
| 6361 | 6351 | .Slice => { |
| 6362 | 6352 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); |
| 6363 | 6353 | try writer.writeAll(", "); |
| ... | ... | @@ -6367,8 +6357,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6367 | 6357 | try writer.writeAll(");\n"); |
| 6368 | 6358 | }, |
| 6369 | 6359 | .One => { |
| 6370 | const array_ty = dest_ty.childType(); | |
| 6371 | const len = array_ty.arrayLen() * elem_abi_size; | |
| 6360 | const array_ty = dest_ty.childType(mod); | |
| 6361 | const len = array_ty.arrayLen(mod) * elem_abi_size; | |
| 6372 | 6362 | |
| 6373 | 6363 | try f.writeCValue(writer, dest_slice, .FunctionArgument); |
| 6374 | 6364 | try writer.writeAll(", "); |
| ... | ... | @@ -6383,12 +6373,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6383 | 6373 | } |
| 6384 | 6374 | |
| 6385 | 6375 | fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6376 | const mod = f.object.dg.module; | |
| 6386 | 6377 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 6387 | 6378 | const dest_ptr = try f.resolveInst(bin_op.lhs); |
| 6388 | 6379 | const src_ptr = try f.resolveInst(bin_op.rhs); |
| 6389 | const dest_ty = f.air.typeOf(bin_op.lhs); | |
| 6390 | const src_ty = f.air.typeOf(bin_op.rhs); | |
| 6391 | const target = f.object.dg.module.getTarget(); | |
| 6380 | const dest_ty = f.typeOf(bin_op.lhs); | |
| 6381 | const src_ty = f.typeOf(bin_op.rhs); | |
| 6392 | 6382 | const writer = f.object.writer(); |
| 6393 | 6383 | |
| 6394 | 6384 | try writer.writeAll("memcpy("); |
| ... | ... | @@ -6396,10 +6386,10 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6396 | 6386 | try writer.writeAll(", "); |
| 6397 | 6387 | try writeSliceOrPtr(f, writer, src_ptr, src_ty); |
| 6398 | 6388 | try writer.writeAll(", "); |
| 6399 | switch (dest_ty.ptrSize()) { | |
| 6389 | switch (dest_ty.ptrSize(mod)) { | |
| 6400 | 6390 | .Slice => { |
| 6401 | const elem_ty = dest_ty.childType(); | |
| 6402 | const elem_abi_size = elem_ty.abiSize(target); | |
| 6391 | const elem_ty = dest_ty.childType(mod); | |
| 6392 | const elem_abi_size = elem_ty.abiSize(mod); | |
| 6403 | 6393 | try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }); |
| 6404 | 6394 | if (elem_abi_size > 1) { |
| 6405 | 6395 | try writer.print(" * {d});\n", .{elem_abi_size}); |
| ... | ... | @@ -6408,10 +6398,10 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6408 | 6398 | } |
| 6409 | 6399 | }, |
| 6410 | 6400 | .One => { |
| 6411 | const array_ty = dest_ty.childType(); | |
| 6412 | const elem_ty = array_ty.childType(); | |
| 6413 | const elem_abi_size = elem_ty.abiSize(target); | |
| 6414 | const len = array_ty.arrayLen() * elem_abi_size; | |
| 6401 | const array_ty = dest_ty.childType(mod); | |
| 6402 | const elem_ty = array_ty.childType(mod); | |
| 6403 | const elem_abi_size = elem_ty.abiSize(mod); | |
| 6404 | const len = array_ty.arrayLen(mod) * elem_abi_size; | |
| 6415 | 6405 | try writer.print("{d});\n", .{len}); |
| 6416 | 6406 | }, |
| 6417 | 6407 | .Many, .C => unreachable, |
| ... | ... | @@ -6422,16 +6412,16 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6422 | 6412 | } |
| 6423 | 6413 | |
| 6424 | 6414 | fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6415 | const mod = f.object.dg.module; | |
| 6425 | 6416 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 6426 | 6417 | const union_ptr = try f.resolveInst(bin_op.lhs); |
| 6427 | 6418 | const new_tag = try f.resolveInst(bin_op.rhs); |
| 6428 | 6419 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 6429 | 6420 | |
| 6430 | const target = f.object.dg.module.getTarget(); | |
| 6431 | const union_ty = f.air.typeOf(bin_op.lhs).childType(); | |
| 6432 | const layout = union_ty.unionGetLayout(target); | |
| 6421 | const union_ty = f.typeOf(bin_op.lhs).childType(mod); | |
| 6422 | const layout = union_ty.unionGetLayout(mod); | |
| 6433 | 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 | 6426 | const writer = f.object.writer(); |
| 6437 | 6427 | const a = try Assignment.start(f, writer, tag_ty); |
| ... | ... | @@ -6443,17 +6433,17 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6443 | 6433 | } |
| 6444 | 6434 | |
| 6445 | 6435 | fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6436 | const mod = f.object.dg.module; | |
| 6446 | 6437 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 6447 | 6438 | |
| 6448 | 6439 | const operand = try f.resolveInst(ty_op.operand); |
| 6449 | 6440 | try reap(f, inst, &.{ty_op.operand}); |
| 6450 | 6441 | |
| 6451 | const union_ty = f.air.typeOf(ty_op.operand); | |
| 6452 | const target = f.object.dg.module.getTarget(); | |
| 6453 | const layout = union_ty.unionGetLayout(target); | |
| 6442 | const union_ty = f.typeOf(ty_op.operand); | |
| 6443 | const layout = union_ty.unionGetLayout(mod); | |
| 6454 | 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 | 6447 | const writer = f.object.writer(); |
| 6458 | 6448 | const local = try f.allocLocal(inst, inst_ty); |
| 6459 | 6449 | const a = try Assignment.start(f, writer, inst_ty); |
| ... | ... | @@ -6465,10 +6455,11 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6465 | 6455 | } |
| 6466 | 6456 | |
| 6467 | 6457 | fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6458 | const mod = f.object.dg.module; | |
| 6468 | 6459 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 6469 | 6460 | |
| 6470 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6471 | const enum_ty = f.air.typeOf(un_op); | |
| 6461 | const inst_ty = f.typeOfIndex(inst); | |
| 6462 | const enum_ty = f.typeOf(un_op); | |
| 6472 | 6463 | const operand = try f.resolveInst(un_op); |
| 6473 | 6464 | try reap(f, inst, &.{un_op}); |
| 6474 | 6465 | |
| ... | ... | @@ -6476,7 +6467,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6476 | 6467 | const local = try f.allocLocal(inst, inst_ty); |
| 6477 | 6468 | try f.writeCValue(writer, local, .Other); |
| 6478 | 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 | 6472 | try f.writeCValue(writer, operand, .Other); |
| 6482 | 6473 | try writer.writeAll(");\n"); |
| ... | ... | @@ -6488,7 +6479,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6488 | 6479 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 6489 | 6480 | |
| 6490 | 6481 | const writer = f.object.writer(); |
| 6491 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6482 | const inst_ty = f.typeOfIndex(inst); | |
| 6492 | 6483 | const operand = try f.resolveInst(un_op); |
| 6493 | 6484 | try reap(f, inst, &.{un_op}); |
| 6494 | 6485 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -6501,13 +6492,14 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6501 | 6492 | } |
| 6502 | 6493 | |
| 6503 | 6494 | fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6495 | const mod = f.object.dg.module; | |
| 6504 | 6496 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 6505 | 6497 | |
| 6506 | 6498 | const operand = try f.resolveInst(ty_op.operand); |
| 6507 | 6499 | try reap(f, inst, &.{ty_op.operand}); |
| 6508 | 6500 | |
| 6509 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6510 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 6501 | const inst_ty = f.typeOfIndex(inst); | |
| 6502 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 6511 | 6503 | |
| 6512 | 6504 | const writer = f.object.writer(); |
| 6513 | 6505 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -6532,7 +6524,7 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6532 | 6524 | const rhs = try f.resolveInst(extra.rhs); |
| 6533 | 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 | 6529 | const writer = f.object.writer(); |
| 6538 | 6530 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -6555,41 +6547,31 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6555 | 6547 | } |
| 6556 | 6548 | |
| 6557 | 6549 | fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6550 | const mod = f.object.dg.module; | |
| 6558 | 6551 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 6559 | 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 | 6555 | const lhs = try f.resolveInst(extra.a); |
| 6563 | 6556 | const rhs = try f.resolveInst(extra.b); |
| 6564 | 6557 | |
| 6565 | const module = f.object.dg.module; | |
| 6566 | const target = module.getTarget(); | |
| 6567 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6558 | const inst_ty = f.typeOfIndex(inst); | |
| 6568 | 6559 | |
| 6569 | 6560 | const writer = f.object.writer(); |
| 6570 | 6561 | const local = try f.allocLocal(inst, inst_ty); |
| 6571 | 6562 | try reap(f, inst, &.{ extra.a, extra.b }); // local cannot alias operands |
| 6572 | 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 | 6564 | try f.writeCValue(writer, local, .Other); |
| 6579 | 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 | 6567 | try writer.writeAll("] = "); |
| 6582 | 6568 | |
| 6583 | var buf: Value.ElemValueBuffer = undefined; | |
| 6584 | const mask_elem = mask.elemValueBuffer(module, index, &buf).toSignedInt(target); | |
| 6585 | var src_pl = Value.Payload.U64{ | |
| 6586 | .base = .{ .tag = .int_u64 }, | |
| 6587 | .data = @intCast(u64, mask_elem ^ mask_elem >> 63), | |
| 6588 | }; | |
| 6569 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); | |
| 6570 | const src_val = try mod.intValue(Type.usize, @intCast(u64, mask_elem ^ mask_elem >> 63)); | |
| 6589 | 6571 | |
| 6590 | 6572 | try f.writeCValue(writer, if (mask_elem >= 0) lhs else rhs, .Other); |
| 6591 | 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 | 6575 | try writer.writeAll("];\n"); |
| 6594 | 6576 | } |
| 6595 | 6577 | |
| ... | ... | @@ -6597,16 +6579,16 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6597 | 6579 | } |
| 6598 | 6580 | |
| 6599 | 6581 | fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6582 | const mod = f.object.dg.module; | |
| 6600 | 6583 | const reduce = f.air.instructions.items(.data)[inst].reduce; |
| 6601 | 6584 | |
| 6602 | const target = f.object.dg.module.getTarget(); | |
| 6603 | const scalar_ty = f.air.typeOfIndex(inst); | |
| 6585 | const scalar_ty = f.typeOfIndex(inst); | |
| 6604 | 6586 | const operand = try f.resolveInst(reduce.operand); |
| 6605 | 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 | 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 | 6592 | const op: union(enum) { |
| 6611 | 6593 | const Func = struct { operation: []const u8, info: BuiltinInfo = .none }; |
| 6612 | 6594 | float_op: Func, |
| ... | ... | @@ -6617,28 +6599,28 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6617 | 6599 | .And => if (use_operator) .{ .infix = " &= " } else .{ .builtin = .{ .operation = "and" } }, |
| 6618 | 6600 | .Or => if (use_operator) .{ .infix = " |= " } else .{ .builtin = .{ .operation = "or" } }, |
| 6619 | 6601 | .Xor => if (use_operator) .{ .infix = " ^= " } else .{ .builtin = .{ .operation = "xor" } }, |
| 6620 | .Min => switch (scalar_ty.zigTypeTag()) { | |
| 6602 | .Min => switch (scalar_ty.zigTypeTag(mod)) { | |
| 6621 | 6603 | .Int => if (use_operator) .{ .ternary = " < " } else .{ |
| 6622 | 6604 | .builtin = .{ .operation = "min" }, |
| 6623 | 6605 | }, |
| 6624 | 6606 | .Float => .{ .float_op = .{ .operation = "fmin" } }, |
| 6625 | 6607 | else => unreachable, |
| 6626 | 6608 | }, |
| 6627 | .Max => switch (scalar_ty.zigTypeTag()) { | |
| 6609 | .Max => switch (scalar_ty.zigTypeTag(mod)) { | |
| 6628 | 6610 | .Int => if (use_operator) .{ .ternary = " > " } else .{ |
| 6629 | 6611 | .builtin = .{ .operation = "max" }, |
| 6630 | 6612 | }, |
| 6631 | 6613 | .Float => .{ .float_op = .{ .operation = "fmax" } }, |
| 6632 | 6614 | else => unreachable, |
| 6633 | 6615 | }, |
| 6634 | .Add => switch (scalar_ty.zigTypeTag()) { | |
| 6616 | .Add => switch (scalar_ty.zigTypeTag(mod)) { | |
| 6635 | 6617 | .Int => if (use_operator) .{ .infix = " += " } else .{ |
| 6636 | 6618 | .builtin = .{ .operation = "addw", .info = .bits }, |
| 6637 | 6619 | }, |
| 6638 | 6620 | .Float => .{ .builtin = .{ .operation = "add" } }, |
| 6639 | 6621 | else => unreachable, |
| 6640 | 6622 | }, |
| 6641 | .Mul => switch (scalar_ty.zigTypeTag()) { | |
| 6623 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { | |
| 6642 | 6624 | .Int => if (use_operator) .{ .infix = " *= " } else .{ |
| 6643 | 6625 | .builtin = .{ .operation = "mulw", .info = .bits }, |
| 6644 | 6626 | }, |
| ... | ... | @@ -6663,43 +6645,42 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6663 | 6645 | try f.writeCValue(writer, accum, .Other); |
| 6664 | 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 | 6648 | try f.object.dg.renderValue(writer, scalar_ty, switch (reduce.operation) { |
| 6682 | .Or, .Xor, .Add => Value.zero, | |
| 6683 | .And => switch (scalar_ty.zigTypeTag()) { | |
| 6684 | .Bool => Value.one, | |
| 6685 | else => switch (scalar_ty.intInfo(target).signedness) { | |
| 6686 | .unsigned => try scalar_ty.maxInt(stack.get(), target), | |
| 6687 | .signed => Value.negative_one, | |
| 6649 | .Or, .Xor => switch (scalar_ty.zigTypeTag(mod)) { | |
| 6650 | .Bool => Value.false, | |
| 6651 | .Int => try mod.intValue(scalar_ty, 0), | |
| 6652 | else => unreachable, | |
| 6653 | }, | |
| 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()) { | |
| 6691 | .Bool => Value.one, | |
| 6692 | .Int => try scalar_ty.maxInt(stack.get(), target), | |
| 6693 | .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target), | |
| 6667 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { | |
| 6668 | .Int => try mod.intValue(scalar_ty, 1), | |
| 6669 | .Float => try mod.floatValue(scalar_ty, 1.0), | |
| 6694 | 6670 | else => unreachable, |
| 6695 | 6671 | }, |
| 6696 | .Max => switch (scalar_ty.zigTypeTag()) { | |
| 6697 | .Bool => Value.zero, | |
| 6698 | .Int => try scalar_ty.minInt(stack.get(), target), | |
| 6699 | .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target), | |
| 6672 | .Min => switch (scalar_ty.zigTypeTag(mod)) { | |
| 6673 | .Bool => Value.true, | |
| 6674 | .Int => try scalar_ty.maxIntScalar(mod, scalar_ty), | |
| 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 | 6682 | else => unreachable, |
| 6701 | 6683 | }, |
| 6702 | .Mul => Value.one, | |
| 6703 | 6684 | }, .Initializer); |
| 6704 | 6685 | try writer.writeAll(";\n"); |
| 6705 | 6686 | |
| ... | ... | @@ -6753,9 +6734,11 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6753 | 6734 | } |
| 6754 | 6735 | |
| 6755 | 6736 | fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6737 | const mod = f.object.dg.module; | |
| 6738 | const ip = &mod.intern_pool; | |
| 6756 | 6739 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 6757 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6758 | const len = @intCast(usize, inst_ty.arrayLen()); | |
| 6740 | const inst_ty = f.typeOfIndex(inst); | |
| 6741 | const len = @intCast(usize, inst_ty.arrayLen(mod)); | |
| 6759 | 6742 | const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); |
| 6760 | 6743 | const gpa = f.object.dg.gpa; |
| 6761 | 6744 | const resolved_elements = try gpa.alloc(CValue, elements.len); |
| ... | ... | @@ -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 | 6756 | const writer = f.object.writer(); |
| 6776 | 6757 | const local = try f.allocLocal(inst, inst_ty); |
| 6777 | switch (inst_ty.zigTypeTag()) { | |
| 6758 | switch (inst_ty.zigTypeTag(mod)) { | |
| 6778 | 6759 | .Array, .Vector => { |
| 6779 | const elem_ty = inst_ty.childType(); | |
| 6760 | const elem_ty = inst_ty.childType(mod); | |
| 6780 | 6761 | const a = try Assignment.init(f, elem_ty); |
| 6781 | 6762 | for (resolved_elements, 0..) |element, i| { |
| 6782 | 6763 | try a.restart(f, writer); |
| ... | ... | @@ -6786,7 +6767,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6786 | 6767 | try f.writeCValue(writer, element, .Other); |
| 6787 | 6768 | try a.end(f, writer); |
| 6788 | 6769 | } |
| 6789 | if (inst_ty.sentinel()) |sentinel| { | |
| 6770 | if (inst_ty.sentinel(mod)) |sentinel| { | |
| 6790 | 6771 | try a.restart(f, writer); |
| 6791 | 6772 | try f.writeCValue(writer, local, .Other); |
| 6792 | 6773 | try writer.print("[{d}]", .{resolved_elements.len}); |
| ... | ... | @@ -6795,17 +6776,17 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6795 | 6776 | try a.end(f, writer); |
| 6796 | 6777 | } |
| 6797 | 6778 | }, |
| 6798 | .Struct => switch (inst_ty.containerLayout()) { | |
| 6779 | .Struct => switch (inst_ty.containerLayout(mod)) { | |
| 6799 | 6780 | .Auto, .Extern => for (resolved_elements, 0..) |element, field_i| { |
| 6800 | if (inst_ty.structFieldIsComptime(field_i)) continue; | |
| 6801 | const field_ty = inst_ty.structFieldType(field_i); | |
| 6802 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 6781 | if (inst_ty.structFieldIsComptime(field_i, mod)) continue; | |
| 6782 | const field_ty = inst_ty.structFieldType(field_i, mod); | |
| 6783 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 6803 | 6784 | |
| 6804 | 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 | 6787 | .{ .field = field_i } |
| 6807 | 6788 | else |
| 6808 | .{ .identifier = inst_ty.structFieldName(field_i) }); | |
| 6789 | .{ .identifier = ip.stringToSlice(inst_ty.structFieldName(field_i, mod)) }); | |
| 6809 | 6790 | try a.assign(f, writer); |
| 6810 | 6791 | try f.writeCValue(writer, element, .Other); |
| 6811 | 6792 | try a.end(f, writer); |
| ... | ... | @@ -6813,22 +6794,17 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6813 | 6794 | .Packed => { |
| 6814 | 6795 | try f.writeCValue(writer, local, .Other); |
| 6815 | 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{ | |
| 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); | |
| 6799 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1)); | |
| 6823 | 6800 | |
| 6824 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; | |
| 6825 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | |
| 6801 | var bit_offset: u64 = 0; | |
| 6826 | 6802 | |
| 6827 | 6803 | var empty = true; |
| 6828 | 6804 | for (0..elements.len) |field_i| { |
| 6829 | if (inst_ty.structFieldIsComptime(field_i)) continue; | |
| 6830 | const field_ty = inst_ty.structFieldType(field_i); | |
| 6831 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 6805 | if (inst_ty.structFieldIsComptime(field_i, mod)) continue; | |
| 6806 | const field_ty = inst_ty.structFieldType(field_i, mod); | |
| 6807 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 6832 | 6808 | |
| 6833 | 6809 | if (!empty) { |
| 6834 | 6810 | try writer.writeAll("zig_or_"); |
| ... | ... | @@ -6839,9 +6815,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6839 | 6815 | } |
| 6840 | 6816 | empty = true; |
| 6841 | 6817 | for (resolved_elements, 0..) |element, field_i| { |
| 6842 | if (inst_ty.structFieldIsComptime(field_i)) continue; | |
| 6843 | const field_ty = inst_ty.structFieldType(field_i); | |
| 6844 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 6818 | if (inst_ty.structFieldIsComptime(field_i, mod)) continue; | |
| 6819 | const field_ty = inst_ty.structFieldType(field_i, mod); | |
| 6820 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 6845 | 6821 | |
| 6846 | 6822 | if (!empty) try writer.writeAll(", "); |
| 6847 | 6823 | // TODO: Skip this entire shift if val is 0? |
| ... | ... | @@ -6849,13 +6825,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6849 | 6825 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 6850 | 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 | 6829 | try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument); |
| 6854 | 6830 | } else { |
| 6855 | 6831 | try writer.writeByte('('); |
| 6856 | 6832 | try f.renderType(writer, inst_ty); |
| 6857 | 6833 | try writer.writeByte(')'); |
| 6858 | if (field_ty.isPtrAtRuntime()) { | |
| 6834 | if (field_ty.isPtrAtRuntime(mod)) { | |
| 6859 | 6835 | try writer.writeByte('('); |
| 6860 | 6836 | try f.renderType(writer, switch (int_info.signedness) { |
| 6861 | 6837 | .unsigned => Type.usize, |
| ... | ... | @@ -6867,12 +6843,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6867 | 6843 | } |
| 6868 | 6844 | |
| 6869 | 6845 | try writer.writeAll(", "); |
| 6846 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | |
| 6870 | 6847 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 6871 | 6848 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); |
| 6872 | 6849 | try writer.writeByte(')'); |
| 6873 | 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 | 6853 | empty = false; |
| 6877 | 6854 | } |
| 6878 | 6855 | |
| ... | ... | @@ -6886,14 +6863,15 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6886 | 6863 | } |
| 6887 | 6864 | |
| 6888 | 6865 | fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6866 | const mod = f.object.dg.module; | |
| 6867 | const ip = &mod.intern_pool; | |
| 6889 | 6868 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 6890 | 6869 | const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 6891 | 6870 | |
| 6892 | const union_ty = f.air.typeOfIndex(inst); | |
| 6893 | const target = f.object.dg.module.getTarget(); | |
| 6894 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | |
| 6871 | const union_ty = f.typeOfIndex(inst); | |
| 6872 | const union_obj = mod.typeToUnion(union_ty).?; | |
| 6895 | 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 | 6875 | const payload = try f.resolveInst(extra.init); |
| 6898 | 6876 | try reap(f, inst, &.{extra.init}); |
| 6899 | 6877 | |
| ... | ... | @@ -6907,19 +6885,14 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6907 | 6885 | return local; |
| 6908 | 6886 | } |
| 6909 | 6887 | |
| 6910 | const field: CValue = if (union_ty.unionTagTypeSafety()) |tag_ty| field: { | |
| 6911 | const layout = union_ty.unionGetLayout(target); | |
| 6888 | const field: CValue = if (union_ty.unionTagTypeSafety(mod)) |tag_ty| field: { | |
| 6889 | const layout = union_ty.unionGetLayout(mod); | |
| 6912 | 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 = .{ | |
| 6916 | .base = .{ .tag = .enum_field_index }, | |
| 6917 | .data = @intCast(u32, field_index), | |
| 6918 | }; | |
| 6919 | const tag_val = Value.initPayload(&tag_pl.base); | |
| 6893 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); | |
| 6920 | 6894 | |
| 6921 | var int_pl: Value.Payload.U64 = undefined; | |
| 6922 | const int_val = tag_val.enumToInt(tag_ty, &int_pl); | |
| 6895 | const int_val = try tag_val.enumToInt(tag_ty, mod); | |
| 6923 | 6896 | |
| 6924 | 6897 | const a = try Assignment.start(f, writer, tag_ty); |
| 6925 | 6898 | try f.writeCValueMember(writer, local, .{ .identifier = "tag" }); |
| ... | ... | @@ -6927,8 +6900,8 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6927 | 6900 | try writer.print("{}", .{try f.fmtIntLiteral(tag_ty, int_val)}); |
| 6928 | 6901 | try a.end(f, writer); |
| 6929 | 6902 | } |
| 6930 | break :field .{ .payload_identifier = field_name }; | |
| 6931 | } else .{ .identifier = field_name }; | |
| 6903 | break :field .{ .payload_identifier = ip.stringToSlice(field_name) }; | |
| 6904 | } else .{ .identifier = ip.stringToSlice(field_name) }; | |
| 6932 | 6905 | |
| 6933 | 6906 | const a = try Assignment.start(f, writer, payload_ty); |
| 6934 | 6907 | try f.writeCValueMember(writer, local, field); |
| ... | ... | @@ -6963,7 +6936,7 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6963 | 6936 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 6964 | 6937 | |
| 6965 | 6938 | const writer = f.object.writer(); |
| 6966 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6939 | const inst_ty = f.typeOfIndex(inst); | |
| 6967 | 6940 | const local = try f.allocLocal(inst, inst_ty); |
| 6968 | 6941 | try f.writeCValue(writer, local, .Other); |
| 6969 | 6942 | |
| ... | ... | @@ -6977,7 +6950,7 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6977 | 6950 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 6978 | 6951 | |
| 6979 | 6952 | const writer = f.object.writer(); |
| 6980 | const inst_ty = f.air.typeOfIndex(inst); | |
| 6953 | const inst_ty = f.typeOfIndex(inst); | |
| 6981 | 6954 | const operand = try f.resolveInst(pl_op.operand); |
| 6982 | 6955 | try reap(f, inst, &.{pl_op.operand}); |
| 6983 | 6956 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -6991,13 +6964,14 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6991 | 6964 | } |
| 6992 | 6965 | |
| 6993 | 6966 | fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6967 | const mod = f.object.dg.module; | |
| 6994 | 6968 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 6995 | 6969 | |
| 6996 | 6970 | const operand = try f.resolveInst(un_op); |
| 6997 | 6971 | try reap(f, inst, &.{un_op}); |
| 6998 | 6972 | |
| 6999 | const operand_ty = f.air.typeOf(un_op); | |
| 7000 | const scalar_ty = operand_ty.scalarType(); | |
| 6973 | const operand_ty = f.typeOf(un_op); | |
| 6974 | const scalar_ty = operand_ty.scalarType(mod); | |
| 7001 | 6975 | |
| 7002 | 6976 | const writer = f.object.writer(); |
| 7003 | 6977 | const local = try f.allocLocal(inst, operand_ty); |
| ... | ... | @@ -7016,13 +6990,14 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7016 | 6990 | } |
| 7017 | 6991 | |
| 7018 | 6992 | fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 6993 | const mod = f.object.dg.module; | |
| 7019 | 6994 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 7020 | 6995 | |
| 7021 | 6996 | const operand = try f.resolveInst(un_op); |
| 7022 | 6997 | try reap(f, inst, &.{un_op}); |
| 7023 | 6998 | |
| 7024 | const inst_ty = f.air.typeOfIndex(inst); | |
| 7025 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 6999 | const inst_ty = f.typeOfIndex(inst); | |
| 7000 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 7026 | 7001 | |
| 7027 | 7002 | const writer = f.object.writer(); |
| 7028 | 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 | 7018 | } |
| 7044 | 7019 | |
| 7045 | 7020 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 7021 | const mod = f.object.dg.module; | |
| 7046 | 7022 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 7047 | 7023 | |
| 7048 | 7024 | const lhs = try f.resolveInst(bin_op.lhs); |
| 7049 | 7025 | const rhs = try f.resolveInst(bin_op.rhs); |
| 7050 | 7026 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 7051 | 7027 | |
| 7052 | const inst_ty = f.air.typeOfIndex(inst); | |
| 7053 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 7028 | const inst_ty = f.typeOfIndex(inst); | |
| 7029 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 7054 | 7030 | |
| 7055 | 7031 | const writer = f.object.writer(); |
| 7056 | 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 | 7050 | } |
| 7075 | 7051 | |
| 7076 | 7052 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7053 | const mod = f.object.dg.module; | |
| 7077 | 7054 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 7078 | 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 | 7059 | const addend = try f.resolveInst(pl_op.operand); |
| 7083 | 7060 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand }); |
| 7084 | 7061 | |
| 7085 | const inst_ty = f.air.typeOfIndex(inst); | |
| 7086 | const inst_scalar_ty = inst_ty.scalarType(); | |
| 7062 | const inst_ty = f.typeOfIndex(inst); | |
| 7063 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 7087 | 7064 | |
| 7088 | 7065 | const writer = f.object.writer(); |
| 7089 | 7066 | const local = try f.allocLocal(inst, inst_ty); |
| ... | ... | @@ -7108,7 +7085,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7108 | 7085 | } |
| 7109 | 7086 | |
| 7110 | 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 | 7089 | const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete); |
| 7113 | 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 | 7104 | fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7128 | 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 | 7108 | const va_list = try f.resolveInst(ty_op.operand); |
| 7132 | 7109 | try reap(f, inst, &.{ty_op.operand}); |
| 7133 | 7110 | |
| ... | ... | @@ -7158,7 +7135,7 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7158 | 7135 | fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7159 | 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 | 7139 | const va_list = try f.resolveInst(ty_op.operand); |
| 7163 | 7140 | try reap(f, inst, &.{ty_op.operand}); |
| 7164 | 7141 | |
| ... | ... | @@ -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 { | |
| 7283 | return if (ty.isInt()) switch (ty.intInfo(target).bits) { | |
| 7259 | fn compilerRtAbbrev(ty: Type, mod: *Module) []const u8 { | |
| 7260 | const target = mod.getTarget(); | |
| 7261 | return if (ty.isInt(mod)) switch (ty.intInfo(mod).bits) { | |
| 7284 | 7262 | 1...32 => "si", |
| 7285 | 7263 | 33...64 => "di", |
| 7286 | 7264 | 65...128 => "ti", |
| ... | ... | @@ -7407,7 +7385,7 @@ fn undefPattern(comptime IntType: type) IntType { |
| 7407 | 7385 | |
| 7408 | 7386 | const FormatIntLiteralContext = struct { |
| 7409 | 7387 | dg: *DeclGen, |
| 7410 | int_info: std.builtin.Type.Int, | |
| 7388 | int_info: InternPool.Key.IntType, | |
| 7411 | 7389 | kind: CType.Kind, |
| 7412 | 7390 | cty: CType, |
| 7413 | 7391 | val: Value, |
| ... | ... | @@ -7418,7 +7396,8 @@ fn formatIntLiteral( |
| 7418 | 7396 | options: std.fmt.FormatOptions, |
| 7419 | 7397 | writer: anytype, |
| 7420 | 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 | 7402 | const ExpectedContents = struct { |
| 7424 | 7403 | const base = 10; |
| ... | ... | @@ -7438,7 +7417,7 @@ fn formatIntLiteral( |
| 7438 | 7417 | defer allocator.free(undef_limbs); |
| 7439 | 7418 | |
| 7440 | 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 | 7421 | undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits)); |
| 7443 | 7422 | @memset(undef_limbs, undefPattern(BigIntLimb)); |
| 7444 | 7423 | |
| ... | ... | @@ -7449,7 +7428,7 @@ fn formatIntLiteral( |
| 7449 | 7428 | }; |
| 7450 | 7429 | undef_int.truncate(undef_int.toConst(), data.int_info.signedness, data.int_info.bits); |
| 7451 | 7430 | break :blk undef_int.toConst(); |
| 7452 | } else data.val.toBigInt(&int_buf, target); | |
| 7431 | } else data.val.toBigInt(&int_buf, mod); | |
| 7453 | 7432 | assert(int.fitsInTwosComp(data.int_info.signedness, data.int_info.bits)); |
| 7454 | 7433 | |
| 7455 | 7434 | const c_bits = @intCast(usize, data.cty.byteSize(data.dg.ctypes.set, target) * 8); |
| ... | ... | @@ -7576,10 +7555,6 @@ fn formatIntLiteral( |
| 7576 | 7555 | c_limb_int_info.signedness = .unsigned; |
| 7577 | 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 | 7559 | if (limb_offset > 0) try writer.writeAll(", "); |
| 7585 | 7560 | try formatIntLiteral(.{ |
| ... | ... | @@ -7587,7 +7562,7 @@ fn formatIntLiteral( |
| 7587 | 7562 | .int_info = c_limb_int_info, |
| 7588 | 7563 | .kind = data.kind, |
| 7589 | 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 | 7566 | }, fmt, options, writer); |
| 7592 | 7567 | } |
| 7593 | 7568 | } |
| ... | ... | @@ -7684,20 +7659,21 @@ const Vectorize = struct { |
| 7684 | 7659 | index: CValue = .none, |
| 7685 | 7660 | |
| 7686 | 7661 | pub fn start(f: *Function, inst: Air.Inst.Index, writer: anytype, ty: Type) !Vectorize { |
| 7687 | return if (ty.zigTypeTag() == .Vector) index: { | |
| 7688 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = ty.vectorLen() }; | |
| 7662 | const mod = f.object.dg.module; | |
| 7663 | return if (ty.zigTypeTag(mod) == .Vector) index: { | |
| 7664 | const len_val = try mod.intValue(Type.usize, ty.vectorLen(mod)); | |
| 7689 | 7665 | |
| 7690 | 7666 | const local = try f.allocLocal(inst, Type.usize); |
| 7691 | 7667 | |
| 7692 | 7668 | try writer.writeAll("for ("); |
| 7693 | 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 | 7671 | try f.writeCValue(writer, local, .Other); |
| 7696 | 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 | 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 | 7677 | f.object.indent_writer.pushIndent(); |
| 7702 | 7678 | |
| 7703 | 7679 | break :index .{ .index = local }; |
| ... | ... | @@ -7721,34 +7697,30 @@ const Vectorize = struct { |
| 7721 | 7697 | } |
| 7722 | 7698 | }; |
| 7723 | 7699 | |
| 7724 | const LowerFnRetTyBuffer = struct { | |
| 7725 | names: [1][]const u8, | |
| 7726 | types: [1]Type, | |
| 7727 | values: [1]Value, | |
| 7728 | payload: Type.Payload.AnonStruct, | |
| 7729 | }; | |
| 7730 | fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type { | |
| 7731 | if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn); | |
| 7732 | ||
| 7733 | if (lowersToArray(ret_ty, target)) { | |
| 7734 | buffer.names = [1][]const u8{"array"}; | |
| 7735 | buffer.types = [1]Type{ret_ty}; | |
| 7736 | buffer.values = [1]Value{Value.initTag(.unreachable_value)}; | |
| 7737 | buffer.payload = .{ .data = .{ | |
| 7738 | .names = &buffer.names, | |
| 7739 | .types = &buffer.types, | |
| 7740 | .values = &buffer.values, | |
| 7741 | } }; | |
| 7742 | return Type.initPayload(&buffer.payload.base); | |
| 7700 | fn lowerFnRetTy(ret_ty: Type, mod: *Module) !Type { | |
| 7701 | if (ret_ty.ip_index == .noreturn_type) return Type.noreturn; | |
| 7702 | ||
| 7703 | if (lowersToArray(ret_ty, mod)) { | |
| 7704 | const names = [1]InternPool.NullTerminatedString{ | |
| 7705 | try mod.intern_pool.getOrPutString(mod.gpa, "array"), | |
| 7706 | }; | |
| 7707 | const types = [1]InternPool.Index{ret_ty.ip_index}; | |
| 7708 | const values = [1]InternPool.Index{.none}; | |
| 7709 | const interned = try mod.intern(.{ .anon_struct_type = .{ | |
| 7710 | .names = &names, | |
| 7711 | .types = &types, | |
| 7712 | .values = &values, | |
| 7713 | } }); | |
| 7714 | return interned.toType(); | |
| 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 { | |
| 7749 | return switch (ty.zigTypeTag()) { | |
| 7720 | fn lowersToArray(ty: Type, mod: *Module) bool { | |
| 7721 | return switch (ty.zigTypeTag(mod)) { | |
| 7750 | 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 | 7737 | |
| 7766 | 7738 | fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void { |
| 7767 | 7739 | const ref_inst = Air.refToIndex(ref) orelse return; |
| 7740 | assert(f.air.instructions.items(.tag)[ref_inst] != .interned); | |
| 7768 | 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 | 7742 | const local_index = switch (c_value) { |
| 7771 | 7743 | .local, .new_local => |l| l, |
| 7772 | 7744 | else => return, |
src/codegen/c/type.zig+165-167| ... | ... | @@ -292,19 +292,19 @@ pub const CType = extern union { |
| 292 | 292 | .abi = std.math.log2_int(u32, abi_alignment), |
| 293 | 293 | }; |
| 294 | 294 | } |
| 295 | pub fn abiAlign(ty: Type, target: Target) AlignAs { | |
| 296 | const abi_align = ty.abiAlignment(target); | |
| 295 | pub fn abiAlign(ty: Type, mod: *Module) AlignAs { | |
| 296 | const abi_align = ty.abiAlignment(mod); | |
| 297 | 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 | 300 | return init( |
| 301 | struct_ty.structFieldAlign(field_i, target), | |
| 302 | struct_ty.structFieldType(field_i).abiAlignment(target), | |
| 301 | struct_ty.structFieldAlign(field_i, mod), | |
| 302 | struct_ty.structFieldType(field_i, mod).abiAlignment(mod), | |
| 303 | 303 | ); |
| 304 | 304 | } |
| 305 | pub fn unionPayloadAlign(union_ty: Type, target: Target) AlignAs { | |
| 306 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | |
| 307 | const union_payload_align = union_obj.abiAlignment(target, false); | |
| 305 | pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs { | |
| 306 | const union_obj = mod.typeToUnion(union_ty).?; | |
| 307 | const union_payload_align = union_obj.abiAlignment(mod, false); | |
| 308 | 308 | return init(union_payload_align, union_payload_align); |
| 309 | 309 | } |
| 310 | 310 | |
| ... | ... | @@ -344,8 +344,8 @@ pub const CType = extern union { |
| 344 | 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 { | |
| 348 | const lookup = Convert.Lookup{ .imm = .{ .set = &self, .target = target } }; | |
| 347 | pub fn typeToIndex(self: Set, ty: Type, mod: *Module, kind: Kind) ?Index { | |
| 348 | const lookup = Convert.Lookup{ .imm = .{ .set = &self, .mod = mod } }; | |
| 349 | 349 | |
| 350 | 350 | var convert: Convert = undefined; |
| 351 | 351 | convert.initType(ty, kind, lookup) catch unreachable; |
| ... | ... | @@ -405,7 +405,7 @@ pub const CType = extern union { |
| 405 | 405 | ); |
| 406 | 406 | if (!gop.found_existing) { |
| 407 | 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 | 410 | if (std.debug.runtime_safety) { |
| 411 | 411 | const adapter = TypeAdapter64{ |
| ... | ... | @@ -1236,10 +1236,10 @@ pub const CType = extern union { |
| 1236 | 1236 | } |
| 1237 | 1237 | |
| 1238 | 1238 | pub const Lookup = union(enum) { |
| 1239 | fail: Target, | |
| 1239 | fail: *Module, | |
| 1240 | 1240 | imm: struct { |
| 1241 | 1241 | set: *const Store.Set, |
| 1242 | target: Target, | |
| 1242 | mod: *Module, | |
| 1243 | 1243 | }, |
| 1244 | 1244 | mut: struct { |
| 1245 | 1245 | promoted: *Store.Promoted, |
| ... | ... | @@ -1254,10 +1254,14 @@ pub const CType = extern union { |
| 1254 | 1254 | } |
| 1255 | 1255 | |
| 1256 | 1256 | pub fn getTarget(self: @This()) Target { |
| 1257 | return self.getModule().getTarget(); | |
| 1258 | } | |
| 1259 | ||
| 1260 | pub fn getModule(self: @This()) *Module { | |
| 1257 | 1261 | return switch (self) { |
| 1258 | .fail => |target| target, | |
| 1259 | .imm => |imm| imm.target, | |
| 1260 | .mut => |mut| mut.mod.getTarget(), | |
| 1262 | .fail => |mod| mod, | |
| 1263 | .imm => |imm| imm.mod, | |
| 1264 | .mut => |mut| mut.mod, | |
| 1261 | 1265 | }; |
| 1262 | 1266 | } |
| 1263 | 1267 | |
| ... | ... | @@ -1272,7 +1276,7 @@ pub const CType = extern union { |
| 1272 | 1276 | pub fn typeToIndex(self: @This(), ty: Type, kind: Kind) !?Index { |
| 1273 | 1277 | return switch (self) { |
| 1274 | 1278 | .fail => null, |
| 1275 | .imm => |imm| imm.set.typeToIndex(ty, imm.target, kind), | |
| 1279 | .imm => |imm| imm.set.typeToIndex(ty, imm.mod, kind), | |
| 1276 | 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 | 1288 | pub fn freeze(self: @This()) @This() { |
| 1285 | 1289 | return switch (self) { |
| 1286 | 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 | 1342 | self.storage.anon.fields[0] = .{ |
| 1339 | 1343 | .name = "array", |
| 1340 | 1344 | .type = array_idx, |
| 1341 | .alignas = AlignAs.abiAlign(ty, lookup.getTarget()), | |
| 1345 | .alignas = AlignAs.abiAlign(ty, lookup.getModule()), | |
| 1342 | 1346 | }; |
| 1343 | 1347 | self.initAnon(kind, fwd_idx, 1); |
| 1344 | 1348 | } else self.init(switch (kind) { |
| ... | ... | @@ -1350,30 +1354,30 @@ pub const CType = extern union { |
| 1350 | 1354 | } |
| 1351 | 1355 | |
| 1352 | 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 | 1359 | self.* = undefined; |
| 1356 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime()) | |
| 1360 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) | |
| 1357 | 1361 | self.init(.void) |
| 1358 | else if (ty.isAbiInt()) switch (ty.tag()) { | |
| 1359 | .usize => self.init(.uintptr_t), | |
| 1360 | .isize => self.init(.intptr_t), | |
| 1361 | .c_char => self.init(.char), | |
| 1362 | .c_short => self.init(.short), | |
| 1363 | .c_ushort => self.init(.@"unsigned short"), | |
| 1364 | .c_int => self.init(.int), | |
| 1365 | .c_uint => self.init(.@"unsigned int"), | |
| 1366 | .c_long => self.init(.long), | |
| 1367 | .c_ulong => self.init(.@"unsigned long"), | |
| 1368 | .c_longlong => self.init(.@"long long"), | |
| 1369 | .c_ulonglong => self.init(.@"unsigned long long"), | |
| 1370 | else => switch (tagFromIntInfo(ty.intInfo(target))) { | |
| 1362 | else if (ty.isAbiInt(mod)) switch (ty.ip_index) { | |
| 1363 | .usize_type => self.init(.uintptr_t), | |
| 1364 | .isize_type => self.init(.intptr_t), | |
| 1365 | .c_char_type => self.init(.char), | |
| 1366 | .c_short_type => self.init(.short), | |
| 1367 | .c_ushort_type => self.init(.@"unsigned short"), | |
| 1368 | .c_int_type => self.init(.int), | |
| 1369 | .c_uint_type => self.init(.@"unsigned int"), | |
| 1370 | .c_long_type => self.init(.long), | |
| 1371 | .c_ulong_type => self.init(.@"unsigned long"), | |
| 1372 | .c_longlong_type => self.init(.@"long long"), | |
| 1373 | .c_ulonglong_type => self.init(.@"unsigned long long"), | |
| 1374 | else => switch (tagFromIntInfo(ty.intInfo(mod))) { | |
| 1371 | 1375 | .void => unreachable, |
| 1372 | 1376 | else => |t| self.init(t), |
| 1373 | 1377 | .array => switch (kind) { |
| 1374 | 1378 | .forward, .complete, .global => { |
| 1375 | const abi_size = ty.abiSize(target); | |
| 1376 | const abi_align = ty.abiAlignment(target); | |
| 1379 | const abi_size = ty.abiSize(mod); | |
| 1380 | const abi_align = ty.abiAlignment(mod); | |
| 1377 | 1381 | self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{ |
| 1378 | 1382 | .len = @divExact(abi_size, abi_align), |
| 1379 | 1383 | .elem_type = tagFromIntInfo(.{ |
| ... | ... | @@ -1389,7 +1393,7 @@ pub const CType = extern union { |
| 1389 | 1393 | .payload => unreachable, |
| 1390 | 1394 | }, |
| 1391 | 1395 | }, |
| 1392 | } else switch (ty.zigTypeTag()) { | |
| 1396 | } else switch (ty.zigTypeTag(mod)) { | |
| 1393 | 1397 | .Frame => unreachable, |
| 1394 | 1398 | .AnyFrame => unreachable, |
| 1395 | 1399 | |
| ... | ... | @@ -1408,18 +1412,18 @@ pub const CType = extern union { |
| 1408 | 1412 | |
| 1409 | 1413 | .Bool => self.init(.bool), |
| 1410 | 1414 | |
| 1411 | .Float => self.init(switch (ty.tag()) { | |
| 1412 | .f16 => .zig_f16, | |
| 1413 | .f32 => .zig_f32, | |
| 1414 | .f64 => .zig_f64, | |
| 1415 | .f80 => .zig_f80, | |
| 1416 | .f128 => .zig_f128, | |
| 1417 | .c_longdouble => .zig_c_longdouble, | |
| 1415 | .Float => self.init(switch (ty.ip_index) { | |
| 1416 | .f16_type => .zig_f16, | |
| 1417 | .f32_type => .zig_f32, | |
| 1418 | .f64_type => .zig_f64, | |
| 1419 | .f80_type => .zig_f80, | |
| 1420 | .f128_type => .zig_f128, | |
| 1421 | .c_longdouble_type => .zig_c_longdouble, | |
| 1418 | 1422 | else => unreachable, |
| 1419 | 1423 | }), |
| 1420 | 1424 | |
| 1421 | 1425 | .Pointer => { |
| 1422 | const info = ty.ptrInfo().data; | |
| 1426 | const info = ty.ptrInfo(mod); | |
| 1423 | 1427 | switch (info.size) { |
| 1424 | 1428 | .Slice => { |
| 1425 | 1429 | if (switch (kind) { |
| ... | ... | @@ -1427,19 +1431,18 @@ pub const CType = extern union { |
| 1427 | 1431 | .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward), |
| 1428 | 1432 | .payload => unreachable, |
| 1429 | 1433 | }) |fwd_idx| { |
| 1430 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 1431 | const ptr_ty = ty.slicePtrFieldType(&buf); | |
| 1434 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 1432 | 1435 | if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| { |
| 1433 | 1436 | self.storage = .{ .anon = undefined }; |
| 1434 | 1437 | self.storage.anon.fields[0] = .{ |
| 1435 | 1438 | .name = "ptr", |
| 1436 | 1439 | .type = ptr_idx, |
| 1437 | .alignas = AlignAs.abiAlign(ptr_ty, target), | |
| 1440 | .alignas = AlignAs.abiAlign(ptr_ty, mod), | |
| 1438 | 1441 | }; |
| 1439 | 1442 | self.storage.anon.fields[1] = .{ |
| 1440 | 1443 | .name = "len", |
| 1441 | 1444 | .type = Tag.uintptr_t.toIndex(), |
| 1442 | .alignas = AlignAs.abiAlign(Type.usize, target), | |
| 1445 | .alignas = AlignAs.abiAlign(Type.usize, mod), | |
| 1443 | 1446 | }; |
| 1444 | 1447 | self.initAnon(kind, fwd_idx, 2); |
| 1445 | 1448 | } else self.init(switch (kind) { |
| ... | ... | @@ -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 | 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 | 1470 | else |
| 1472 | 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 | 1474 | Tag.char.toIndex() |
| 1476 | 1475 | else |
| 1477 | 1476 | try lookup.typeToIndex(pointee_ty, .forward)) |child_idx| |
| ... | ... | @@ -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) { | |
| 1490 | if (ty.castTag(.@"struct")) |struct_obj| { | |
| 1491 | try self.initType(struct_obj.data.backing_int_ty, kind, lookup); | |
| 1488 | .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) { | |
| 1489 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 1490 | try self.initType(struct_obj.backing_int_ty, kind, lookup); | |
| 1492 | 1491 | } else { |
| 1493 | var buf: Type.Payload.Bits = .{ | |
| 1494 | .base = .{ .tag = .int_unsigned }, | |
| 1495 | .data = @intCast(u16, ty.bitSize(target)), | |
| 1496 | }; | |
| 1497 | try self.initType(Type.initPayload(&buf.base), kind, lookup); | |
| 1492 | const bits = @intCast(u16, ty.bitSize(mod)); | |
| 1493 | const int_ty = try mod.intType(.unsigned, bits); | |
| 1494 | try self.initType(int_ty, kind, lookup); | |
| 1498 | 1495 | } |
| 1499 | } else if (ty.isTupleOrAnonStruct()) { | |
| 1496 | } else if (ty.isTupleOrAnonStruct(mod)) { | |
| 1500 | 1497 | if (lookup.isMutable()) { |
| 1501 | 1498 | for (0..switch (zig_ty_tag) { |
| 1502 | .Struct => ty.structFieldCount(), | |
| 1503 | .Union => ty.unionFields().count(), | |
| 1499 | .Struct => ty.structFieldCount(mod), | |
| 1500 | .Union => ty.unionFields(mod).count(), | |
| 1504 | 1501 | else => unreachable, |
| 1505 | 1502 | }) |field_i| { |
| 1506 | const field_ty = ty.structFieldType(field_i); | |
| 1507 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | |
| 1508 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1503 | const field_ty = ty.structFieldType(field_i, mod); | |
| 1504 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or | |
| 1505 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1509 | 1506 | _ = try lookup.typeToIndex(field_ty, switch (kind) { |
| 1510 | 1507 | .forward, .forward_parameter => .forward, |
| 1511 | 1508 | .complete, .parameter => .complete, |
| ... | ... | @@ -1533,14 +1530,14 @@ pub const CType = extern union { |
| 1533 | 1530 | .payload => unreachable, |
| 1534 | 1531 | }); |
| 1535 | 1532 | } else { |
| 1536 | const tag_ty = ty.unionTagTypeSafety(); | |
| 1533 | const tag_ty = ty.unionTagTypeSafety(mod); | |
| 1537 | 1534 | const is_tagged_union_wrapper = kind != .payload and tag_ty != null; |
| 1538 | 1535 | const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper; |
| 1539 | 1536 | switch (kind) { |
| 1540 | 1537 | .forward, .forward_parameter => { |
| 1541 | 1538 | self.storage = .{ .fwd = .{ |
| 1542 | 1539 | .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union }, |
| 1543 | .data = ty.getOwnerDecl(), | |
| 1540 | .data = ty.getOwnerDecl(mod), | |
| 1544 | 1541 | } }; |
| 1545 | 1542 | self.value = .{ .cty = initPayload(&self.storage.fwd) }; |
| 1546 | 1543 | }, |
| ... | ... | @@ -1555,7 +1552,7 @@ pub const CType = extern union { |
| 1555 | 1552 | self.storage.anon.fields[field_count] = .{ |
| 1556 | 1553 | .name = "payload", |
| 1557 | 1554 | .type = payload_idx.?, |
| 1558 | .alignas = AlignAs.unionPayloadAlign(ty, target), | |
| 1555 | .alignas = AlignAs.unionPayloadAlign(ty, mod), | |
| 1559 | 1556 | }; |
| 1560 | 1557 | field_count += 1; |
| 1561 | 1558 | } |
| ... | ... | @@ -1563,7 +1560,7 @@ pub const CType = extern union { |
| 1563 | 1560 | self.storage.anon.fields[field_count] = .{ |
| 1564 | 1561 | .name = "tag", |
| 1565 | 1562 | .type = tag_idx.?, |
| 1566 | .alignas = AlignAs.abiAlign(tag_ty.?, target), | |
| 1563 | .alignas = AlignAs.abiAlign(tag_ty.?, mod), | |
| 1567 | 1564 | }; |
| 1568 | 1565 | field_count += 1; |
| 1569 | 1566 | } |
| ... | ... | @@ -1576,19 +1573,19 @@ pub const CType = extern union { |
| 1576 | 1573 | } }; |
| 1577 | 1574 | self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) }; |
| 1578 | 1575 | } else self.init(.@"struct"); |
| 1579 | } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes()) { | |
| 1576 | } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes(mod)) { | |
| 1580 | 1577 | self.init(.void); |
| 1581 | 1578 | } else { |
| 1582 | 1579 | var is_packed = false; |
| 1583 | 1580 | for (0..switch (zig_ty_tag) { |
| 1584 | .Struct => ty.structFieldCount(), | |
| 1585 | .Union => ty.unionFields().count(), | |
| 1581 | .Struct => ty.structFieldCount(mod), | |
| 1582 | .Union => ty.unionFields(mod).count(), | |
| 1586 | 1583 | else => unreachable, |
| 1587 | 1584 | }) |field_i| { |
| 1588 | const field_ty = ty.structFieldType(field_i); | |
| 1589 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1585 | const field_ty = ty.structFieldType(field_i, mod); | |
| 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 | 1589 | if (field_align.@"align" < field_align.abi) { |
| 1593 | 1590 | is_packed = true; |
| 1594 | 1591 | if (!lookup.isMutable()) break; |
| ... | ... | @@ -1627,9 +1624,9 @@ pub const CType = extern union { |
| 1627 | 1624 | .Vector => .vector, |
| 1628 | 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 | 1628 | self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{ |
| 1632 | .len = ty.arrayLenIncludingSentinel(), | |
| 1629 | .len = ty.arrayLenIncludingSentinel(mod), | |
| 1633 | 1630 | .elem_type = child_idx, |
| 1634 | 1631 | } } }; |
| 1635 | 1632 | self.value = .{ .cty = initPayload(&self.storage.seq) }; |
| ... | ... | @@ -1641,10 +1638,9 @@ pub const CType = extern union { |
| 1641 | 1638 | }, |
| 1642 | 1639 | |
| 1643 | 1640 | .Optional => { |
| 1644 | var buf: Type.Payload.ElemType = undefined; | |
| 1645 | const payload_ty = ty.optionalChild(&buf); | |
| 1646 | if (payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1647 | if (ty.optionalReprIsPayload()) { | |
| 1641 | const payload_ty = ty.optionalChild(mod); | |
| 1642 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1643 | if (ty.optionalReprIsPayload(mod)) { | |
| 1648 | 1644 | try self.initType(payload_ty, kind, lookup); |
| 1649 | 1645 | } else if (switch (kind) { |
| 1650 | 1646 | .forward, .forward_parameter => @as(Index, undefined), |
| ... | ... | @@ -1661,12 +1657,12 @@ pub const CType = extern union { |
| 1661 | 1657 | self.storage.anon.fields[0] = .{ |
| 1662 | 1658 | .name = "payload", |
| 1663 | 1659 | .type = payload_idx, |
| 1664 | .alignas = AlignAs.abiAlign(payload_ty, target), | |
| 1660 | .alignas = AlignAs.abiAlign(payload_ty, mod), | |
| 1665 | 1661 | }; |
| 1666 | 1662 | self.storage.anon.fields[1] = .{ |
| 1667 | 1663 | .name = "is_null", |
| 1668 | 1664 | .type = Tag.bool.toIndex(), |
| 1669 | .alignas = AlignAs.abiAlign(Type.bool, target), | |
| 1665 | .alignas = AlignAs.abiAlign(Type.bool, mod), | |
| 1670 | 1666 | }; |
| 1671 | 1667 | self.initAnon(kind, fwd_idx, 2); |
| 1672 | 1668 | } else self.init(switch (kind) { |
| ... | ... | @@ -1684,14 +1680,14 @@ pub const CType = extern union { |
| 1684 | 1680 | .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward), |
| 1685 | 1681 | .payload => unreachable, |
| 1686 | 1682 | }) |fwd_idx| { |
| 1687 | const payload_ty = ty.errorUnionPayload(); | |
| 1683 | const payload_ty = ty.errorUnionPayload(mod); | |
| 1688 | 1684 | if (try lookup.typeToIndex(payload_ty, switch (kind) { |
| 1689 | 1685 | .forward, .forward_parameter => .forward, |
| 1690 | 1686 | .complete, .parameter => .complete, |
| 1691 | 1687 | .global => .global, |
| 1692 | 1688 | .payload => unreachable, |
| 1693 | 1689 | })) |payload_idx| { |
| 1694 | const error_ty = ty.errorUnionSet(); | |
| 1690 | const error_ty = ty.errorUnionSet(mod); | |
| 1695 | 1691 | if (payload_idx == Tag.void.toIndex()) { |
| 1696 | 1692 | try self.initType(error_ty, kind, lookup); |
| 1697 | 1693 | } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| { |
| ... | ... | @@ -1699,12 +1695,12 @@ pub const CType = extern union { |
| 1699 | 1695 | self.storage.anon.fields[0] = .{ |
| 1700 | 1696 | .name = "payload", |
| 1701 | 1697 | .type = payload_idx, |
| 1702 | .alignas = AlignAs.abiAlign(payload_ty, target), | |
| 1698 | .alignas = AlignAs.abiAlign(payload_ty, mod), | |
| 1703 | 1699 | }; |
| 1704 | 1700 | self.storage.anon.fields[1] = .{ |
| 1705 | 1701 | .name = "error", |
| 1706 | 1702 | .type = error_idx, |
| 1707 | .alignas = AlignAs.abiAlign(error_ty, target), | |
| 1703 | .alignas = AlignAs.abiAlign(error_ty, mod), | |
| 1708 | 1704 | }; |
| 1709 | 1705 | self.initAnon(kind, fwd_idx, 2); |
| 1710 | 1706 | } else self.init(switch (kind) { |
| ... | ... | @@ -1723,7 +1719,7 @@ pub const CType = extern union { |
| 1723 | 1719 | .Opaque => self.init(.void), |
| 1724 | 1720 | |
| 1725 | 1721 | .Fn => { |
| 1726 | const info = ty.fnInfo(); | |
| 1722 | const info = mod.typeToFunc(ty).?; | |
| 1727 | 1723 | if (!info.is_generic) { |
| 1728 | 1724 | if (lookup.isMutable()) { |
| 1729 | 1725 | const param_kind: Kind = switch (kind) { |
| ... | ... | @@ -1731,10 +1727,10 @@ pub const CType = extern union { |
| 1731 | 1727 | .complete, .parameter, .global => .parameter, |
| 1732 | 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 | 1731 | for (info.param_types) |param_type| { |
| 1736 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1737 | _ = try lookup.typeToIndex(param_type, param_kind); | |
| 1732 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1733 | _ = try lookup.typeToIndex(param_type.toType(), param_kind); | |
| 1738 | 1734 | } |
| 1739 | 1735 | } |
| 1740 | 1736 | self.init(if (info.is_var_args) .varargs_function else .function); |
| ... | ... | @@ -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 | 1900 | var convert: Convert = undefined; |
| 1905 | try convert.initType(ty, kind, .{ .imm = .{ .set = &store.set, .target = target } }); | |
| 1906 | return createFromConvert(store, ty, target, kind, &convert); | |
| 1901 | try convert.initType(ty, kind, .{ .imm = .{ .set = &store.set, .mod = mod } }); | |
| 1902 | return createFromConvert(store, ty, mod, kind, &convert); | |
| 1907 | 1903 | } |
| 1908 | 1904 | |
| 1909 | 1905 | fn createFromConvert( |
| 1910 | 1906 | store: *Store.Promoted, |
| 1911 | 1907 | ty: Type, |
| 1912 | target: Target, | |
| 1908 | mod: *Module, | |
| 1913 | 1909 | kind: Kind, |
| 1914 | 1910 | convert: Convert, |
| 1915 | 1911 | ) !CType { |
| ... | ... | @@ -1930,44 +1926,44 @@ pub const CType = extern union { |
| 1930 | 1926 | .packed_struct, |
| 1931 | 1927 | .packed_union, |
| 1932 | 1928 | => { |
| 1933 | const zig_ty_tag = ty.zigTypeTag(); | |
| 1929 | const zig_ty_tag = ty.zigTypeTag(mod); | |
| 1934 | 1930 | const fields_len = switch (zig_ty_tag) { |
| 1935 | .Struct => ty.structFieldCount(), | |
| 1936 | .Union => ty.unionFields().count(), | |
| 1931 | .Struct => ty.structFieldCount(mod), | |
| 1932 | .Union => ty.unionFields(mod).count(), | |
| 1937 | 1933 | else => unreachable, |
| 1938 | 1934 | }; |
| 1939 | 1935 | |
| 1940 | 1936 | var c_fields_len: usize = 0; |
| 1941 | 1937 | for (0..fields_len) |field_i| { |
| 1942 | const field_ty = ty.structFieldType(field_i); | |
| 1943 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | |
| 1944 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1938 | const field_ty = ty.structFieldType(field_i, mod); | |
| 1939 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or | |
| 1940 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1945 | 1941 | c_fields_len += 1; |
| 1946 | 1942 | } |
| 1947 | 1943 | |
| 1948 | 1944 | const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len); |
| 1949 | 1945 | var c_field_i: usize = 0; |
| 1950 | 1946 | for (0..fields_len) |field_i| { |
| 1951 | const field_ty = ty.structFieldType(field_i); | |
| 1952 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | |
| 1953 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1947 | const field_ty = ty.structFieldType(field_i, mod); | |
| 1948 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or | |
| 1949 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1954 | 1950 | |
| 1955 | 1951 | defer c_field_i += 1; |
| 1956 | 1952 | fields_pl[c_field_i] = .{ |
| 1957 | .name = try if (ty.isSimpleTuple()) | |
| 1953 | .name = try if (ty.isSimpleTuple(mod)) | |
| 1958 | 1954 | std.fmt.allocPrintZ(arena, "f{}", .{field_i}) |
| 1959 | 1955 | else |
| 1960 | arena.dupeZ(u8, switch (zig_ty_tag) { | |
| 1961 | .Struct => ty.structFieldName(field_i), | |
| 1962 | .Union => ty.unionFields().keys()[field_i], | |
| 1956 | arena.dupeZ(u8, mod.intern_pool.stringToSlice(switch (zig_ty_tag) { | |
| 1957 | .Struct => ty.structFieldName(field_i, mod), | |
| 1958 | .Union => ty.unionFields(mod).keys()[field_i], | |
| 1963 | 1959 | else => unreachable, |
| 1964 | }), | |
| 1965 | .type = store.set.typeToIndex(field_ty, target, switch (kind) { | |
| 1960 | })), | |
| 1961 | .type = store.set.typeToIndex(field_ty, mod, switch (kind) { | |
| 1966 | 1962 | .forward, .forward_parameter => .forward, |
| 1967 | 1963 | .complete, .parameter, .payload => .complete, |
| 1968 | 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 | 1984 | const unnamed_pl = try arena.create(Payload.Unnamed); |
| 1989 | 1985 | unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{ |
| 1990 | 1986 | .fields = fields_pl, |
| 1991 | .owner_decl = ty.getOwnerDecl(), | |
| 1992 | .id = if (ty.unionTagTypeSafety()) |_| 0 else unreachable, | |
| 1987 | .owner_decl = ty.getOwnerDecl(mod), | |
| 1988 | .id = if (ty.unionTagTypeSafety(mod)) |_| 0 else unreachable, | |
| 1993 | 1989 | } }; |
| 1994 | 1990 | return initPayload(unnamed_pl); |
| 1995 | 1991 | }, |
| ... | ... | @@ -2004,7 +2000,7 @@ pub const CType = extern union { |
| 2004 | 2000 | const struct_pl = try arena.create(Payload.Aggregate); |
| 2005 | 2001 | struct_pl.* = .{ .base = .{ .tag = t }, .data = .{ |
| 2006 | 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 | 2005 | return initPayload(struct_pl); |
| 2010 | 2006 | }, |
| ... | ... | @@ -2016,7 +2012,7 @@ pub const CType = extern union { |
| 2016 | 2012 | .function, |
| 2017 | 2013 | .varargs_function, |
| 2018 | 2014 | => { |
| 2019 | const info = ty.fnInfo(); | |
| 2015 | const info = mod.typeToFunc(ty).?; | |
| 2020 | 2016 | assert(!info.is_generic); |
| 2021 | 2017 | const param_kind: Kind = switch (kind) { |
| 2022 | 2018 | .forward, .forward_parameter => .forward_parameter, |
| ... | ... | @@ -2026,21 +2022,21 @@ pub const CType = extern union { |
| 2026 | 2022 | |
| 2027 | 2023 | var c_params_len: usize = 0; |
| 2028 | 2024 | for (info.param_types) |param_type| { |
| 2029 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2025 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 2030 | 2026 | c_params_len += 1; |
| 2031 | 2027 | } |
| 2032 | 2028 | |
| 2033 | 2029 | const params_pl = try arena.alloc(Index, c_params_len); |
| 2034 | 2030 | var c_param_i: usize = 0; |
| 2035 | 2031 | for (info.param_types) |param_type| { |
| 2036 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2037 | params_pl[c_param_i] = store.set.typeToIndex(param_type, target, param_kind).?; | |
| 2032 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 2033 | params_pl[c_param_i] = store.set.typeToIndex(param_type.toType(), mod, param_kind).?; | |
| 2038 | 2034 | c_param_i += 1; |
| 2039 | 2035 | } |
| 2040 | 2036 | |
| 2041 | 2037 | const fn_pl = try arena.create(Payload.Function); |
| 2042 | 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 | 2040 | .param_types = params_pl, |
| 2045 | 2041 | } }; |
| 2046 | 2042 | return initPayload(fn_pl); |
| ... | ... | @@ -2067,33 +2063,33 @@ pub const CType = extern union { |
| 2067 | 2063 | } |
| 2068 | 2064 | |
| 2069 | 2065 | pub fn eql(self: @This(), ty: Type, cty: CType) bool { |
| 2066 | const mod = self.lookup.getModule(); | |
| 2070 | 2067 | switch (self.convert.value) { |
| 2071 | 2068 | .cty => |c| return c.eql(cty), |
| 2072 | 2069 | .tag => |t| { |
| 2073 | 2070 | if (t != cty.tag()) return false; |
| 2074 | 2071 | |
| 2075 | const target = self.lookup.getTarget(); | |
| 2076 | 2072 | switch (t) { |
| 2077 | 2073 | .fwd_anon_struct, |
| 2078 | 2074 | .fwd_anon_union, |
| 2079 | 2075 | => { |
| 2080 | if (!ty.isTupleOrAnonStruct()) return false; | |
| 2076 | if (!ty.isTupleOrAnonStruct(mod)) return false; | |
| 2081 | 2077 | |
| 2082 | 2078 | var name_buf: [ |
| 2083 | 2079 | std.fmt.count("f{}", .{std.math.maxInt(usize)}) |
| 2084 | 2080 | ]u8 = undefined; |
| 2085 | 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 | 2084 | var c_field_i: usize = 0; |
| 2089 | 2085 | for (0..switch (zig_ty_tag) { |
| 2090 | .Struct => ty.structFieldCount(), | |
| 2091 | .Union => ty.unionFields().count(), | |
| 2086 | .Struct => ty.structFieldCount(mod), | |
| 2087 | .Union => ty.unionFields(mod).count(), | |
| 2092 | 2088 | else => unreachable, |
| 2093 | 2089 | }) |field_i| { |
| 2094 | const field_ty = ty.structFieldType(field_i); | |
| 2095 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | |
| 2096 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2090 | const field_ty = ty.structFieldType(field_i, mod); | |
| 2091 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or | |
| 2092 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 2097 | 2093 | |
| 2098 | 2094 | defer c_field_i += 1; |
| 2099 | 2095 | const c_field = &c_fields[c_field_i]; |
| ... | ... | @@ -2105,15 +2101,16 @@ pub const CType = extern union { |
| 2105 | 2101 | .payload => unreachable, |
| 2106 | 2102 | }) or !mem.eql( |
| 2107 | 2103 | u8, |
| 2108 | if (ty.isSimpleTuple()) | |
| 2109 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable | |
| 2110 | else switch (zig_ty_tag) { | |
| 2111 | .Struct => ty.structFieldName(field_i), | |
| 2112 | .Union => ty.unionFields().keys()[field_i], | |
| 2113 | else => unreachable, | |
| 2114 | }, | |
| 2104 | if (ty.isSimpleTuple(mod)) | |
| 2105 | std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable | |
| 2106 | else | |
| 2107 | mod.intern_pool.stringToSlice(switch (zig_ty_tag) { | |
| 2108 | .Struct => ty.structFieldName(field_i, mod), | |
| 2109 | .Union => ty.unionFields(mod).keys()[field_i], | |
| 2110 | else => unreachable, | |
| 2111 | }), | |
| 2115 | 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 | 2114 | c_field.alignas.@"align") return false; |
| 2118 | 2115 | } |
| 2119 | 2116 | return true; |
| ... | ... | @@ -2125,9 +2122,9 @@ pub const CType = extern union { |
| 2125 | 2122 | .packed_unnamed_union, |
| 2126 | 2123 | => switch (self.kind) { |
| 2127 | 2124 | .forward, .forward_parameter, .complete, .parameter, .global => unreachable, |
| 2128 | .payload => if (ty.unionTagTypeSafety()) |_| { | |
| 2125 | .payload => if (ty.unionTagTypeSafety(mod)) |_| { | |
| 2129 | 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 | 2128 | } else unreachable, |
| 2132 | 2129 | }, |
| 2133 | 2130 | |
| ... | ... | @@ -2146,9 +2143,9 @@ pub const CType = extern union { |
| 2146 | 2143 | .function, |
| 2147 | 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 | 2149 | assert(!info.is_generic); |
| 2153 | 2150 | const data = cty.cast(Payload.Function).?.data; |
| 2154 | 2151 | const param_kind: Kind = switch (self.kind) { |
| ... | ... | @@ -2157,18 +2154,18 @@ pub const CType = extern union { |
| 2157 | 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 | 2158 | return false; |
| 2162 | 2159 | |
| 2163 | 2160 | var c_param_i: usize = 0; |
| 2164 | 2161 | for (info.param_types) |param_type| { |
| 2165 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2162 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 2166 | 2163 | |
| 2167 | 2164 | if (c_param_i >= data.param_types.len) return false; |
| 2168 | 2165 | const param_cty = data.param_types[c_param_i]; |
| 2169 | 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 | 2169 | return false; |
| 2173 | 2170 | } |
| 2174 | 2171 | return c_param_i == data.param_types.len; |
| ... | ... | @@ -2202,7 +2199,7 @@ pub const CType = extern union { |
| 2202 | 2199 | .tag => |t| { |
| 2203 | 2200 | autoHash(hasher, t); |
| 2204 | 2201 | |
| 2205 | const target = self.lookup.getTarget(); | |
| 2202 | const mod = self.lookup.getModule(); | |
| 2206 | 2203 | switch (t) { |
| 2207 | 2204 | .fwd_anon_struct, |
| 2208 | 2205 | .fwd_anon_union, |
| ... | ... | @@ -2211,15 +2208,15 @@ pub const CType = extern union { |
| 2211 | 2208 | std.fmt.count("f{}", .{std.math.maxInt(usize)}) |
| 2212 | 2209 | ]u8 = undefined; |
| 2213 | 2210 | |
| 2214 | const zig_ty_tag = ty.zigTypeTag(); | |
| 2215 | for (0..switch (ty.zigTypeTag()) { | |
| 2216 | .Struct => ty.structFieldCount(), | |
| 2217 | .Union => ty.unionFields().count(), | |
| 2211 | const zig_ty_tag = ty.zigTypeTag(mod); | |
| 2212 | for (0..switch (ty.zigTypeTag(mod)) { | |
| 2213 | .Struct => ty.structFieldCount(mod), | |
| 2214 | .Union => ty.unionFields(mod).count(), | |
| 2218 | 2215 | else => unreachable, |
| 2219 | 2216 | }) |field_i| { |
| 2220 | const field_ty = ty.structFieldType(field_i); | |
| 2221 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | |
| 2222 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2217 | const field_ty = ty.structFieldType(field_i, mod); | |
| 2218 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or | |
| 2219 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 2223 | 2220 | |
| 2224 | 2221 | self.updateHasherRecurse(hasher, field_ty, switch (self.kind) { |
| 2225 | 2222 | .forward, .forward_parameter => .forward, |
| ... | ... | @@ -2227,14 +2224,15 @@ pub const CType = extern union { |
| 2227 | 2224 | .global => .global, |
| 2228 | 2225 | .payload => unreachable, |
| 2229 | 2226 | }); |
| 2230 | hasher.update(if (ty.isSimpleTuple()) | |
| 2227 | hasher.update(if (ty.isSimpleTuple(mod)) | |
| 2231 | 2228 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2232 | else switch (zig_ty_tag) { | |
| 2233 | .Struct => ty.structFieldName(field_i), | |
| 2234 | .Union => ty.unionFields().keys()[field_i], | |
| 2235 | else => unreachable, | |
| 2236 | }); | |
| 2237 | autoHash(hasher, AlignAs.fieldAlign(ty, field_i, target).@"align"); | |
| 2229 | else | |
| 2230 | mod.intern_pool.stringToSlice(switch (zig_ty_tag) { | |
| 2231 | .Struct => ty.structFieldName(field_i, mod), | |
| 2232 | .Union => ty.unionFields(mod).keys()[field_i], | |
| 2233 | else => unreachable, | |
| 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 | 2242 | .packed_unnamed_union, |
| 2245 | 2243 | => switch (self.kind) { |
| 2246 | 2244 | .forward, .forward_parameter, .complete, .parameter, .global => unreachable, |
| 2247 | .payload => if (ty.unionTagTypeSafety()) |_| { | |
| 2248 | autoHash(hasher, ty.getOwnerDecl()); | |
| 2245 | .payload => if (ty.unionTagTypeSafety(mod)) |_| { | |
| 2246 | autoHash(hasher, ty.getOwnerDecl(mod)); | |
| 2249 | 2247 | autoHash(hasher, @as(u32, 0)); |
| 2250 | 2248 | } else unreachable, |
| 2251 | 2249 | }, |
| ... | ... | @@ -2261,7 +2259,7 @@ pub const CType = extern union { |
| 2261 | 2259 | .function, |
| 2262 | 2260 | .varargs_function, |
| 2263 | 2261 | => { |
| 2264 | const info = ty.fnInfo(); | |
| 2262 | const info = mod.typeToFunc(ty).?; | |
| 2265 | 2263 | assert(!info.is_generic); |
| 2266 | 2264 | const param_kind: Kind = switch (self.kind) { |
| 2267 | 2265 | .forward, .forward_parameter => .forward_parameter, |
| ... | ... | @@ -2269,10 +2267,10 @@ pub const CType = extern union { |
| 2269 | 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 | 2271 | for (info.param_types) |param_type| { |
| 2274 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2275 | self.updateHasherRecurse(hasher, param_type, param_kind); | |
| 2272 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 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 | 12 | const Compilation = @import("../Compilation.zig"); |
| 13 | 13 | const build_options = @import("build_options"); |
| 14 | 14 | const Module = @import("../Module.zig"); |
| 15 | const InternPool = @import("../InternPool.zig"); | |
| 15 | 16 | const Package = @import("../Package.zig"); |
| 16 | 17 | const TypedValue = @import("../TypedValue.zig"); |
| 17 | 18 | const Air = @import("../Air.zig"); |
| ... | ... | @@ -361,15 +362,11 @@ pub const Object = struct { |
| 361 | 362 | decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value), |
| 362 | 363 | /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction. |
| 363 | 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 | /// the compiler, but the Type/Value memory here is backed by `type_map_arena`. | |
| 366 | /// TODO we need to remove entries from this map in response to incremental compilation | |
| 367 | /// but I think the frontend won't tell us about types that get deleted because | |
| 368 | /// hasRuntimeBits() is false for types. | |
| 365 | /// Maps Zig types to LLVM types. The table memory is backed by the GPA of | |
| 366 | /// the compiler. | |
| 367 | /// TODO when InternPool garbage collection is implemented, this map needs | |
| 368 | /// to be garbage collected as well. | |
| 369 | 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 | 370 | di_type_map: DITypeMap, |
| 374 | 371 | /// The LLVM global table which holds the names corresponding to Zig errors. |
| 375 | 372 | /// Note that the values are not added until flushModule, when all errors in |
| ... | ... | @@ -380,21 +377,11 @@ pub const Object = struct { |
| 380 | 377 | /// name collision. |
| 381 | 378 | extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void), |
| 382 | 379 | |
| 383 | pub const TypeMap = std.HashMapUnmanaged( | |
| 384 | Type, | |
| 385 | *llvm.Type, | |
| 386 | Type.HashContext64, | |
| 387 | std.hash_map.default_max_load_percentage, | |
| 388 | ); | |
| 380 | pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, *llvm.Type); | |
| 389 | 381 | |
| 390 | 382 | /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we |
| 391 | 383 | /// want to iterate over it while adding entries to it. |
| 392 | pub const DITypeMap = std.ArrayHashMapUnmanaged( | |
| 393 | Type, | |
| 394 | AnnotatedDITypePtr, | |
| 395 | Type.HashContext32, | |
| 396 | true, | |
| 397 | ); | |
| 384 | pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr); | |
| 398 | 385 | |
| 399 | 386 | pub fn create(gpa: Allocator, options: link.Options) !*Object { |
| 400 | 387 | const obj = try gpa.create(Object); |
| ... | ... | @@ -542,7 +529,6 @@ pub const Object = struct { |
| 542 | 529 | .decl_map = .{}, |
| 543 | 530 | .named_enum_map = .{}, |
| 544 | 531 | .type_map = .{}, |
| 545 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), | |
| 546 | 532 | .di_type_map = .{}, |
| 547 | 533 | .error_name_table = null, |
| 548 | 534 | .extern_collisions = .{}, |
| ... | ... | @@ -562,7 +548,6 @@ pub const Object = struct { |
| 562 | 548 | self.decl_map.deinit(gpa); |
| 563 | 549 | self.named_enum_map.deinit(gpa); |
| 564 | 550 | self.type_map.deinit(gpa); |
| 565 | self.type_map_arena.deinit(); | |
| 566 | 551 | self.extern_collisions.deinit(gpa); |
| 567 | 552 | self.* = undefined; |
| 568 | 553 | } |
| ... | ... | @@ -597,16 +582,16 @@ pub const Object = struct { |
| 597 | 582 | llvm_usize_ty, |
| 598 | 583 | }; |
| 599 | 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); | |
| 601 | const slice_alignment = slice_ty.abiAlignment(target); | |
| 585 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 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 | 589 | const llvm_errors = try mod.gpa.alloc(*llvm.Value, error_name_list.len); |
| 605 | 590 | defer mod.gpa.free(llvm_errors); |
| 606 | 591 | |
| 607 | 592 | llvm_errors[0] = llvm_slice_ty.getUndef(); |
| 608 | for (llvm_errors[1..], 0..) |*llvm_error, i| { | |
| 609 | const name = error_name_list[1..][i]; | |
| 593 | for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| { | |
| 594 | const name = mod.intern_pool.stringToSlice(name_nts); | |
| 610 | 595 | const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False); |
| 611 | 596 | const str_global = self.llvm_module.addGlobal(str_init.typeOf(), ""); |
| 612 | 597 | str_global.setInitializer(str_init); |
| ... | ... | @@ -686,7 +671,7 @@ pub const Object = struct { |
| 686 | 671 | const llvm_global = entry.value_ptr.*; |
| 687 | 672 | // Same logic as below but for externs instead of exports. |
| 688 | 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 | 675 | if (other_global == llvm_global) continue; |
| 691 | 676 | |
| 692 | 677 | llvm_global.replaceAllUsesWith(other_global); |
| ... | ... | @@ -702,12 +687,9 @@ pub const Object = struct { |
| 702 | 687 | for (export_list.items) |exp| { |
| 703 | 688 | // Detect if the LLVM global has already been created as an extern. In such |
| 704 | 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 | |
| 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); | |
| 690 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | |
| 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 | 693 | if (other_global == llvm_global) continue; |
| 712 | 694 | |
| 713 | 695 | other_global.replaceAllUsesWith(llvm_global); |
| ... | ... | @@ -880,28 +862,29 @@ pub const Object = struct { |
| 880 | 862 | |
| 881 | 863 | pub fn updateFunc( |
| 882 | 864 | o: *Object, |
| 883 | module: *Module, | |
| 884 | func: *Module.Fn, | |
| 865 | mod: *Module, | |
| 866 | func_index: Module.Fn.Index, | |
| 885 | 867 | air: Air, |
| 886 | 868 | liveness: Liveness, |
| 887 | 869 | ) !void { |
| 870 | const func = mod.funcPtr(func_index); | |
| 888 | 871 | const decl_index = func.owner_decl; |
| 889 | const decl = module.declPtr(decl_index); | |
| 890 | const target = module.getTarget(); | |
| 872 | const decl = mod.declPtr(decl_index); | |
| 873 | const target = mod.getTarget(); | |
| 891 | 874 | |
| 892 | 875 | var dg: DeclGen = .{ |
| 893 | 876 | .context = o.context, |
| 894 | 877 | .object = o, |
| 895 | .module = module, | |
| 878 | .module = mod, | |
| 896 | 879 | .decl_index = decl_index, |
| 897 | 880 | .decl = decl, |
| 898 | 881 | .err_msg = null, |
| 899 | .gpa = module.gpa, | |
| 882 | .gpa = mod.gpa, | |
| 900 | 883 | }; |
| 901 | 884 | |
| 902 | 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 | 888 | dg.addFnAttrInt(llvm_func, "alignstack", align_info.alignment); |
| 906 | 889 | dg.addFnAttr(llvm_func, "noinline"); |
| 907 | 890 | } else { |
| ... | ... | @@ -922,7 +905,7 @@ pub const Object = struct { |
| 922 | 905 | } |
| 923 | 906 | |
| 924 | 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 | 909 | if (ssp_buf_size != 0) { |
| 927 | 910 | var buf: [12]u8 = undefined; |
| 928 | 911 | const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable; |
| ... | ... | @@ -931,15 +914,14 @@ pub const Object = struct { |
| 931 | 914 | } |
| 932 | 915 | |
| 933 | 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 | 918 | dg.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack"); |
| 936 | 919 | } else if (target.os.tag == .uefi) { |
| 937 | 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 | 924 | llvm_func.setSection(section); |
| 942 | } | |
| 943 | 925 | |
| 944 | 926 | // Remove all the basic blocks of a function in order to start over, generating |
| 945 | 927 | // LLVM IR from an empty function body. |
| ... | ... | @@ -953,18 +935,18 @@ pub const Object = struct { |
| 953 | 935 | builder.positionBuilderAtEnd(entry_block); |
| 954 | 936 | |
| 955 | 937 | // This gets the LLVM values from the function and stores them in `dg.args`. |
| 956 | const fn_info = decl.ty.fnInfo(); | |
| 957 | const sret = firstParamSRet(fn_info, target); | |
| 938 | const fn_info = mod.typeToFunc(decl.ty).?; | |
| 939 | const sret = firstParamSRet(fn_info, mod); | |
| 958 | 940 | const ret_ptr = if (sret) llvm_func.getParam(0) else null; |
| 959 | 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 | 944 | .signed => dg.addAttr(llvm_func, 0, "signext"), |
| 963 | 945 | .unsigned => dg.addAttr(llvm_func, 0, "zeroext"), |
| 964 | 946 | }; |
| 965 | 947 | |
| 966 | const err_return_tracing = fn_info.return_type.isError() and | |
| 967 | module.comp.bin_file.options.error_return_tracing; | |
| 948 | const err_return_tracing = fn_info.return_type.toType().isError(mod) and | |
| 949 | mod.comp.bin_file.options.error_return_tracing; | |
| 968 | 950 | |
| 969 | 951 | const err_ret_trace = if (err_return_tracing) |
| 970 | 952 | llvm_func.getParam(@boolToInt(ret_ptr != null)) |
| ... | ... | @@ -985,12 +967,12 @@ pub const Object = struct { |
| 985 | 967 | .byval => { |
| 986 | 968 | assert(!it.byval_attr); |
| 987 | 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 | 971 | const param = llvm_func.getParam(llvm_arg_i); |
| 990 | 972 | try args.ensureUnusedCapacity(1); |
| 991 | 973 | |
| 992 | if (isByRef(param_ty)) { | |
| 993 | const alignment = param_ty.abiAlignment(target); | |
| 974 | if (isByRef(param_ty, mod)) { | |
| 975 | const alignment = param_ty.abiAlignment(mod); | |
| 994 | 976 | const param_llvm_ty = param.typeOf(); |
| 995 | 977 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 996 | 978 | const store_inst = builder.buildStore(param, arg_ptr); |
| ... | ... | @@ -1004,17 +986,17 @@ pub const Object = struct { |
| 1004 | 986 | llvm_arg_i += 1; |
| 1005 | 987 | }, |
| 1006 | 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 | 990 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1009 | 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 | 994 | dg.addByRefParamAttrs(llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty); |
| 1013 | 995 | llvm_arg_i += 1; |
| 1014 | 996 | |
| 1015 | 997 | try args.ensureUnusedCapacity(1); |
| 1016 | 998 | |
| 1017 | if (isByRef(param_ty)) { | |
| 999 | if (isByRef(param_ty, mod)) { | |
| 1018 | 1000 | args.appendAssumeCapacity(param); |
| 1019 | 1001 | } else { |
| 1020 | 1002 | const load_inst = builder.buildLoad(param_llvm_ty, param, ""); |
| ... | ... | @@ -1023,17 +1005,17 @@ pub const Object = struct { |
| 1023 | 1005 | } |
| 1024 | 1006 | }, |
| 1025 | 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 | 1009 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1028 | 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 | 1013 | dg.addArgAttr(llvm_func, llvm_arg_i, "noundef"); |
| 1032 | 1014 | llvm_arg_i += 1; |
| 1033 | 1015 | |
| 1034 | 1016 | try args.ensureUnusedCapacity(1); |
| 1035 | 1017 | |
| 1036 | if (isByRef(param_ty)) { | |
| 1018 | if (isByRef(param_ty, mod)) { | |
| 1037 | 1019 | args.appendAssumeCapacity(param); |
| 1038 | 1020 | } else { |
| 1039 | 1021 | const load_inst = builder.buildLoad(param_llvm_ty, param, ""); |
| ... | ... | @@ -1043,15 +1025,15 @@ pub const Object = struct { |
| 1043 | 1025 | }, |
| 1044 | 1026 | .abi_sized_int => { |
| 1045 | 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 | 1029 | const param = llvm_func.getParam(llvm_arg_i); |
| 1048 | 1030 | llvm_arg_i += 1; |
| 1049 | 1031 | |
| 1050 | 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 | 1034 | const int_llvm_ty = dg.context.intType(abi_size * 8); |
| 1053 | 1035 | const alignment = @max( |
| 1054 | param_ty.abiAlignment(target), | |
| 1036 | param_ty.abiAlignment(mod), | |
| 1055 | 1037 | dg.object.target_data.abiAlignmentOfType(int_llvm_ty), |
| 1056 | 1038 | ); |
| 1057 | 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 | 1042 | |
| 1061 | 1043 | try args.ensureUnusedCapacity(1); |
| 1062 | 1044 | |
| 1063 | if (isByRef(param_ty)) { | |
| 1045 | if (isByRef(param_ty, mod)) { | |
| 1064 | 1046 | args.appendAssumeCapacity(arg_ptr); |
| 1065 | 1047 | } else { |
| 1066 | 1048 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); |
| ... | ... | @@ -1070,15 +1052,15 @@ pub const Object = struct { |
| 1070 | 1052 | }, |
| 1071 | 1053 | .slice => { |
| 1072 | 1054 | assert(!it.byval_attr); |
| 1073 | const param_ty = fn_info.param_types[it.zig_index - 1]; | |
| 1074 | const ptr_info = param_ty.ptrInfo().data; | |
| 1055 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); | |
| 1056 | const ptr_info = param_ty.ptrInfo(mod); | |
| 1075 | 1057 | |
| 1076 | 1058 | if (math.cast(u5, it.zig_index - 1)) |i| { |
| 1077 | 1059 | if (@truncate(u1, fn_info.noalias_bits >> i) != 0) { |
| 1078 | 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 | 1064 | dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull"); |
| 1083 | 1065 | } |
| 1084 | 1066 | if (!ptr_info.mutable) { |
| ... | ... | @@ -1087,7 +1069,7 @@ pub const Object = struct { |
| 1087 | 1069 | if (ptr_info.@"align" != 0) { |
| 1088 | 1070 | dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.@"align"); |
| 1089 | 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 | 1073 | dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align); |
| 1092 | 1074 | } |
| 1093 | 1075 | const ptr_param = llvm_func.getParam(llvm_arg_i); |
| ... | ... | @@ -1103,9 +1085,9 @@ pub const Object = struct { |
| 1103 | 1085 | .multiple_llvm_types => { |
| 1104 | 1086 | assert(!it.byval_attr); |
| 1105 | 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 | 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 | 1091 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, param_alignment, target); |
| 1110 | 1092 | const llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); |
| 1111 | 1093 | for (field_types, 0..) |_, field_i_usize| { |
| ... | ... | @@ -1117,7 +1099,7 @@ pub const Object = struct { |
| 1117 | 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 | 1103 | const loaded = if (is_by_ref) arg_ptr else l: { |
| 1122 | 1104 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); |
| 1123 | 1105 | load_inst.setAlignment(param_alignment); |
| ... | ... | @@ -1134,16 +1116,16 @@ pub const Object = struct { |
| 1134 | 1116 | args.appendAssumeCapacity(casted); |
| 1135 | 1117 | }, |
| 1136 | 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 | 1120 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1139 | 1121 | const param = llvm_func.getParam(llvm_arg_i); |
| 1140 | 1122 | llvm_arg_i += 1; |
| 1141 | 1123 | |
| 1142 | const alignment = param_ty.abiAlignment(target); | |
| 1124 | const alignment = param_ty.abiAlignment(mod); | |
| 1143 | 1125 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 1144 | 1126 | _ = builder.buildStore(param, arg_ptr); |
| 1145 | 1127 | |
| 1146 | if (isByRef(param_ty)) { | |
| 1128 | if (isByRef(param_ty, mod)) { | |
| 1147 | 1129 | try args.append(arg_ptr); |
| 1148 | 1130 | } else { |
| 1149 | 1131 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); |
| ... | ... | @@ -1152,16 +1134,16 @@ pub const Object = struct { |
| 1152 | 1134 | } |
| 1153 | 1135 | }, |
| 1154 | 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 | 1138 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1157 | 1139 | const param = llvm_func.getParam(llvm_arg_i); |
| 1158 | 1140 | llvm_arg_i += 1; |
| 1159 | 1141 | |
| 1160 | const alignment = param_ty.abiAlignment(target); | |
| 1142 | const alignment = param_ty.abiAlignment(mod); | |
| 1161 | 1143 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 1162 | 1144 | _ = builder.buildStore(param, arg_ptr); |
| 1163 | 1145 | |
| 1164 | if (isByRef(param_ty)) { | |
| 1146 | if (isByRef(param_ty, mod)) { | |
| 1165 | 1147 | try args.append(arg_ptr); |
| 1166 | 1148 | } else { |
| 1167 | 1149 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); |
| ... | ... | @@ -1176,27 +1158,28 @@ pub const Object = struct { |
| 1176 | 1158 | var di_scope: ?*llvm.DIScope = null; |
| 1177 | 1159 | |
| 1178 | 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 | 1163 | const line_number = decl.src_line + 1; |
| 1182 | const is_internal_linkage = decl.val.tag() != .extern_fn and | |
| 1183 | !module.decl_exports.contains(decl_index); | |
| 1184 | const noret_bit: c_uint = if (fn_info.return_type.isNoReturn()) | |
| 1164 | const is_internal_linkage = decl.val.getExternFunc(mod) == null and | |
| 1165 | !mod.decl_exports.contains(decl_index); | |
| 1166 | const noret_bit: c_uint = if (fn_info.return_type == .noreturn_type) | |
| 1185 | 1167 | llvm.DIFlags.NoReturn |
| 1186 | 1168 | else |
| 1187 | 1169 | 0; |
| 1170 | const decl_di_ty = try o.lowerDebugType(decl.ty, .full); | |
| 1188 | 1171 | const subprogram = dib.createFunction( |
| 1189 | 1172 | di_file.?.toScope(), |
| 1190 | decl.name, | |
| 1173 | mod.intern_pool.stringToSlice(decl.name), | |
| 1191 | 1174 | llvm_func.getValueName(), |
| 1192 | 1175 | di_file.?, |
| 1193 | 1176 | line_number, |
| 1194 | try o.lowerDebugType(decl.ty, .full), | |
| 1177 | decl_di_ty, | |
| 1195 | 1178 | is_internal_linkage, |
| 1196 | 1179 | true, // is definition |
| 1197 | 1180 | line_number + func.lbrace_line, // scope line |
| 1198 | 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 | 1183 | null, // decl_subprogram |
| 1201 | 1184 | ); |
| 1202 | 1185 | try dg.object.di_map.put(gpa, decl, subprogram.toNode()); |
| ... | ... | @@ -1219,7 +1202,7 @@ pub const Object = struct { |
| 1219 | 1202 | .func_inst_table = .{}, |
| 1220 | 1203 | .llvm_func = llvm_func, |
| 1221 | 1204 | .blocks = .{}, |
| 1222 | .single_threaded = module.comp.bin_file.options.single_threaded, | |
| 1205 | .single_threaded = mod.comp.bin_file.options.single_threaded, | |
| 1223 | 1206 | .di_scope = di_scope, |
| 1224 | 1207 | .di_file = di_file, |
| 1225 | 1208 | .base_line = dg.decl.src_line, |
| ... | ... | @@ -1232,14 +1215,14 @@ pub const Object = struct { |
| 1232 | 1215 | fg.genBody(air.getMainBody()) catch |err| switch (err) { |
| 1233 | 1216 | error.CodegenFail => { |
| 1234 | 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 | 1219 | dg.err_msg = null; |
| 1237 | 1220 | return; |
| 1238 | 1221 | }, |
| 1239 | 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 | 1228 | pub fn updateDecl(self: *Object, module: *Module, decl_index: Module.Decl.Index) !void { |
| ... | ... | @@ -1275,63 +1258,72 @@ pub const Object = struct { |
| 1275 | 1258 | |
| 1276 | 1259 | pub fn updateDeclExports( |
| 1277 | 1260 | self: *Object, |
| 1278 | module: *Module, | |
| 1261 | mod: *Module, | |
| 1279 | 1262 | decl_index: Module.Decl.Index, |
| 1280 | 1263 | exports: []const *Module.Export, |
| 1281 | 1264 | ) !void { |
| 1265 | const gpa = mod.gpa; | |
| 1282 | 1266 | // If the module does not already have the function, we ignore this function call |
| 1283 | 1267 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. |
| 1284 | 1268 | const llvm_global = self.decl_map.get(decl_index) orelse return; |
| 1285 | const decl = module.declPtr(decl_index); | |
| 1286 | if (decl.isExtern()) { | |
| 1287 | const is_wasm_fn = module.getTarget().isWasm() and try decl.isFunction(); | |
| 1288 | const mangle_name = is_wasm_fn and | |
| 1289 | decl.getExternFn().?.lib_name != null and | |
| 1290 | !std.mem.eql(u8, std.mem.sliceTo(decl.getExternFn().?.lib_name.?, 0), "c"); | |
| 1291 | const decl_name = if (mangle_name) name: { | |
| 1292 | const tmp = try std.fmt.allocPrintZ(module.gpa, "{s}|{s}", .{ decl.name, decl.getExternFn().?.lib_name.? }); | |
| 1293 | break :name tmp.ptr; | |
| 1294 | } else decl.name; | |
| 1295 | defer if (mangle_name) module.gpa.free(std.mem.sliceTo(decl_name, 0)); | |
| 1269 | const decl = mod.declPtr(decl_index); | |
| 1270 | if (decl.isExtern(mod)) { | |
| 1271 | var free_decl_name = false; | |
| 1272 | const decl_name = decl_name: { | |
| 1273 | const decl_name = mod.intern_pool.stringToSlice(decl.name); | |
| 1274 | ||
| 1275 | if (mod.getTarget().isWasm() and try decl.isFunction(mod)) { | |
| 1276 | if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| { | |
| 1277 | if (!std.mem.eql(u8, lib_name, "c")) { | |
| 1278 | free_decl_name = true; | |
| 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 | 1290 | llvm_global.setValueName(decl_name); |
| 1298 | 1291 | if (self.getLlvmGlobal(decl_name)) |other_global| { |
| 1299 | 1292 | if (other_global != llvm_global) { |
| 1300 | log.debug("updateDeclExports isExtern()=true setValueName({s}) conflict", .{decl.name}); | |
| 1301 | try self.extern_collisions.put(module.gpa, decl_index, {}); | |
| 1293 | try self.extern_collisions.put(gpa, decl_index, {}); | |
| 1302 | 1294 | } |
| 1303 | 1295 | } |
| 1304 | 1296 | llvm_global.setUnnamedAddr(.False); |
| 1305 | 1297 | llvm_global.setLinkage(.External); |
| 1306 | if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default); | |
| 1298 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default); | |
| 1307 | 1299 | if (self.di_map.get(decl)) |di_node| { |
| 1308 | if (try decl.isFunction()) { | |
| 1300 | if (try decl.isFunction(mod)) { | |
| 1309 | 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 | 1303 | di_func.replaceLinkageName(linkage_name); |
| 1312 | 1304 | } else { |
| 1313 | 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 | 1307 | di_global.replaceLinkageName(linkage_name); |
| 1316 | 1308 | } |
| 1317 | 1309 | } |
| 1318 | if (decl.val.castTag(.variable)) |variable| { | |
| 1319 | if (variable.data.is_threadlocal) { | |
| 1310 | if (decl.val.getVariable(mod)) |variable| { | |
| 1311 | if (variable.is_threadlocal) { | |
| 1320 | 1312 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1321 | 1313 | } else { |
| 1322 | 1314 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 1323 | 1315 | } |
| 1324 | if (variable.data.is_weak_linkage) { | |
| 1316 | if (variable.is_weak_linkage) { | |
| 1325 | 1317 | llvm_global.setLinkage(.ExternalWeak); |
| 1326 | 1318 | } |
| 1327 | 1319 | } |
| 1328 | 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 | 1322 | llvm_global.setValueName2(exp_name.ptr, exp_name.len); |
| 1331 | 1323 | llvm_global.setUnnamedAddr(.False); |
| 1332 | if (module.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport); | |
| 1324 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport); | |
| 1333 | 1325 | if (self.di_map.get(decl)) |di_node| { |
| 1334 | if (try decl.isFunction()) { | |
| 1326 | if (try decl.isFunction(mod)) { | |
| 1335 | 1327 | const di_func = @ptrCast(*llvm.DISubprogram, di_node); |
| 1336 | 1328 | const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len); |
| 1337 | 1329 | di_func.replaceLinkageName(linkage_name); |
| ... | ... | @@ -1341,37 +1333,34 @@ pub const Object = struct { |
| 1341 | 1333 | di_global.replaceLinkageName(linkage_name); |
| 1342 | 1334 | } |
| 1343 | 1335 | } |
| 1344 | switch (exports[0].options.linkage) { | |
| 1336 | switch (exports[0].opts.linkage) { | |
| 1345 | 1337 | .Internal => unreachable, |
| 1346 | 1338 | .Strong => llvm_global.setLinkage(.External), |
| 1347 | 1339 | .Weak => llvm_global.setLinkage(.WeakODR), |
| 1348 | 1340 | .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), |
| 1349 | 1341 | } |
| 1350 | switch (exports[0].options.visibility) { | |
| 1342 | switch (exports[0].opts.visibility) { | |
| 1351 | 1343 | .default => llvm_global.setVisibility(.Default), |
| 1352 | 1344 | .hidden => llvm_global.setVisibility(.Hidden), |
| 1353 | 1345 | .protected => llvm_global.setVisibility(.Protected), |
| 1354 | 1346 | } |
| 1355 | if (exports[0].options.section) |section| { | |
| 1356 | const section_z = try module.gpa.dupeZ(u8, section); | |
| 1357 | defer module.gpa.free(section_z); | |
| 1358 | llvm_global.setSection(section_z); | |
| 1347 | if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| { | |
| 1348 | llvm_global.setSection(section); | |
| 1359 | 1349 | } |
| 1360 | if (decl.val.castTag(.variable)) |variable| { | |
| 1361 | if (variable.data.is_threadlocal) { | |
| 1350 | if (decl.val.getVariable(mod)) |variable| { | |
| 1351 | if (variable.is_threadlocal) { | |
| 1362 | 1352 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1363 | 1353 | } |
| 1364 | 1354 | } |
| 1365 | 1355 | |
| 1366 | 1356 | // If a Decl is exported more than one time (which is rare), |
| 1367 | 1357 | // we add aliases for all but the first export. |
| 1368 | // TODO LLVM C API does not support deleting aliases. We need to | |
| 1369 | // patch it to support this or figure out how to wrap the C++ API ourselves. | |
| 1358 | // TODO LLVM C API does not support deleting aliases. | |
| 1359 | // The planned solution to this is https://github.com/ziglang/zig/issues/13265 | |
| 1370 | 1360 | // Until then we iterate over existing aliases and make them point |
| 1371 | 1361 | // to the correct decl, or otherwise add a new alias. Old aliases are leaked. |
| 1372 | 1362 | for (exports[1..]) |exp| { |
| 1373 | const exp_name_z = try module.gpa.dupeZ(u8, exp.options.name); | |
| 1374 | defer module.gpa.free(exp_name_z); | |
| 1363 | const exp_name_z = mod.intern_pool.stringToSlice(exp.opts.name); | |
| 1375 | 1364 | |
| 1376 | 1365 | if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| { |
| 1377 | 1366 | alias.setAliasee(llvm_global); |
| ... | ... | @@ -1385,15 +1374,14 @@ pub const Object = struct { |
| 1385 | 1374 | } |
| 1386 | 1375 | } |
| 1387 | 1376 | } else { |
| 1388 | const fqn = try decl.getFullyQualifiedName(module); | |
| 1389 | defer module.gpa.free(fqn); | |
| 1377 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 1390 | 1378 | llvm_global.setValueName2(fqn.ptr, fqn.len); |
| 1391 | 1379 | llvm_global.setLinkage(.Internal); |
| 1392 | if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default); | |
| 1380 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default); | |
| 1393 | 1381 | llvm_global.setUnnamedAddr(.True); |
| 1394 | if (decl.val.castTag(.variable)) |variable| { | |
| 1395 | const single_threaded = module.comp.bin_file.options.single_threaded; | |
| 1396 | if (variable.data.is_threadlocal and !single_threaded) { | |
| 1382 | if (decl.val.getVariable(mod)) |variable| { | |
| 1383 | const single_threaded = mod.comp.bin_file.options.single_threaded; | |
| 1384 | if (variable.is_threadlocal and !single_threaded) { | |
| 1397 | 1385 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1398 | 1386 | } else { |
| 1399 | 1387 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| ... | ... | @@ -1444,7 +1432,7 @@ pub const Object = struct { |
| 1444 | 1432 | const gpa = o.gpa; |
| 1445 | 1433 | // Be careful not to reference this `gop` variable after any recursive calls |
| 1446 | 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 | 1436 | if (gop.found_existing) { |
| 1449 | 1437 | const annotated = gop.value_ptr.*; |
| 1450 | 1438 | const di_type = annotated.toDIType(); |
| ... | ... | @@ -1457,10 +1445,7 @@ pub const Object = struct { |
| 1457 | 1445 | }; |
| 1458 | 1446 | return o.lowerDebugTypeImpl(entry, resolve, di_type); |
| 1459 | 1447 | } |
| 1460 | errdefer assert(o.di_type_map.orderedRemoveContext(ty, .{ .mod = o.module })); | |
| 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()); | |
| 1448 | errdefer assert(o.di_type_map.orderedRemove(ty.toIntern())); | |
| 1464 | 1449 | const entry: Object.DITypeMap.Entry = .{ |
| 1465 | 1450 | .key_ptr = gop.key_ptr, |
| 1466 | 1451 | .value_ptr = gop.value_ptr, |
| ... | ... | @@ -1475,18 +1460,19 @@ pub const Object = struct { |
| 1475 | 1460 | resolve: DebugResolveStatus, |
| 1476 | 1461 | opt_fwd_decl: ?*llvm.DIType, |
| 1477 | 1462 | ) Allocator.Error!*llvm.DIType { |
| 1478 | const ty = gop.key_ptr.*; | |
| 1463 | const ty = gop.key_ptr.toType(); | |
| 1479 | 1464 | const gpa = o.gpa; |
| 1480 | 1465 | const target = o.target; |
| 1481 | 1466 | const dib = o.di_builder.?; |
| 1482 | switch (ty.zigTypeTag()) { | |
| 1467 | const mod = o.module; | |
| 1468 | switch (ty.zigTypeTag(mod)) { | |
| 1483 | 1469 | .Void, .NoReturn => { |
| 1484 | 1470 | const di_type = dib.createBasicType("void", 0, DW.ATE.signed); |
| 1485 | 1471 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); |
| 1486 | 1472 | return di_type; |
| 1487 | 1473 | }, |
| 1488 | 1474 | .Int => { |
| 1489 | const info = ty.intInfo(target); | |
| 1475 | const info = ty.intInfo(mod); | |
| 1490 | 1476 | assert(info.bits != 0); |
| 1491 | 1477 | const name = try ty.nameAlloc(gpa, o.module); |
| 1492 | 1478 | defer gpa.free(name); |
| ... | ... | @@ -1494,49 +1480,41 @@ pub const Object = struct { |
| 1494 | 1480 | .signed => DW.ATE.signed, |
| 1495 | 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 | 1484 | const di_type = dib.createBasicType(name, di_bits, dwarf_encoding); |
| 1499 | 1485 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); |
| 1500 | 1486 | return di_type; |
| 1501 | 1487 | }, |
| 1502 | 1488 | .Enum => { |
| 1503 | const owner_decl_index = ty.getOwnerDecl(); | |
| 1489 | const owner_decl_index = ty.getOwnerDecl(mod); | |
| 1504 | 1490 | const owner_decl = o.module.declPtr(owner_decl_index); |
| 1505 | 1491 | |
| 1506 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1492 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1507 | 1493 | const enum_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); |
| 1508 | 1494 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 1509 | 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 | 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 | 1504 | defer gpa.free(enumerators); |
| 1518 | 1505 | |
| 1519 | var buf_field_index: Value.Payload.U32 = .{ | |
| 1520 | .base = .{ .tag = .enum_field_index }, | |
| 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); | |
| 1506 | const int_ty = enum_type.tag_ty.toType(); | |
| 1507 | const int_info = ty.intInfo(mod); | |
| 1528 | 1508 | assert(int_info.bits != 0); |
| 1529 | 1509 | |
| 1530 | for (field_names, 0..) |field_name, i| { | |
| 1531 | const field_name_z = try gpa.dupeZ(u8, field_name); | |
| 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); | |
| 1510 | for (enum_type.names, 0..) |field_name_ip, i| { | |
| 1511 | const field_name_z = ip.stringToSlice(field_name_ip); | |
| 1537 | 1512 | |
| 1538 | 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 | 1519 | if (bigint.limbs.len == 1) { |
| 1542 | 1520 | enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned); |
| ... | ... | @@ -1555,7 +1533,7 @@ pub const Object = struct { |
| 1555 | 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 | 1537 | const di_scope = try o.namespaceToDebugScope(owner_decl.src_namespace); |
| 1560 | 1538 | |
| 1561 | 1539 | const name = try ty.nameAlloc(gpa, o.module); |
| ... | ... | @@ -1566,15 +1544,15 @@ pub const Object = struct { |
| 1566 | 1544 | name, |
| 1567 | 1545 | di_file, |
| 1568 | 1546 | owner_decl.src_node + 1, |
| 1569 | ty.abiSize(target) * 8, | |
| 1570 | ty.abiAlignment(target) * 8, | |
| 1547 | ty.abiSize(mod) * 8, | |
| 1548 | ty.abiAlignment(mod) * 8, | |
| 1571 | 1549 | enumerators.ptr, |
| 1572 | 1550 | @intCast(c_int, enumerators.len), |
| 1573 | 1551 | try o.lowerDebugType(int_ty, .full), |
| 1574 | 1552 | "", |
| 1575 | 1553 | ); |
| 1576 | 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 | 1556 | return enum_di_ty; |
| 1579 | 1557 | }, |
| 1580 | 1558 | .Float => { |
| ... | ... | @@ -1593,49 +1571,40 @@ pub const Object = struct { |
| 1593 | 1571 | }, |
| 1594 | 1572 | .Pointer => { |
| 1595 | 1573 | // Normalize everything that the debug info does not represent. |
| 1596 | const ptr_info = ty.ptrInfo().data; | |
| 1597 | ||
| 1598 | if (ptr_info.sentinel != null or | |
| 1599 | ptr_info.@"addrspace" != .generic or | |
| 1600 | ptr_info.bit_offset != 0 or | |
| 1601 | ptr_info.host_size != 0 or | |
| 1602 | ptr_info.vector_index != .none or | |
| 1603 | ptr_info.@"allowzero" or | |
| 1604 | !ptr_info.mutable or | |
| 1605 | ptr_info.@"volatile" or | |
| 1606 | ptr_info.size == .Many or ptr_info.size == .C or | |
| 1607 | !ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) | |
| 1574 | const ptr_info = Type.ptrInfoIp(&mod.intern_pool, ty.toIntern()); | |
| 1575 | ||
| 1576 | if (ptr_info.sentinel != .none or | |
| 1577 | ptr_info.flags.address_space != .generic or | |
| 1578 | ptr_info.packed_offset.bit_offset != 0 or | |
| 1579 | ptr_info.packed_offset.host_size != 0 or | |
| 1580 | ptr_info.flags.vector_index != .none or | |
| 1581 | ptr_info.flags.is_allowzero or | |
| 1582 | ptr_info.flags.is_const or | |
| 1583 | ptr_info.flags.is_volatile or | |
| 1584 | ptr_info.flags.size == .Many or ptr_info.flags.size == .C or | |
| 1585 | !ptr_info.child.toType().hasRuntimeBitsIgnoreComptime(mod)) | |
| 1608 | 1586 | { |
| 1609 | var payload: Type.Payload.Pointer = .{ | |
| 1610 | .data = .{ | |
| 1611 | .pointee_type = ptr_info.pointee_type, | |
| 1612 | .sentinel = null, | |
| 1613 | .@"align" = ptr_info.@"align", | |
| 1614 | .@"addrspace" = .generic, | |
| 1615 | .bit_offset = 0, | |
| 1616 | .host_size = 0, | |
| 1617 | .@"allowzero" = false, | |
| 1618 | .mutable = true, | |
| 1619 | .@"volatile" = false, | |
| 1620 | .size = switch (ptr_info.size) { | |
| 1587 | const bland_ptr_ty = try mod.ptrType(.{ | |
| 1588 | .child = if (!ptr_info.child.toType().hasRuntimeBitsIgnoreComptime(mod)) | |
| 1589 | .anyopaque_type | |
| 1590 | else | |
| 1591 | ptr_info.child, | |
| 1592 | .flags = .{ | |
| 1593 | .alignment = ptr_info.flags.alignment, | |
| 1594 | .size = switch (ptr_info.flags.size) { | |
| 1621 | 1595 | .Many, .C, .One => .One, |
| 1622 | 1596 | .Slice => .Slice, |
| 1623 | 1597 | }, |
| 1624 | 1598 | }, |
| 1625 | }; | |
| 1626 | if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) { | |
| 1627 | payload.data.pointee_type = Type.anyopaque; | |
| 1628 | } | |
| 1629 | const bland_ptr_ty = Type.initPayload(&payload.base); | |
| 1599 | }); | |
| 1630 | 1600 | const ptr_di_ty = try o.lowerDebugType(bland_ptr_ty, resolve); |
| 1631 | 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 | 1603 | return ptr_di_ty; |
| 1634 | 1604 | } |
| 1635 | 1605 | |
| 1636 | if (ty.isSlice()) { | |
| 1637 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 1638 | const ptr_ty = ty.slicePtrFieldType(&buf); | |
| 1606 | if (ty.isSlice(mod)) { | |
| 1607 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 1639 | 1608 | const len_ty = Type.usize; |
| 1640 | 1609 | |
| 1641 | 1610 | const name = try ty.nameAlloc(gpa, o.module); |
| ... | ... | @@ -1657,10 +1626,10 @@ pub const Object = struct { |
| 1657 | 1626 | break :blk fwd_decl; |
| 1658 | 1627 | }; |
| 1659 | 1628 | |
| 1660 | const ptr_size = ptr_ty.abiSize(target); | |
| 1661 | const ptr_align = ptr_ty.abiAlignment(target); | |
| 1662 | const len_size = len_ty.abiSize(target); | |
| 1663 | const len_align = len_ty.abiAlignment(target); | |
| 1629 | const ptr_size = ptr_ty.abiSize(mod); | |
| 1630 | const ptr_align = ptr_ty.abiAlignment(mod); | |
| 1631 | const len_size = len_ty.abiSize(mod); | |
| 1632 | const len_align = len_ty.abiAlignment(mod); | |
| 1664 | 1633 | |
| 1665 | 1634 | var offset: u64 = 0; |
| 1666 | 1635 | offset += ptr_size; |
| ... | ... | @@ -1697,8 +1666,8 @@ pub const Object = struct { |
| 1697 | 1666 | name.ptr, |
| 1698 | 1667 | di_file, |
| 1699 | 1668 | line, |
| 1700 | ty.abiSize(target) * 8, // size in bits | |
| 1701 | ty.abiAlignment(target) * 8, // align in bits | |
| 1669 | ty.abiSize(mod) * 8, // size in bits | |
| 1670 | ty.abiAlignment(mod) * 8, // align in bits | |
| 1702 | 1671 | 0, // flags |
| 1703 | 1672 | null, // derived from |
| 1704 | 1673 | &fields, |
| ... | ... | @@ -1709,65 +1678,65 @@ pub const Object = struct { |
| 1709 | 1678 | ); |
| 1710 | 1679 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 1711 | 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 | 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 | 1686 | const name = try ty.nameAlloc(gpa, o.module); |
| 1718 | 1687 | defer gpa.free(name); |
| 1719 | 1688 | const ptr_di_ty = dib.createPointerType( |
| 1720 | 1689 | elem_di_ty, |
| 1721 | 1690 | target.ptrBitWidth(), |
| 1722 | ty.ptrAlignment(target) * 8, | |
| 1691 | ty.ptrAlignment(mod) * 8, | |
| 1723 | 1692 | name, |
| 1724 | 1693 | ); |
| 1725 | 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 | 1696 | return ptr_di_ty; |
| 1728 | 1697 | }, |
| 1729 | 1698 | .Opaque => { |
| 1730 | if (ty.tag() == .anyopaque) { | |
| 1699 | if (ty.toIntern() == .anyopaque_type) { | |
| 1731 | 1700 | const di_ty = dib.createBasicType("anyopaque", 0, DW.ATE.signed); |
| 1732 | 1701 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| 1733 | 1702 | return di_ty; |
| 1734 | 1703 | } |
| 1735 | 1704 | const name = try ty.nameAlloc(gpa, o.module); |
| 1736 | 1705 | defer gpa.free(name); |
| 1737 | const owner_decl_index = ty.getOwnerDecl(); | |
| 1706 | const owner_decl_index = ty.getOwnerDecl(mod); | |
| 1738 | 1707 | const owner_decl = o.module.declPtr(owner_decl_index); |
| 1739 | 1708 | const opaque_di_ty = dib.createForwardDeclType( |
| 1740 | 1709 | DW.TAG.structure_type, |
| 1741 | 1710 | name, |
| 1742 | 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 | 1713 | owner_decl.src_node + 1, |
| 1745 | 1714 | ); |
| 1746 | 1715 | // The recursive call to `lowerDebugType` va `namespaceToDebugScope` |
| 1747 | 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 | 1718 | return opaque_di_ty; |
| 1750 | 1719 | }, |
| 1751 | 1720 | .Array => { |
| 1752 | 1721 | const array_di_ty = dib.createArrayType( |
| 1753 | ty.abiSize(target) * 8, | |
| 1754 | ty.abiAlignment(target) * 8, | |
| 1755 | try o.lowerDebugType(ty.childType(), .full), | |
| 1756 | @intCast(c_int, ty.arrayLen()), | |
| 1722 | ty.abiSize(mod) * 8, | |
| 1723 | ty.abiAlignment(mod) * 8, | |
| 1724 | try o.lowerDebugType(ty.childType(mod), .full), | |
| 1725 | @intCast(c_int, ty.arrayLen(mod)), | |
| 1757 | 1726 | ); |
| 1758 | 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 | 1729 | return array_di_ty; |
| 1761 | 1730 | }, |
| 1762 | 1731 | .Vector => { |
| 1763 | const elem_ty = ty.elemType2(); | |
| 1732 | const elem_ty = ty.elemType2(mod); | |
| 1764 | 1733 | // Vector elements cannot be padded since that would make |
| 1765 | 1734 | // @bitSizOf(elem) * len > @bitSizOf(vec). |
| 1766 | 1735 | // Neither gdb nor lldb seem to be able to display non-byte sized |
| 1767 | 1736 | // vectors properly. |
| 1768 | const elem_di_type = switch (elem_ty.zigTypeTag()) { | |
| 1737 | const elem_di_type = switch (elem_ty.zigTypeTag(mod)) { | |
| 1769 | 1738 | .Int => blk: { |
| 1770 | const info = elem_ty.intInfo(target); | |
| 1739 | const info = elem_ty.intInfo(mod); | |
| 1771 | 1740 | assert(info.bits != 0); |
| 1772 | 1741 | const name = try ty.nameAlloc(gpa, o.module); |
| 1773 | 1742 | defer gpa.free(name); |
| ... | ... | @@ -1778,34 +1747,33 @@ pub const Object = struct { |
| 1778 | 1747 | break :blk dib.createBasicType(name, info.bits, dwarf_encoding); |
| 1779 | 1748 | }, |
| 1780 | 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 | 1753 | const vector_di_ty = dib.createVectorType( |
| 1785 | ty.abiSize(target) * 8, | |
| 1786 | ty.abiAlignment(target) * 8, | |
| 1754 | ty.abiSize(mod) * 8, | |
| 1755 | ty.abiAlignment(mod) * 8, | |
| 1787 | 1756 | elem_di_type, |
| 1788 | ty.vectorLen(), | |
| 1757 | ty.vectorLen(mod), | |
| 1789 | 1758 | ); |
| 1790 | 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 | 1761 | return vector_di_ty; |
| 1793 | 1762 | }, |
| 1794 | 1763 | .Optional => { |
| 1795 | 1764 | const name = try ty.nameAlloc(gpa, o.module); |
| 1796 | 1765 | defer gpa.free(name); |
| 1797 | var buf: Type.Payload.ElemType = undefined; | |
| 1798 | const child_ty = ty.optionalChild(&buf); | |
| 1799 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1766 | const child_ty = ty.optionalChild(mod); | |
| 1767 | if (!child_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1800 | 1768 | const di_bits = 8; // lldb cannot handle non-byte sized types |
| 1801 | 1769 | const di_ty = dib.createBasicType(name, di_bits, DW.ATE.boolean); |
| 1802 | 1770 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| 1803 | 1771 | return di_ty; |
| 1804 | 1772 | } |
| 1805 | if (ty.optionalReprIsPayload()) { | |
| 1773 | if (ty.optionalReprIsPayload(mod)) { | |
| 1806 | 1774 | const ptr_di_ty = try o.lowerDebugType(child_ty, resolve); |
| 1807 | 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 | 1777 | return ptr_di_ty; |
| 1810 | 1778 | } |
| 1811 | 1779 | |
| ... | ... | @@ -1826,10 +1794,10 @@ pub const Object = struct { |
| 1826 | 1794 | }; |
| 1827 | 1795 | |
| 1828 | 1796 | const non_null_ty = Type.u8; |
| 1829 | const payload_size = child_ty.abiSize(target); | |
| 1830 | const payload_align = child_ty.abiAlignment(target); | |
| 1831 | const non_null_size = non_null_ty.abiSize(target); | |
| 1832 | const non_null_align = non_null_ty.abiAlignment(target); | |
| 1797 | const payload_size = child_ty.abiSize(mod); | |
| 1798 | const payload_align = child_ty.abiAlignment(mod); | |
| 1799 | const non_null_size = non_null_ty.abiSize(mod); | |
| 1800 | const non_null_align = non_null_ty.abiAlignment(mod); | |
| 1833 | 1801 | |
| 1834 | 1802 | var offset: u64 = 0; |
| 1835 | 1803 | offset += payload_size; |
| ... | ... | @@ -1866,8 +1834,8 @@ pub const Object = struct { |
| 1866 | 1834 | name.ptr, |
| 1867 | 1835 | di_file, |
| 1868 | 1836 | line, |
| 1869 | ty.abiSize(target) * 8, // size in bits | |
| 1870 | ty.abiAlignment(target) * 8, // align in bits | |
| 1837 | ty.abiSize(mod) * 8, // size in bits | |
| 1838 | ty.abiAlignment(mod) * 8, // align in bits | |
| 1871 | 1839 | 0, // flags |
| 1872 | 1840 | null, // derived from |
| 1873 | 1841 | &fields, |
| ... | ... | @@ -1878,15 +1846,15 @@ pub const Object = struct { |
| 1878 | 1846 | ); |
| 1879 | 1847 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 1880 | 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 | 1850 | return full_di_ty; |
| 1883 | 1851 | }, |
| 1884 | 1852 | .ErrorUnion => { |
| 1885 | const payload_ty = ty.errorUnionPayload(); | |
| 1886 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1853 | const payload_ty = ty.errorUnionPayload(mod); | |
| 1854 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1887 | 1855 | const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full); |
| 1888 | 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 | 1858 | return err_set_di_ty; |
| 1891 | 1859 | } |
| 1892 | 1860 | const name = try ty.nameAlloc(gpa, o.module); |
| ... | ... | @@ -1907,10 +1875,10 @@ pub const Object = struct { |
| 1907 | 1875 | break :blk fwd_decl; |
| 1908 | 1876 | }; |
| 1909 | 1877 | |
| 1910 | const error_size = Type.anyerror.abiSize(target); | |
| 1911 | const error_align = Type.anyerror.abiAlignment(target); | |
| 1912 | const payload_size = payload_ty.abiSize(target); | |
| 1913 | const payload_align = payload_ty.abiAlignment(target); | |
| 1878 | const error_size = Type.anyerror.abiSize(mod); | |
| 1879 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 1880 | const payload_size = payload_ty.abiSize(mod); | |
| 1881 | const payload_align = payload_ty.abiAlignment(mod); | |
| 1914 | 1882 | |
| 1915 | 1883 | var error_index: u32 = undefined; |
| 1916 | 1884 | var payload_index: u32 = undefined; |
| ... | ... | @@ -1957,8 +1925,8 @@ pub const Object = struct { |
| 1957 | 1925 | name.ptr, |
| 1958 | 1926 | di_file, |
| 1959 | 1927 | line, |
| 1960 | ty.abiSize(target) * 8, // size in bits | |
| 1961 | ty.abiAlignment(target) * 8, // align in bits | |
| 1928 | ty.abiSize(mod) * 8, // size in bits | |
| 1929 | ty.abiAlignment(mod) * 8, // align in bits | |
| 1962 | 1930 | 0, // flags |
| 1963 | 1931 | null, // derived from |
| 1964 | 1932 | &fields, |
| ... | ... | @@ -1969,7 +1937,7 @@ pub const Object = struct { |
| 1969 | 1937 | ); |
| 1970 | 1938 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 1971 | 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 | 1941 | return full_di_ty; |
| 1974 | 1942 | }, |
| 1975 | 1943 | .ErrorSet => { |
| ... | ... | @@ -1984,16 +1952,15 @@ pub const Object = struct { |
| 1984 | 1952 | const name = try ty.nameAlloc(gpa, o.module); |
| 1985 | 1953 | defer gpa.free(name); |
| 1986 | 1954 | |
| 1987 | if (ty.castTag(.@"struct")) |payload| { | |
| 1988 | const struct_obj = payload.data; | |
| 1955 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 1989 | 1956 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { |
| 1990 | 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 | 1959 | const dwarf_encoding: c_uint = switch (info.signedness) { |
| 1993 | 1960 | .signed => DW.ATE.signed, |
| 1994 | 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 | 1964 | const di_ty = dib.createBasicType(name, di_bits, dwarf_encoding); |
| 1998 | 1965 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| 1999 | 1966 | return di_ty; |
| ... | ... | @@ -2013,98 +1980,98 @@ pub const Object = struct { |
| 2013 | 1980 | break :blk fwd_decl; |
| 2014 | 1981 | }; |
| 2015 | 1982 | |
| 2016 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 2017 | const tuple = ty.tupleFields(); | |
| 2018 | ||
| 2019 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | |
| 2020 | defer di_fields.deinit(gpa); | |
| 2021 | ||
| 2022 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 2023 | ||
| 2024 | comptime assert(struct_layout_version == 2); | |
| 2025 | var offset: u64 = 0; | |
| 2026 | ||
| 2027 | for (tuple.types, 0..) |field_ty, i| { | |
| 2028 | const field_val = tuple.values[i]; | |
| 2029 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; | |
| 2030 | ||
| 2031 | const field_size = field_ty.abiSize(target); | |
| 2032 | const field_align = field_ty.abiAlignment(target); | |
| 2033 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 2034 | offset = field_offset + field_size; | |
| 2035 | ||
| 2036 | const field_name = if (ty.castTag(.anon_struct)) |payload| | |
| 2037 | try gpa.dupeZ(u8, payload.data.names[i]) | |
| 2038 | else | |
| 2039 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); | |
| 2040 | defer gpa.free(field_name); | |
| 1983 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1984 | .anon_struct_type => |tuple| { | |
| 1985 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | |
| 1986 | defer di_fields.deinit(gpa); | |
| 1987 | ||
| 1988 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 1989 | ||
| 1990 | comptime assert(struct_layout_version == 2); | |
| 1991 | var offset: u64 = 0; | |
| 1992 | ||
| 1993 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 1994 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 1995 | ||
| 1996 | const field_size = field_ty.toType().abiSize(mod); | |
| 1997 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 1998 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 1999 | offset = field_offset + field_size; | |
| 2000 | ||
| 2001 | const field_name = if (tuple.names.len != 0) | |
| 2002 | mod.intern_pool.stringToSlice(tuple.names[i]) | |
| 2003 | else | |
| 2004 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); | |
| 2005 | defer if (tuple.names.len == 0) gpa.free(field_name); | |
| 2006 | ||
| 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( | |
| 2043 | fwd_decl.toScope(), | |
| 2044 | field_name, | |
| 2020 | const full_di_ty = dib.createStructType( | |
| 2021 | compile_unit_scope, | |
| 2022 | name.ptr, | |
| 2045 | 2023 | null, // file |
| 2046 | 2024 | 0, // line |
| 2047 | field_size * 8, // size in bits | |
| 2048 | field_align * 8, // align in bits | |
| 2049 | field_offset * 8, // offset in bits | |
| 2025 | ty.abiSize(mod) * 8, // size in bits | |
| 2026 | ty.abiAlignment(mod) * 8, // align in bits | |
| 2050 | 2027 | 0, // flags |
| 2051 | try o.lowerDebugType(field_ty, .full), | |
| 2052 | )); | |
| 2053 | } | |
| 2054 | ||
| 2055 | const full_di_ty = dib.createStructType( | |
| 2056 | compile_unit_scope, | |
| 2057 | name.ptr, | |
| 2058 | null, // file | |
| 2059 | 0, // line | |
| 2060 | ty.abiSize(target) * 8, // size in bits | |
| 2061 | ty.abiAlignment(target) * 8, // align in bits | |
| 2062 | 0, // flags | |
| 2063 | null, // derived from | |
| 2064 | di_fields.items.ptr, | |
| 2065 | @intCast(c_int, di_fields.items.len), | |
| 2066 | 0, // run time lang | |
| 2067 | null, // vtable holder | |
| 2068 | "", // unique id | |
| 2069 | ); | |
| 2070 | dib.replaceTemporary(fwd_decl, full_di_ty); | |
| 2071 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | |
| 2072 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | |
| 2073 | return full_di_ty; | |
| 2074 | } | |
| 2075 | ||
| 2076 | if (ty.castTag(.@"struct")) |payload| { | |
| 2077 | const struct_obj = payload.data; | |
| 2078 | if (!struct_obj.haveFieldTypes()) { | |
| 2079 | // This can happen if a struct type makes it all the way to | |
| 2080 | // flush() without ever being instantiated or referenced (even | |
| 2081 | // via pointer). The only reason we are hearing about it now is | |
| 2082 | // that it is being used as a namespace to put other debug types | |
| 2083 | // into. Therefore we can satisfy this by making an empty namespace, | |
| 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 | } | |
| 2028 | null, // derived from | |
| 2029 | di_fields.items.ptr, | |
| 2030 | @intCast(c_int, di_fields.items.len), | |
| 2031 | 0, // run time lang | |
| 2032 | null, // vtable holder | |
| 2033 | "", // unique id | |
| 2034 | ); | |
| 2035 | dib.replaceTemporary(fwd_decl, full_di_ty); | |
| 2036 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | |
| 2037 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); | |
| 2038 | return full_di_ty; | |
| 2039 | }, | |
| 2040 | .struct_type => |struct_type| s: { | |
| 2041 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; | |
| 2042 | ||
| 2043 | if (!struct_obj.haveFieldTypes()) { | |
| 2044 | // This can happen if a struct type makes it all the way to | |
| 2045 | // flush() without ever being instantiated or referenced (even | |
| 2046 | // via pointer). The only reason we are hearing about it now is | |
| 2047 | // that it is being used as a namespace to put other debug types | |
| 2048 | // into. Therefore we can satisfy this by making an empty namespace, | |
| 2049 | // rather than changing the frontend to unnecessarily resolve the | |
| 2050 | // struct field types. | |
| 2051 | const owner_decl_index = ty.getOwnerDecl(mod); | |
| 2052 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | |
| 2053 | dib.replaceTemporary(fwd_decl, struct_di_ty); | |
| 2054 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | |
| 2055 | // means we can't use `gop` anymore. | |
| 2056 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(struct_di_ty)); | |
| 2057 | return struct_di_ty; | |
| 2058 | } | |
| 2059 | }, | |
| 2060 | else => {}, | |
| 2094 | 2061 | } |
| 2095 | 2062 | |
| 2096 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2097 | const owner_decl_index = ty.getOwnerDecl(); | |
| 2063 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2064 | const owner_decl_index = ty.getOwnerDecl(mod); | |
| 2098 | 2065 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); |
| 2099 | 2066 | dib.replaceTemporary(fwd_decl, struct_di_ty); |
| 2100 | 2067 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2101 | 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 | 2070 | return struct_di_ty; |
| 2104 | 2071 | } |
| 2105 | 2072 | |
| 2106 | const fields = ty.structFields(); | |
| 2107 | const layout = ty.containerLayout(); | |
| 2073 | const fields = ty.structFields(mod); | |
| 2074 | const layout = ty.containerLayout(mod); | |
| 2108 | 2075 | |
| 2109 | 2076 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; |
| 2110 | 2077 | defer di_fields.deinit(gpa); |
| ... | ... | @@ -2114,16 +2081,15 @@ pub const Object = struct { |
| 2114 | 2081 | comptime assert(struct_layout_version == 2); |
| 2115 | 2082 | var offset: u64 = 0; |
| 2116 | 2083 | |
| 2117 | var it = ty.castTag(.@"struct").?.data.runtimeFieldIterator(); | |
| 2084 | var it = mod.typeToStruct(ty).?.runtimeFieldIterator(mod); | |
| 2118 | 2085 | while (it.next()) |field_and_index| { |
| 2119 | 2086 | const field = field_and_index.field; |
| 2120 | const field_size = field.ty.abiSize(target); | |
| 2121 | const field_align = field.alignment(target, layout); | |
| 2087 | const field_size = field.ty.abiSize(mod); | |
| 2088 | const field_align = field.alignment(mod, layout); | |
| 2122 | 2089 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2123 | 2090 | offset = field_offset + field_size; |
| 2124 | 2091 | |
| 2125 | const field_name = try gpa.dupeZ(u8, fields.keys()[field_and_index.index]); | |
| 2126 | defer gpa.free(field_name); | |
| 2092 | const field_name = mod.intern_pool.stringToSlice(fields.keys()[field_and_index.index]); | |
| 2127 | 2093 | |
| 2128 | 2094 | try di_fields.append(gpa, dib.createMemberType( |
| 2129 | 2095 | fwd_decl.toScope(), |
| ... | ... | @@ -2143,8 +2109,8 @@ pub const Object = struct { |
| 2143 | 2109 | name.ptr, |
| 2144 | 2110 | null, // file |
| 2145 | 2111 | 0, // line |
| 2146 | ty.abiSize(target) * 8, // size in bits | |
| 2147 | ty.abiAlignment(target) * 8, // align in bits | |
| 2112 | ty.abiSize(mod) * 8, // size in bits | |
| 2113 | ty.abiAlignment(mod) * 8, // align in bits | |
| 2148 | 2114 | 0, // flags |
| 2149 | 2115 | null, // derived from |
| 2150 | 2116 | di_fields.items.ptr, |
| ... | ... | @@ -2155,12 +2121,12 @@ pub const Object = struct { |
| 2155 | 2121 | ); |
| 2156 | 2122 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 2157 | 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 | 2125 | return full_di_ty; |
| 2160 | 2126 | }, |
| 2161 | 2127 | .Union => { |
| 2162 | 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 | 2131 | const name = try ty.nameAlloc(gpa, o.module); |
| 2166 | 2132 | defer gpa.free(name); |
| ... | ... | @@ -2178,17 +2144,17 @@ pub const Object = struct { |
| 2178 | 2144 | break :blk fwd_decl; |
| 2179 | 2145 | }; |
| 2180 | 2146 | |
| 2181 | const union_obj = ty.cast(Type.Payload.Union).?.data; | |
| 2182 | if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2147 | const union_obj = mod.typeToUnion(ty).?; | |
| 2148 | if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2183 | 2149 | const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); |
| 2184 | 2150 | dib.replaceTemporary(fwd_decl, union_di_ty); |
| 2185 | 2151 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2186 | 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 | 2154 | return union_di_ty; |
| 2189 | 2155 | } |
| 2190 | 2156 | |
| 2191 | const layout = ty.unionGetLayout(target); | |
| 2157 | const layout = ty.unionGetLayout(mod); | |
| 2192 | 2158 | |
| 2193 | 2159 | if (layout.payload_size == 0) { |
| 2194 | 2160 | const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full); |
| ... | ... | @@ -2198,8 +2164,8 @@ pub const Object = struct { |
| 2198 | 2164 | name.ptr, |
| 2199 | 2165 | null, // file |
| 2200 | 2166 | 0, // line |
| 2201 | ty.abiSize(target) * 8, // size in bits | |
| 2202 | ty.abiAlignment(target) * 8, // align in bits | |
| 2167 | ty.abiSize(mod) * 8, // size in bits | |
| 2168 | ty.abiAlignment(mod) * 8, // align in bits | |
| 2203 | 2169 | 0, // flags |
| 2204 | 2170 | null, // derived from |
| 2205 | 2171 | &di_fields, |
| ... | ... | @@ -2211,7 +2177,7 @@ pub const Object = struct { |
| 2211 | 2177 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 2212 | 2178 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2213 | 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 | 2181 | return full_di_ty; |
| 2216 | 2182 | } |
| 2217 | 2183 | |
| ... | ... | @@ -2225,24 +2191,22 @@ pub const Object = struct { |
| 2225 | 2191 | const field_name = kv.key_ptr.*; |
| 2226 | 2192 | const field = kv.value_ptr.*; |
| 2227 | 2193 | |
| 2228 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2229 | ||
| 2230 | const field_size = field.ty.abiSize(target); | |
| 2231 | const field_align = field.normalAlignment(target); | |
| 2194 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 2232 | 2195 | |
| 2233 | const field_name_copy = try gpa.dupeZ(u8, field_name); | |
| 2234 | defer gpa.free(field_name_copy); | |
| 2196 | const field_size = field.ty.abiSize(mod); | |
| 2197 | const field_align = field.normalAlignment(mod); | |
| 2235 | 2198 | |
| 2199 | const field_di_ty = try o.lowerDebugType(field.ty, .full); | |
| 2236 | 2200 | di_fields.appendAssumeCapacity(dib.createMemberType( |
| 2237 | 2201 | fwd_decl.toScope(), |
| 2238 | field_name_copy, | |
| 2202 | mod.intern_pool.stringToSlice(field_name), | |
| 2239 | 2203 | null, // file |
| 2240 | 2204 | 0, // line |
| 2241 | 2205 | field_size * 8, // size in bits |
| 2242 | 2206 | field_align * 8, // align in bits |
| 2243 | 2207 | 0, // offset in bits |
| 2244 | 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 | 2222 | union_name.ptr, |
| 2259 | 2223 | null, // file |
| 2260 | 2224 | 0, // line |
| 2261 | ty.abiSize(target) * 8, // size in bits | |
| 2262 | ty.abiAlignment(target) * 8, // align in bits | |
| 2225 | ty.abiSize(mod) * 8, // size in bits | |
| 2226 | ty.abiAlignment(mod) * 8, // align in bits | |
| 2263 | 2227 | 0, // flags |
| 2264 | 2228 | di_fields.items.ptr, |
| 2265 | 2229 | @intCast(c_int, di_fields.items.len), |
| ... | ... | @@ -2270,7 +2234,7 @@ pub const Object = struct { |
| 2270 | 2234 | if (layout.tag_size == 0) { |
| 2271 | 2235 | dib.replaceTemporary(fwd_decl, union_di_ty); |
| 2272 | 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 | 2238 | return union_di_ty; |
| 2275 | 2239 | } |
| 2276 | 2240 | |
| ... | ... | @@ -2319,8 +2283,8 @@ pub const Object = struct { |
| 2319 | 2283 | name.ptr, |
| 2320 | 2284 | null, // file |
| 2321 | 2285 | 0, // line |
| 2322 | ty.abiSize(target) * 8, // size in bits | |
| 2323 | ty.abiAlignment(target) * 8, // align in bits | |
| 2286 | ty.abiSize(mod) * 8, // size in bits | |
| 2287 | ty.abiAlignment(mod) * 8, // align in bits | |
| 2324 | 2288 | 0, // flags |
| 2325 | 2289 | null, // derived from |
| 2326 | 2290 | &full_di_fields, |
| ... | ... | @@ -2331,53 +2295,42 @@ pub const Object = struct { |
| 2331 | 2295 | ); |
| 2332 | 2296 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 2333 | 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 | 2299 | return full_di_ty; |
| 2336 | 2300 | }, |
| 2337 | 2301 | .Fn => { |
| 2338 | const fn_info = ty.fnInfo(); | |
| 2302 | const fn_info = mod.typeToFunc(ty).?; | |
| 2339 | 2303 | |
| 2340 | 2304 | var param_di_types = std.ArrayList(*llvm.DIType).init(gpa); |
| 2341 | 2305 | defer param_di_types.deinit(); |
| 2342 | 2306 | |
| 2343 | 2307 | // Return type goes first. |
| 2344 | if (fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { | |
| 2345 | const sret = firstParamSRet(fn_info, target); | |
| 2346 | const di_ret_ty = if (sret) Type.void else fn_info.return_type; | |
| 2308 | if (fn_info.return_type.toType().hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2309 | const sret = firstParamSRet(fn_info, mod); | |
| 2310 | const di_ret_ty = if (sret) Type.void else fn_info.return_type.toType(); | |
| 2347 | 2311 | try param_di_types.append(try o.lowerDebugType(di_ret_ty, .full)); |
| 2348 | 2312 | |
| 2349 | 2313 | if (sret) { |
| 2350 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 2351 | .base = .{ .tag = .single_mut_pointer }, | |
| 2352 | .data = fn_info.return_type, | |
| 2353 | }; | |
| 2354 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 2314 | const ptr_ty = try mod.singleMutPtrType(fn_info.return_type.toType()); | |
| 2355 | 2315 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); |
| 2356 | 2316 | } |
| 2357 | 2317 | } else { |
| 2358 | 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 | 2322 | o.module.comp.bin_file.options.error_return_tracing) |
| 2363 | 2323 | { |
| 2364 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 2365 | .base = .{ .tag = .single_mut_pointer }, | |
| 2366 | .data = o.getStackTraceType(), | |
| 2367 | }; | |
| 2368 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 2324 | const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); | |
| 2369 | 2325 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); |
| 2370 | 2326 | } |
| 2371 | 2327 | |
| 2372 | for (fn_info.param_types) |param_ty| { | |
| 2373 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 2328 | for (0..mod.typeToFunc(ty).?.param_types.len) |i| { | |
| 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)) { | |
| 2376 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 2377 | .base = .{ .tag = .single_mut_pointer }, | |
| 2378 | .data = param_ty, | |
| 2379 | }; | |
| 2380 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 2332 | if (isByRef(param_ty, mod)) { | |
| 2333 | const ptr_ty = try mod.singleMutPtrType(param_ty); | |
| 2381 | 2334 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); |
| 2382 | 2335 | } else { |
| 2383 | 2336 | try param_di_types.append(try o.lowerDebugType(param_ty, .full)); |
| ... | ... | @@ -2390,7 +2343,7 @@ pub const Object = struct { |
| 2390 | 2343 | 0, |
| 2391 | 2344 | ); |
| 2392 | 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 | 2347 | return fn_di_ty; |
| 2395 | 2348 | }, |
| 2396 | 2349 | .ComptimeInt => unreachable, |
| ... | ... | @@ -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 { | |
| 2409 | if (namespace.parent == null) { | |
| 2361 | fn namespaceToDebugScope(o: *Object, namespace_index: Module.Namespace.Index) !*llvm.DIScope { | |
| 2362 | const mod = o.module; | |
| 2363 | const namespace = mod.namespacePtr(namespace_index); | |
| 2364 | if (namespace.parent == .none) { | |
| 2410 | 2365 | const di_file = try o.getDIFile(o.gpa, namespace.file_scope); |
| 2411 | 2366 | return di_file.toScope(); |
| 2412 | 2367 | } |
| ... | ... | @@ -2418,12 +2373,14 @@ pub const Object = struct { |
| 2418 | 2373 | /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"' |
| 2419 | 2374 | /// when targeting CodeView (Windows). |
| 2420 | 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 | 2378 | const fields: [0]*llvm.DIType = .{}; |
| 2379 | const di_scope = try o.namespaceToDebugScope(decl.src_namespace); | |
| 2423 | 2380 | return o.di_builder.?.createStructType( |
| 2424 | try o.namespaceToDebugScope(decl.src_namespace), | |
| 2425 | decl.name, // TODO use fully qualified name | |
| 2426 | try o.getDIFile(o.gpa, decl.src_namespace.file_scope), | |
| 2381 | di_scope, | |
| 2382 | mod.intern_pool.stringToSlice(decl.name), // TODO use fully qualified name | |
| 2383 | try o.getDIFile(o.gpa, mod.namespacePtr(decl.src_namespace).file_scope), | |
| 2427 | 2384 | decl.src_line + 1, |
| 2428 | 2385 | 0, // size in bits |
| 2429 | 2386 | 0, // align in bits |
| ... | ... | @@ -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 | 2398 | const mod = o.module; |
| 2442 | 2399 | |
| 2443 | 2400 | const std_pkg = mod.main_pkg.table.get("std").?; |
| 2444 | 2401 | const std_file = (mod.importPkg(std_pkg) catch unreachable).file; |
| 2445 | 2402 | |
| 2446 | const builtin_str: []const u8 = "builtin"; | |
| 2447 | const std_namespace = mod.declPtr(std_file.root_decl.unwrap().?).src_namespace; | |
| 2403 | const builtin_str = try mod.intern_pool.getOrPutString(mod.gpa, "builtin"); | |
| 2404 | const std_namespace = mod.namespacePtr(mod.declPtr(std_file.root_decl.unwrap().?).src_namespace); | |
| 2448 | 2405 | const builtin_decl = std_namespace.decls |
| 2449 | 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 | 2409 | // buffer is only used for int_type, `builtin` is a struct. |
| 2453 | const builtin_ty = mod.declPtr(builtin_decl).val.toType(undefined); | |
| 2454 | const builtin_namespace = builtin_ty.getNamespace().?; | |
| 2410 | const builtin_ty = mod.declPtr(builtin_decl).val.toType(); | |
| 2411 | const builtin_namespace = builtin_ty.getNamespace(mod).?; | |
| 2455 | 2412 | const stack_trace_decl_index = builtin_namespace.decls |
| 2456 | 2413 | .getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .mod = mod }).?; |
| 2457 | 2414 | const stack_trace_decl = mod.declPtr(stack_trace_decl_index); |
| 2458 | 2415 | |
| 2459 | 2416 | // Sema should have ensured that StackTrace was analyzed. |
| 2460 | 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 | 2431 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) Error { |
| 2475 | 2432 | @setCold(true); |
| 2476 | 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 | 2436 | self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, "TODO (LLVM): " ++ format, args); |
| 2479 | 2437 | return error.CodegenFail; |
| 2480 | 2438 | } |
| ... | ... | @@ -2484,31 +2442,27 @@ pub const DeclGen = struct { |
| 2484 | 2442 | } |
| 2485 | 2443 | |
| 2486 | 2444 | fn genDecl(dg: *DeclGen) !void { |
| 2445 | const mod = dg.module; | |
| 2487 | 2446 | const decl = dg.decl; |
| 2488 | 2447 | const decl_index = dg.decl_index; |
| 2489 | 2448 | assert(decl.has_tv); |
| 2490 | 2449 | |
| 2491 | log.debug("gen: {s} type: {}, value: {}", .{ | |
| 2492 | decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(), | |
| 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); | |
| 2450 | if (decl.val.getExternFunc(mod)) |extern_func| { | |
| 2451 | _ = try dg.resolveLlvmFunction(extern_func.decl); | |
| 2497 | 2452 | } else { |
| 2498 | const target = dg.module.getTarget(); | |
| 2453 | const target = mod.getTarget(); | |
| 2499 | 2454 | var global = try dg.resolveGlobalDecl(decl_index); |
| 2500 | global.setAlignment(decl.getAlignment(target)); | |
| 2501 | if (decl.@"linksection") |section| global.setSection(section); | |
| 2455 | global.setAlignment(decl.getAlignment(mod)); | |
| 2456 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| global.setSection(s); | |
| 2502 | 2457 | assert(decl.has_tv); |
| 2503 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { | |
| 2504 | const variable = payload.data; | |
| 2458 | const init_val = if (decl.val.getVariable(mod)) |variable| init_val: { | |
| 2505 | 2459 | break :init_val variable.init; |
| 2506 | 2460 | } else init_val: { |
| 2507 | 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) { | |
| 2511 | const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val }); | |
| 2464 | if (init_val != .none) { | |
| 2465 | const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val.toValue() }); | |
| 2512 | 2466 | if (global.globalGetValueType() == llvm_init.typeOf()) { |
| 2513 | 2467 | global.setInitializer(llvm_init); |
| 2514 | 2468 | } else { |
| ... | ... | @@ -2533,7 +2487,8 @@ pub const DeclGen = struct { |
| 2533 | 2487 | new_global.setLinkage(global.getLinkage()); |
| 2534 | 2488 | new_global.setUnnamedAddr(global.getUnnamedAddress()); |
| 2535 | 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 | 2492 | new_global.setInitializer(llvm_init); |
| 2538 | 2493 | // TODO: How should this work then the address space of a global changed? |
| 2539 | 2494 | global.replaceAllUsesWith(new_global); |
| ... | ... | @@ -2545,13 +2500,13 @@ pub const DeclGen = struct { |
| 2545 | 2500 | } |
| 2546 | 2501 | |
| 2547 | 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 | 2505 | const line_number = decl.src_line + 1; |
| 2551 | 2506 | const is_internal_linkage = !dg.module.decl_exports.contains(decl_index); |
| 2552 | 2507 | const di_global = dib.createGlobalVariableExpression( |
| 2553 | 2508 | di_file.toScope(), |
| 2554 | decl.name, | |
| 2509 | mod.intern_pool.stringToSlice(decl.name), | |
| 2555 | 2510 | global.getValueName(), |
| 2556 | 2511 | di_file, |
| 2557 | 2512 | line_number, |
| ... | ... | @@ -2560,7 +2515,7 @@ pub const DeclGen = struct { |
| 2560 | 2515 | ); |
| 2561 | 2516 | |
| 2562 | 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 | 2524 | /// Note that this can be called before the function's semantic analysis has |
| 2570 | 2525 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 2571 | 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 | 2529 | const zig_fn_type = decl.ty; |
| 2574 | 2530 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl_index); |
| 2575 | 2531 | if (gop.found_existing) return gop.value_ptr.*; |
| 2576 | 2532 | |
| 2577 | 2533 | assert(decl.has_tv); |
| 2578 | const fn_info = zig_fn_type.fnInfo(); | |
| 2579 | const target = dg.module.getTarget(); | |
| 2580 | const sret = firstParamSRet(fn_info, target); | |
| 2534 | const fn_info = mod.typeToFunc(zig_fn_type).?; | |
| 2535 | const target = mod.getTarget(); | |
| 2536 | const sret = firstParamSRet(fn_info, mod); | |
| 2581 | 2537 | |
| 2582 | 2538 | const fn_type = try dg.lowerType(zig_fn_type); |
| 2583 | 2539 | |
| 2584 | const fqn = try decl.getFullyQualifiedName(dg.module); | |
| 2585 | defer dg.gpa.free(fqn); | |
| 2540 | const fqn = try decl.getFullyQualifiedName(mod); | |
| 2586 | 2541 | |
| 2587 | 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 | 2544 | gop.value_ptr.* = llvm_fn; |
| 2590 | 2545 | |
| 2591 | const is_extern = decl.isExtern(); | |
| 2546 | const is_extern = decl.isExtern(mod); | |
| 2592 | 2547 | if (!is_extern) { |
| 2593 | 2548 | llvm_fn.setLinkage(.Internal); |
| 2594 | 2549 | llvm_fn.setUnnamedAddr(.True); |
| 2595 | 2550 | } else { |
| 2596 | if (dg.module.getTarget().isWasm()) { | |
| 2597 | dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0)); | |
| 2598 | if (decl.getExternFn().?.lib_name) |lib_name| { | |
| 2599 | const module_name = std.mem.sliceTo(lib_name, 0); | |
| 2600 | if (!std.mem.eql(u8, module_name, "c")) { | |
| 2601 | dg.addFnAttrString(llvm_fn, "wasm-import-module", module_name); | |
| 2551 | if (target.isWasm()) { | |
| 2552 | dg.addFnAttrString(llvm_fn, "wasm-import-name", mod.intern_pool.stringToSlice(decl.name)); | |
| 2553 | if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| { | |
| 2554 | if (!std.mem.eql(u8, lib_name, "c")) { | |
| 2555 | dg.addFnAttrString(llvm_fn, "wasm-import-module", lib_name); | |
| 2602 | 2556 | } |
| 2603 | 2557 | } |
| 2604 | 2558 | } |
| ... | ... | @@ -2608,12 +2562,12 @@ pub const DeclGen = struct { |
| 2608 | 2562 | dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0 |
| 2609 | 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 | 2566 | llvm_fn.addSretAttr(raw_llvm_ret_ty); |
| 2613 | 2567 | } |
| 2614 | 2568 | |
| 2615 | const err_return_tracing = fn_info.return_type.isError() and | |
| 2616 | dg.module.comp.bin_file.options.error_return_tracing; | |
| 2569 | const err_return_tracing = fn_info.return_type.toType().isError(mod) and | |
| 2570 | mod.comp.bin_file.options.error_return_tracing; | |
| 2617 | 2571 | |
| 2618 | 2572 | if (err_return_tracing) { |
| 2619 | 2573 | dg.addArgAttr(llvm_fn, @boolToInt(sret), "nonnull"); |
| ... | ... | @@ -2635,14 +2589,14 @@ pub const DeclGen = struct { |
| 2635 | 2589 | }, |
| 2636 | 2590 | } |
| 2637 | 2591 | |
| 2638 | if (fn_info.alignment != 0) { | |
| 2639 | llvm_fn.setAlignment(fn_info.alignment); | |
| 2592 | if (fn_info.alignment.toByteUnitsOptional()) |a| { | |
| 2593 | llvm_fn.setAlignment(@intCast(c_uint, a)); | |
| 2640 | 2594 | } |
| 2641 | 2595 | |
| 2642 | 2596 | // Function attributes that are independent of analysis results of the function body. |
| 2643 | 2597 | dg.addCommonFnAttributes(llvm_fn); |
| 2644 | 2598 | |
| 2645 | if (fn_info.return_type.isNoReturn()) { | |
| 2599 | if (fn_info.return_type == .noreturn_type) { | |
| 2646 | 2600 | dg.addFnAttr(llvm_fn, "noreturn"); |
| 2647 | 2601 | } |
| 2648 | 2602 | |
| ... | ... | @@ -2655,15 +2609,15 @@ pub const DeclGen = struct { |
| 2655 | 2609 | while (it.next()) |lowering| switch (lowering) { |
| 2656 | 2610 | .byval => { |
| 2657 | 2611 | const param_index = it.zig_index - 1; |
| 2658 | const param_ty = fn_info.param_types[param_index]; | |
| 2659 | if (!isByRef(param_ty)) { | |
| 2612 | const param_ty = fn_info.param_types[param_index].toType(); | |
| 2613 | if (!isByRef(param_ty, mod)) { | |
| 2660 | 2614 | dg.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1); |
| 2661 | 2615 | } |
| 2662 | 2616 | }, |
| 2663 | 2617 | .byref => { |
| 2664 | 2618 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 2665 | const param_llvm_ty = try dg.lowerType(param_ty); | |
| 2666 | const alignment = param_ty.abiAlignment(target); | |
| 2619 | const param_llvm_ty = try dg.lowerType(param_ty.toType()); | |
| 2620 | const alignment = param_ty.toType().abiAlignment(mod); | |
| 2667 | 2621 | dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); |
| 2668 | 2622 | }, |
| 2669 | 2623 | .byref_mut => { |
| ... | ... | @@ -2735,35 +2689,35 @@ pub const DeclGen = struct { |
| 2735 | 2689 | if (gop.found_existing) return gop.value_ptr.*; |
| 2736 | 2690 | errdefer assert(dg.object.decl_map.remove(decl_index)); |
| 2737 | 2691 | |
| 2738 | const decl = dg.module.declPtr(decl_index); | |
| 2739 | const fqn = try decl.getFullyQualifiedName(dg.module); | |
| 2740 | defer dg.gpa.free(fqn); | |
| 2692 | const mod = dg.module; | |
| 2693 | const decl = mod.declPtr(decl_index); | |
| 2694 | const fqn = try decl.getFullyQualifiedName(mod); | |
| 2741 | 2695 | |
| 2742 | const target = dg.module.getTarget(); | |
| 2696 | const target = mod.getTarget(); | |
| 2743 | 2697 | |
| 2744 | 2698 | const llvm_type = try dg.lowerType(decl.ty); |
| 2745 | 2699 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| 2746 | 2700 | |
| 2747 | 2701 | const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace( |
| 2748 | 2702 | llvm_type, |
| 2749 | fqn, | |
| 2703 | mod.intern_pool.stringToSlice(fqn), | |
| 2750 | 2704 | llvm_actual_addrspace, |
| 2751 | 2705 | ); |
| 2752 | 2706 | gop.value_ptr.* = llvm_global; |
| 2753 | 2707 | |
| 2754 | 2708 | // This is needed for declarations created by `@extern`. |
| 2755 | if (decl.isExtern()) { | |
| 2756 | llvm_global.setValueName(decl.name); | |
| 2709 | if (decl.isExtern(mod)) { | |
| 2710 | llvm_global.setValueName(mod.intern_pool.stringToSlice(decl.name)); | |
| 2757 | 2711 | llvm_global.setUnnamedAddr(.False); |
| 2758 | 2712 | llvm_global.setLinkage(.External); |
| 2759 | if (decl.val.castTag(.variable)) |variable| { | |
| 2760 | const single_threaded = dg.module.comp.bin_file.options.single_threaded; | |
| 2761 | if (variable.data.is_threadlocal and !single_threaded) { | |
| 2713 | if (decl.val.getVariable(mod)) |variable| { | |
| 2714 | const single_threaded = mod.comp.bin_file.options.single_threaded; | |
| 2715 | if (variable.is_threadlocal and !single_threaded) { | |
| 2762 | 2716 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 2763 | 2717 | } else { |
| 2764 | 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 | 2722 | } else { |
| 2769 | 2723 | llvm_global.setLinkage(.Internal); |
| ... | ... | @@ -2784,12 +2738,13 @@ pub const DeclGen = struct { |
| 2784 | 2738 | |
| 2785 | 2739 | fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*llvm.Type { |
| 2786 | 2740 | const llvm_ty = try lowerTypeInner(dg, t); |
| 2741 | const mod = dg.module; | |
| 2787 | 2742 | if (std.debug.runtime_safety and false) check: { |
| 2788 | if (t.zigTypeTag() == .Opaque) break :check; | |
| 2789 | if (!t.hasRuntimeBits()) break :check; | |
| 2743 | if (t.zigTypeTag(mod) == .Opaque) break :check; | |
| 2744 | if (!t.hasRuntimeBits(mod)) break :check; | |
| 2790 | 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 | 2748 | const llvm_size = dg.object.target_data.abiSizeOfType(llvm_ty); |
| 2794 | 2749 | if (llvm_size != zig_size) { |
| 2795 | 2750 | log.err("when lowering {}, Zig ABI size = {d} but LLVM ABI size = {d}", .{ |
| ... | ... | @@ -2802,18 +2757,18 @@ pub const DeclGen = struct { |
| 2802 | 2757 | |
| 2803 | 2758 | fn lowerTypeInner(dg: *DeclGen, t: Type) Allocator.Error!*llvm.Type { |
| 2804 | 2759 | const gpa = dg.gpa; |
| 2805 | const target = dg.module.getTarget(); | |
| 2806 | switch (t.zigTypeTag()) { | |
| 2760 | const mod = dg.module; | |
| 2761 | const target = mod.getTarget(); | |
| 2762 | switch (t.zigTypeTag(mod)) { | |
| 2807 | 2763 | .Void, .NoReturn => return dg.context.voidType(), |
| 2808 | 2764 | .Int => { |
| 2809 | const info = t.intInfo(target); | |
| 2765 | const info = t.intInfo(mod); | |
| 2810 | 2766 | assert(info.bits != 0); |
| 2811 | 2767 | return dg.context.intType(info.bits); |
| 2812 | 2768 | }, |
| 2813 | 2769 | .Enum => { |
| 2814 | var buffer: Type.Payload.Bits = undefined; | |
| 2815 | const int_ty = t.intTagType(&buffer); | |
| 2816 | const bit_count = int_ty.intInfo(target).bits; | |
| 2770 | const int_ty = t.intTagType(mod); | |
| 2771 | const bit_count = int_ty.intInfo(mod).bits; | |
| 2817 | 2772 | assert(bit_count != 0); |
| 2818 | 2773 | return dg.context.intType(bit_count); |
| 2819 | 2774 | }, |
| ... | ... | @@ -2827,9 +2782,8 @@ pub const DeclGen = struct { |
| 2827 | 2782 | }, |
| 2828 | 2783 | .Bool => return dg.context.intType(1), |
| 2829 | 2784 | .Pointer => { |
| 2830 | if (t.isSlice()) { | |
| 2831 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 2832 | const ptr_type = t.slicePtrFieldType(&buf); | |
| 2785 | if (t.isSlice(mod)) { | |
| 2786 | const ptr_type = t.slicePtrFieldType(mod); | |
| 2833 | 2787 | |
| 2834 | 2788 | const fields: [2]*llvm.Type = .{ |
| 2835 | 2789 | try dg.lowerType(ptr_type), |
| ... | ... | @@ -2837,49 +2791,41 @@ pub const DeclGen = struct { |
| 2837 | 2791 | }; |
| 2838 | 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 | 2795 | const llvm_addrspace = toLlvmAddressSpace(ptr_info.@"addrspace", target); |
| 2842 | 2796 | return dg.context.pointerType(llvm_addrspace); |
| 2843 | 2797 | }, |
| 2844 | .Opaque => switch (t.tag()) { | |
| 2845 | .@"opaque" => { | |
| 2846 | const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module }); | |
| 2847 | if (gop.found_existing) return gop.value_ptr.*; | |
| 2798 | .Opaque => { | |
| 2799 | if (t.toIntern() == .anyopaque_type) return dg.context.intType(8); | |
| 2848 | 2800 | |
| 2849 | // The Type memory is ephemeral; since we want to store a longer-lived | |
| 2850 | // reference, we need to copy it here. | |
| 2851 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | |
| 2801 | const gop = try dg.object.type_map.getOrPut(gpa, t.toIntern()); | |
| 2802 | if (gop.found_existing) return gop.value_ptr.*; | |
| 2852 | 2803 | |
| 2853 | const opaque_obj = t.castTag(.@"opaque").?.data; | |
| 2854 | const name = try opaque_obj.getFullyQualifiedName(dg.module); | |
| 2855 | defer gpa.free(name); | |
| 2804 | const opaque_type = mod.intern_pool.indexToKey(t.toIntern()).opaque_type; | |
| 2805 | const name = mod.intern_pool.stringToSlice(try mod.opaqueFullyQualifiedName(opaque_type)); | |
| 2856 | 2806 | |
| 2857 | const llvm_struct_ty = dg.context.structCreateNamed(name); | |
| 2858 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | |
| 2859 | return llvm_struct_ty; | |
| 2860 | }, | |
| 2861 | .anyopaque => return dg.context.intType(8), | |
| 2862 | else => unreachable, | |
| 2807 | const llvm_struct_ty = dg.context.structCreateNamed(name); | |
| 2808 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | |
| 2809 | return llvm_struct_ty; | |
| 2863 | 2810 | }, |
| 2864 | 2811 | .Array => { |
| 2865 | const elem_ty = t.childType(); | |
| 2866 | assert(elem_ty.onePossibleValue() == null); | |
| 2812 | const elem_ty = t.childType(mod); | |
| 2813 | if (std.debug.runtime_safety) assert((try elem_ty.onePossibleValue(mod)) == null); | |
| 2867 | 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 | 2816 | return elem_llvm_ty.arrayType(@intCast(c_uint, total_len)); |
| 2870 | 2817 | }, |
| 2871 | 2818 | .Vector => { |
| 2872 | const elem_type = try dg.lowerType(t.childType()); | |
| 2873 | return elem_type.vectorType(t.vectorLen()); | |
| 2819 | const elem_type = try dg.lowerType(t.childType(mod)); | |
| 2820 | return elem_type.vectorType(t.vectorLen(mod)); | |
| 2874 | 2821 | }, |
| 2875 | 2822 | .Optional => { |
| 2876 | var buf: Type.Payload.ElemType = undefined; | |
| 2877 | const child_ty = t.optionalChild(&buf); | |
| 2878 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2823 | const child_ty = t.optionalChild(mod); | |
| 2824 | if (!child_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2879 | 2825 | return dg.context.intType(8); |
| 2880 | 2826 | } |
| 2881 | 2827 | const payload_llvm_ty = try dg.lowerType(child_ty); |
| 2882 | if (t.optionalReprIsPayload()) { | |
| 2828 | if (t.optionalReprIsPayload(mod)) { | |
| 2883 | 2829 | return payload_llvm_ty; |
| 2884 | 2830 | } |
| 2885 | 2831 | |
| ... | ... | @@ -2887,8 +2833,8 @@ pub const DeclGen = struct { |
| 2887 | 2833 | var fields_buf: [3]*llvm.Type = .{ |
| 2888 | 2834 | payload_llvm_ty, dg.context.intType(8), undefined, |
| 2889 | 2835 | }; |
| 2890 | const offset = child_ty.abiSize(target) + 1; | |
| 2891 | const abi_size = t.abiSize(target); | |
| 2836 | const offset = child_ty.abiSize(mod) + 1; | |
| 2837 | const abi_size = t.abiSize(mod); | |
| 2892 | 2838 | const padding = @intCast(c_uint, abi_size - offset); |
| 2893 | 2839 | if (padding == 0) { |
| 2894 | 2840 | return dg.context.structType(&fields_buf, 2, .False); |
| ... | ... | @@ -2897,18 +2843,18 @@ pub const DeclGen = struct { |
| 2897 | 2843 | return dg.context.structType(&fields_buf, 3, .False); |
| 2898 | 2844 | }, |
| 2899 | 2845 | .ErrorUnion => { |
| 2900 | const payload_ty = t.errorUnionPayload(); | |
| 2901 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2846 | const payload_ty = t.errorUnionPayload(mod); | |
| 2847 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2902 | 2848 | return try dg.lowerType(Type.anyerror); |
| 2903 | 2849 | } |
| 2904 | 2850 | const llvm_error_type = try dg.lowerType(Type.anyerror); |
| 2905 | 2851 | const llvm_payload_type = try dg.lowerType(payload_ty); |
| 2906 | 2852 | |
| 2907 | const payload_align = payload_ty.abiAlignment(target); | |
| 2908 | const error_align = Type.anyerror.abiAlignment(target); | |
| 2853 | const payload_align = payload_ty.abiAlignment(mod); | |
| 2854 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 2909 | 2855 | |
| 2910 | const payload_size = payload_ty.abiSize(target); | |
| 2911 | const error_size = Type.anyerror.abiSize(target); | |
| 2856 | const payload_size = payload_ty.abiSize(mod); | |
| 2857 | const error_size = Type.anyerror.abiSize(mod); | |
| 2912 | 2858 | |
| 2913 | 2859 | var fields_buf: [3]*llvm.Type = undefined; |
| 2914 | 2860 | if (error_align > payload_align) { |
| ... | ... | @@ -2941,66 +2887,64 @@ pub const DeclGen = struct { |
| 2941 | 2887 | }, |
| 2942 | 2888 | .ErrorSet => return dg.context.intType(16), |
| 2943 | 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 | 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 | |
| 2948 | // reference, we need to copy it here. | |
| 2949 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | |
| 2893 | const struct_type = switch (mod.intern_pool.indexToKey(t.toIntern())) { | |
| 2894 | .anon_struct_type => |tuple| { | |
| 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()) { | |
| 2952 | const tuple = t.tupleFields(); | |
| 2953 | const llvm_struct_ty = dg.context.structCreateNamed(""); | |
| 2954 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | |
| 2898 | var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{}; | |
| 2899 | defer llvm_field_types.deinit(gpa); | |
| 2955 | 2900 | |
| 2956 | var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{}; | |
| 2957 | defer llvm_field_types.deinit(gpa); | |
| 2901 | try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 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); | |
| 2962 | var offset: u64 = 0; | |
| 2963 | var big_align: u32 = 0; | |
| 2907 | for (tuple.types, tuple.values) |field_ty, field_val| { | |
| 2908 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 2964 | 2909 | |
| 2965 | for (tuple.types, 0..) |field_ty, i| { | |
| 2966 | const field_val = tuple.values[i]; | |
| 2967 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; | |
| 2910 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 2911 | big_align = @max(big_align, field_align); | |
| 2912 | const prev_offset = offset; | |
| 2913 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 2968 | 2914 | |
| 2969 | const field_align = field_ty.abiAlignment(target); | |
| 2970 | big_align = @max(big_align, field_align); | |
| 2971 | const prev_offset = offset; | |
| 2972 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 2915 | const padding_len = offset - prev_offset; | |
| 2916 | if (padding_len > 0) { | |
| 2917 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 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; | |
| 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); | |
| 2923 | offset += field_ty.toType().abiSize(mod); | |
| 2978 | 2924 | } |
| 2979 | const field_llvm_ty = try dg.lowerType(field_ty); | |
| 2980 | try llvm_field_types.append(gpa, field_llvm_ty); | |
| 2981 | ||
| 2982 | offset += field_ty.abiSize(target); | |
| 2983 | } | |
| 2984 | { | |
| 2985 | const prev_offset = offset; | |
| 2986 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 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); | |
| 2925 | { | |
| 2926 | const prev_offset = offset; | |
| 2927 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 2928 | const padding_len = offset - prev_offset; | |
| 2929 | if (padding_len > 0) { | |
| 2930 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 2931 | try llvm_field_types.append(gpa, llvm_array_ty); | |
| 2932 | } | |
| 2991 | 2933 | } |
| 2992 | } | |
| 2993 | 2934 | |
| 2994 | llvm_struct_ty.structSetBody( | |
| 2995 | llvm_field_types.items.ptr, | |
| 2996 | @intCast(c_uint, llvm_field_types.items.len), | |
| 2997 | .False, | |
| 2998 | ); | |
| 2935 | llvm_struct_ty.structSetBody( | |
| 2936 | llvm_field_types.items.ptr, | |
| 2937 | @intCast(c_uint, llvm_field_types.items.len), | |
| 2938 | .False, | |
| 2939 | ); | |
| 2999 | 2940 | |
| 3000 | return llvm_struct_ty; | |
| 3001 | } | |
| 2941 | return llvm_struct_ty; | |
| 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 | 2949 | if (struct_obj.layout == .Packed) { |
| 3006 | 2950 | assert(struct_obj.haveLayout()); |
| ... | ... | @@ -3009,8 +2953,7 @@ pub const DeclGen = struct { |
| 3009 | 2953 | return int_llvm_ty; |
| 3010 | 2954 | } |
| 3011 | 2955 | |
| 3012 | const name = try struct_obj.getFullyQualifiedName(dg.module); | |
| 3013 | defer gpa.free(name); | |
| 2956 | const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(mod)); | |
| 3014 | 2957 | |
| 3015 | 2958 | const llvm_struct_ty = dg.context.structCreateNamed(name); |
| 3016 | 2959 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| ... | ... | @@ -3027,11 +2970,11 @@ pub const DeclGen = struct { |
| 3027 | 2970 | var big_align: u32 = 1; |
| 3028 | 2971 | var any_underaligned_fields = false; |
| 3029 | 2972 | |
| 3030 | var it = struct_obj.runtimeFieldIterator(); | |
| 2973 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 3031 | 2974 | while (it.next()) |field_and_index| { |
| 3032 | 2975 | const field = field_and_index.field; |
| 3033 | const field_align = field.alignment(target, struct_obj.layout); | |
| 3034 | const field_ty_align = field.ty.abiAlignment(target); | |
| 2976 | const field_align = field.alignment(mod, struct_obj.layout); | |
| 2977 | const field_ty_align = field.ty.abiAlignment(mod); | |
| 3035 | 2978 | any_underaligned_fields = any_underaligned_fields or |
| 3036 | 2979 | field_align < field_ty_align; |
| 3037 | 2980 | big_align = @max(big_align, field_align); |
| ... | ... | @@ -3046,7 +2989,7 @@ pub const DeclGen = struct { |
| 3046 | 2989 | const field_llvm_ty = try dg.lowerType(field.ty); |
| 3047 | 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 | 2995 | const prev_offset = offset; |
| ... | ... | @@ -3067,18 +3010,14 @@ pub const DeclGen = struct { |
| 3067 | 3010 | return llvm_struct_ty; |
| 3068 | 3011 | }, |
| 3069 | 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 | 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 | |
| 3074 | // reference, we need to copy it here. | |
| 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; | |
| 3016 | const layout = t.unionGetLayout(mod); | |
| 3017 | const union_obj = mod.typeToUnion(t).?; | |
| 3079 | 3018 | |
| 3080 | 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 | 3021 | const int_llvm_ty = dg.context.intType(bitsize); |
| 3083 | 3022 | gop.value_ptr.* = int_llvm_ty; |
| 3084 | 3023 | return int_llvm_ty; |
| ... | ... | @@ -3090,8 +3029,7 @@ pub const DeclGen = struct { |
| 3090 | 3029 | return enum_tag_llvm_ty; |
| 3091 | 3030 | } |
| 3092 | 3031 | |
| 3093 | const name = try union_obj.getFullyQualifiedName(dg.module); | |
| 3094 | defer gpa.free(name); | |
| 3032 | const name = mod.intern_pool.stringToSlice(try union_obj.getFullyQualifiedName(mod)); | |
| 3095 | 3033 | |
| 3096 | 3034 | const llvm_union_ty = dg.context.structCreateNamed(name); |
| 3097 | 3035 | gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls |
| ... | ... | @@ -3155,25 +3093,21 @@ pub const DeclGen = struct { |
| 3155 | 3093 | } |
| 3156 | 3094 | |
| 3157 | 3095 | fn lowerTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*llvm.Type { |
| 3158 | const target = dg.module.getTarget(); | |
| 3159 | const fn_info = fn_ty.fnInfo(); | |
| 3096 | const mod = dg.module; | |
| 3097 | const fn_info = mod.typeToFunc(fn_ty).?; | |
| 3160 | 3098 | const llvm_ret_ty = try lowerFnRetTy(dg, fn_info); |
| 3161 | 3099 | |
| 3162 | 3100 | var llvm_params = std.ArrayList(*llvm.Type).init(dg.gpa); |
| 3163 | 3101 | defer llvm_params.deinit(); |
| 3164 | 3102 | |
| 3165 | if (firstParamSRet(fn_info, target)) { | |
| 3103 | if (firstParamSRet(fn_info, mod)) { | |
| 3166 | 3104 | try llvm_params.append(dg.context.pointerType(0)); |
| 3167 | 3105 | } |
| 3168 | 3106 | |
| 3169 | if (fn_info.return_type.isError() and | |
| 3170 | dg.module.comp.bin_file.options.error_return_tracing) | |
| 3107 | if (fn_info.return_type.toType().isError(mod) and | |
| 3108 | mod.comp.bin_file.options.error_return_tracing) | |
| 3171 | 3109 | { |
| 3172 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 3173 | .base = .{ .tag = .single_mut_pointer }, | |
| 3174 | .data = dg.object.getStackTraceType(), | |
| 3175 | }; | |
| 3176 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 3110 | const ptr_ty = try mod.singleMutPtrType(try dg.object.getStackTraceType()); | |
| 3177 | 3111 | try llvm_params.append(try dg.lowerType(ptr_ty)); |
| 3178 | 3112 | } |
| 3179 | 3113 | |
| ... | ... | @@ -3181,25 +3115,23 @@ pub const DeclGen = struct { |
| 3181 | 3115 | while (it.next()) |lowering| switch (lowering) { |
| 3182 | 3116 | .no_bits => continue, |
| 3183 | 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 | 3119 | try llvm_params.append(try dg.lowerType(param_ty)); |
| 3186 | 3120 | }, |
| 3187 | 3121 | .byref, .byref_mut => { |
| 3188 | 3122 | try llvm_params.append(dg.context.pointerType(0)); |
| 3189 | 3123 | }, |
| 3190 | 3124 | .abi_sized_int => { |
| 3191 | const param_ty = fn_info.param_types[it.zig_index - 1]; | |
| 3192 | const abi_size = @intCast(c_uint, param_ty.abiSize(target)); | |
| 3125 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); | |
| 3126 | const abi_size = @intCast(c_uint, param_ty.abiSize(mod)); | |
| 3193 | 3127 | try llvm_params.append(dg.context.intType(abi_size * 8)); |
| 3194 | 3128 | }, |
| 3195 | 3129 | .slice => { |
| 3196 | const param_ty = fn_info.param_types[it.zig_index - 1]; | |
| 3197 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 3198 | var opt_buf: Type.Payload.ElemType = undefined; | |
| 3199 | const ptr_ty = if (param_ty.zigTypeTag() == .Optional) | |
| 3200 | param_ty.optionalChild(&opt_buf).slicePtrFieldType(&buf) | |
| 3130 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); | |
| 3131 | const ptr_ty = if (param_ty.zigTypeTag(mod) == .Optional) | |
| 3132 | param_ty.optionalChild(mod).slicePtrFieldType(mod) | |
| 3201 | 3133 | else |
| 3202 | param_ty.slicePtrFieldType(&buf); | |
| 3134 | param_ty.slicePtrFieldType(mod); | |
| 3203 | 3135 | const ptr_llvm_ty = try dg.lowerType(ptr_ty); |
| 3204 | 3136 | const len_llvm_ty = try dg.lowerType(Type.usize); |
| 3205 | 3137 | |
| ... | ... | @@ -3214,8 +3146,8 @@ pub const DeclGen = struct { |
| 3214 | 3146 | try llvm_params.append(dg.context.intType(16)); |
| 3215 | 3147 | }, |
| 3216 | 3148 | .float_array => |count| { |
| 3217 | const param_ty = fn_info.param_types[it.zig_index - 1]; | |
| 3218 | const float_ty = try dg.lowerType(aarch64_c_abi.getFloatArrayType(param_ty).?); | |
| 3149 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); | |
| 3150 | const float_ty = try dg.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, mod).?); | |
| 3219 | 3151 | const field_count = @intCast(c_uint, count); |
| 3220 | 3152 | const arr_ty = float_ty.arrayType(field_count); |
| 3221 | 3153 | try llvm_params.append(arr_ty); |
| ... | ... | @@ -3239,11 +3171,12 @@ pub const DeclGen = struct { |
| 3239 | 3171 | /// being a zero bit type, but it should still be lowered as an i8 in such case. |
| 3240 | 3172 | /// There are other similar cases handled here as well. |
| 3241 | 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 | 3176 | .Opaque => true, |
| 3244 | .Fn => !elem_ty.fnInfo().is_generic, | |
| 3245 | .Array => elem_ty.childType().hasRuntimeBitsIgnoreComptime(), | |
| 3246 | else => elem_ty.hasRuntimeBitsIgnoreComptime(), | |
| 3177 | .Fn => !mod.typeToFunc(elem_ty).?.is_generic, | |
| 3178 | .Array => elem_ty.childType(mod).hasRuntimeBitsIgnoreComptime(mod), | |
| 3179 | else => elem_ty.hasRuntimeBitsIgnoreComptime(mod), | |
| 3247 | 3180 | }; |
| 3248 | 3181 | const llvm_elem_ty = if (lower_elem_ty) |
| 3249 | 3182 | try dg.lowerType(elem_ty) |
| ... | ... | @@ -3254,59 +3187,132 @@ pub const DeclGen = struct { |
| 3254 | 3187 | } |
| 3255 | 3188 | |
| 3256 | 3189 | fn lowerValue(dg: *DeclGen, arg_tv: TypedValue) Error!*llvm.Value { |
| 3190 | const mod = dg.module; | |
| 3191 | const target = mod.getTarget(); | |
| 3257 | 3192 | var tv = arg_tv; |
| 3258 | if (tv.val.castTag(.runtime_value)) |rt| { | |
| 3259 | tv.val = rt.data; | |
| 3193 | switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { | |
| 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 | 3198 | const llvm_type = try dg.lowerType(tv.ty); |
| 3263 | 3199 | return llvm_type.getUndef(); |
| 3264 | 3200 | } |
| 3265 | const target = dg.module.getTarget(); | |
| 3266 | 3201 | |
| 3267 | switch (tv.ty.zigTypeTag()) { | |
| 3268 | .Bool => { | |
| 3269 | const llvm_type = try dg.lowerType(tv.ty); | |
| 3270 | return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(); | |
| 3271 | }, | |
| 3272 | // TODO this duplicates code with Pointer but they should share the handling | |
| 3273 | // of the tv.val.tag() and then Int should do extra constPtrToInt on top | |
| 3274 | .Int => switch (tv.val.tag()) { | |
| 3275 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index), | |
| 3276 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | |
| 3277 | else => { | |
| 3278 | var bigint_space: Value.BigIntSpace = undefined; | |
| 3279 | const bigint = tv.val.toBigInt(&bigint_space, target); | |
| 3280 | const int_info = tv.ty.intInfo(target); | |
| 3281 | assert(int_info.bits != 0); | |
| 3282 | const llvm_type = dg.context.intType(int_info.bits); | |
| 3283 | ||
| 3284 | const unsigned_val = v: { | |
| 3285 | if (bigint.limbs.len == 1) { | |
| 3286 | break :v llvm_type.constInt(bigint.limbs[0], .False); | |
| 3287 | } | |
| 3288 | if (@sizeOf(usize) == @sizeOf(u64)) { | |
| 3289 | break :v llvm_type.constIntOfArbitraryPrecision( | |
| 3290 | @intCast(c_uint, bigint.limbs.len), | |
| 3291 | bigint.limbs.ptr, | |
| 3292 | ); | |
| 3293 | } | |
| 3294 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); | |
| 3295 | }; | |
| 3296 | if (!bigint.positive) { | |
| 3297 | return llvm.constNeg(unsigned_val); | |
| 3298 | } | |
| 3299 | return unsigned_val; | |
| 3202 | const val_key = mod.intern_pool.indexToKey(tv.val.toIntern()); | |
| 3203 | switch (val_key) { | |
| 3204 | .int_type, | |
| 3205 | .ptr_type, | |
| 3206 | .array_type, | |
| 3207 | .vector_type, | |
| 3208 | .opt_type, | |
| 3209 | .anyframe_type, | |
| 3210 | .error_union_type, | |
| 3211 | .simple_type, | |
| 3212 | .struct_type, | |
| 3213 | .anon_struct_type, | |
| 3214 | .union_type, | |
| 3215 | .opaque_type, | |
| 3216 | .enum_type, | |
| 3217 | .func_type, | |
| 3218 | .error_set_type, | |
| 3219 | .inferred_error_set_type, | |
| 3220 | => unreachable, // types, not values | |
| 3221 | ||
| 3222 | .undef, .runtime_value => unreachable, // handled above | |
| 3223 | .simple_value => |simple_value| switch (simple_value) { | |
| 3224 | .undefined, | |
| 3225 | .void, | |
| 3226 | .null, | |
| 3227 | .empty_struct, | |
| 3228 | .@"unreachable", | |
| 3229 | .generic_poison, | |
| 3230 | => unreachable, // non-runtime values | |
| 3231 | .false, .true => { | |
| 3232 | const llvm_type = try dg.lowerType(tv.ty); | |
| 3233 | return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(); | |
| 3300 | 3234 | }, |
| 3301 | 3235 | }, |
| 3302 | .Enum => { | |
| 3303 | var int_buffer: Value.Payload.U64 = undefined; | |
| 3304 | const int_val = tv.enumToInt(&int_buffer); | |
| 3236 | .variable, | |
| 3237 | .enum_literal, | |
| 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 | 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 | 3316 | const llvm_type = dg.context.intType(int_info.bits); |
| 3311 | 3317 | |
| 3312 | 3318 | const unsigned_val = v: { |
| ... | ... | @@ -3326,29 +3332,29 @@ pub const DeclGen = struct { |
| 3326 | 3332 | } |
| 3327 | 3333 | return unsigned_val; |
| 3328 | 3334 | }, |
| 3329 | .Float => { | |
| 3335 | .float => { | |
| 3330 | 3336 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3331 | 3337 | switch (tv.ty.floatBits(target)) { |
| 3332 | 3338 | 16 => { |
| 3333 | const repr = @bitCast(u16, tv.val.toFloat(f16)); | |
| 3339 | const repr = @bitCast(u16, tv.val.toFloat(f16, mod)); | |
| 3334 | 3340 | const llvm_i16 = dg.context.intType(16); |
| 3335 | 3341 | const int = llvm_i16.constInt(repr, .False); |
| 3336 | 3342 | return int.constBitCast(llvm_ty); |
| 3337 | 3343 | }, |
| 3338 | 3344 | 32 => { |
| 3339 | const repr = @bitCast(u32, tv.val.toFloat(f32)); | |
| 3345 | const repr = @bitCast(u32, tv.val.toFloat(f32, mod)); | |
| 3340 | 3346 | const llvm_i32 = dg.context.intType(32); |
| 3341 | 3347 | const int = llvm_i32.constInt(repr, .False); |
| 3342 | 3348 | return int.constBitCast(llvm_ty); |
| 3343 | 3349 | }, |
| 3344 | 3350 | 64 => { |
| 3345 | const repr = @bitCast(u64, tv.val.toFloat(f64)); | |
| 3351 | const repr = @bitCast(u64, tv.val.toFloat(f64, mod)); | |
| 3346 | 3352 | const llvm_i64 = dg.context.intType(64); |
| 3347 | 3353 | const int = llvm_i64.constInt(repr, .False); |
| 3348 | 3354 | return int.constBitCast(llvm_ty); |
| 3349 | 3355 | }, |
| 3350 | 3356 | 80 => { |
| 3351 | const float = tv.val.toFloat(f80); | |
| 3357 | const float = tv.val.toFloat(f80, mod); | |
| 3352 | 3358 | const repr = std.math.break_f80(float); |
| 3353 | 3359 | const llvm_i80 = dg.context.intType(80); |
| 3354 | 3360 | var x = llvm_i80.constInt(repr.exp, .False); |
| ... | ... | @@ -3361,7 +3367,7 @@ pub const DeclGen = struct { |
| 3361 | 3367 | } |
| 3362 | 3368 | }, |
| 3363 | 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 | 3371 | // LLVM seems to require that the lower half of the f128 be placed first |
| 3366 | 3372 | // in the buffer. |
| 3367 | 3373 | if (native_endian == .Big) { |
| ... | ... | @@ -3373,204 +3379,60 @@ pub const DeclGen = struct { |
| 3373 | 3379 | else => unreachable, |
| 3374 | 3380 | } |
| 3375 | 3381 | }, |
| 3376 | .Pointer => switch (tv.val.tag()) { | |
| 3377 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index), | |
| 3378 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | |
| 3379 | .variable => { | |
| 3380 | const decl_index = tv.val.castTag(.variable).?.data.owner_decl; | |
| 3381 | const decl = dg.module.declPtr(decl_index); | |
| 3382 | dg.module.markDeclAlive(decl); | |
| 3383 | ||
| 3384 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | |
| 3385 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | |
| 3386 | ||
| 3387 | const val = try dg.resolveGlobalDecl(decl_index); | |
| 3388 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | |
| 3389 | val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace)) | |
| 3390 | else | |
| 3391 | val; | |
| 3392 | return addrspace_casted_ptr; | |
| 3393 | }, | |
| 3394 | .slice => { | |
| 3395 | const slice = tv.val.castTag(.slice).?.data; | |
| 3396 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 3397 | const fields: [2]*llvm.Value = .{ | |
| 3398 | try dg.lowerValue(.{ | |
| 3399 | .ty = tv.ty.slicePtrFieldType(&buf), | |
| 3400 | .val = slice.ptr, | |
| 3401 | }), | |
| 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, | |
| 3382 | .ptr => |ptr| { | |
| 3383 | const ptr_tv: TypedValue = switch (ptr.len) { | |
| 3384 | .none => tv, | |
| 3385 | else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) }, | |
| 3386 | }; | |
| 3387 | const llvm_ptr_val = switch (ptr.addr) { | |
| 3388 | .decl => |decl| try dg.lowerDeclRefValue(ptr_tv, decl), | |
| 3389 | .mut_decl => |mut_decl| try dg.lowerDeclRefValue(ptr_tv, mut_decl.decl), | |
| 3390 | .int => |int| try dg.lowerIntAsPtr(int.toValue()), | |
| 3391 | .eu_payload, | |
| 3392 | .opt_payload, | |
| 3393 | .elem, | |
| 3394 | .field, | |
| 3395 | => try dg.lowerParentPtr(ptr_tv.val, ptr_tv.ty.ptrInfo(mod).bit_offset % 8 == 0), | |
| 3396 | .comptime_field => unreachable, | |
| 3397 | }; | |
| 3398 | switch (ptr.len) { | |
| 3399 | .none => return llvm_ptr_val, | |
| 3400 | else => { | |
| 3401 | const fields: [2]*llvm.Value = .{ | |
| 3402 | llvm_ptr_val, | |
| 3403 | try dg.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }), | |
| 3404 | }; | |
| 3405 | return dg.context.constStruct(&fields, fields.len, .False); | |
| 3406 | }, | |
| 3407 | } | |
| 3545 | 3408 | }, |
| 3546 | .Optional => { | |
| 3409 | .opt => |opt| { | |
| 3547 | 3410 | comptime assert(optional_layout_version == 3); |
| 3548 | var buf: Type.Payload.ElemType = undefined; | |
| 3549 | const payload_ty = tv.ty.optionalChild(&buf); | |
| 3411 | const payload_ty = tv.ty.optionalChild(mod); | |
| 3550 | 3412 | |
| 3551 | 3413 | const llvm_i8 = dg.context.intType(8); |
| 3552 | const is_pl = !tv.val.isNull(); | |
| 3553 | const non_null_bit = if (is_pl) llvm_i8.constInt(1, .False) else llvm_i8.constNull(); | |
| 3554 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3414 | const non_null_bit = switch (opt.val) { | |
| 3415 | .none => llvm_i8.constNull(), | |
| 3416 | else => llvm_i8.constInt(1, .False), | |
| 3417 | }; | |
| 3418 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3555 | 3419 | return non_null_bit; |
| 3556 | 3420 | } |
| 3557 | 3421 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3558 | if (tv.ty.optionalReprIsPayload()) { | |
| 3559 | if (tv.val.castTag(.opt_payload)) |payload| { | |
| 3560 | return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data }); | |
| 3561 | } else if (is_pl) { | |
| 3562 | return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val }); | |
| 3563 | } else { | |
| 3564 | return llvm_ty.constNull(); | |
| 3565 | } | |
| 3566 | } | |
| 3567 | assert(payload_ty.zigTypeTag() != .Fn); | |
| 3422 | if (tv.ty.optionalReprIsPayload(mod)) return switch (opt.val) { | |
| 3423 | .none => llvm_ty.constNull(), | |
| 3424 | else => |payload| dg.lowerValue(.{ .ty = payload_ty, .val = payload.toValue() }), | |
| 3425 | }; | |
| 3426 | assert(payload_ty.zigTypeTag(mod) != .Fn); | |
| 3568 | 3427 | |
| 3569 | 3428 | const llvm_field_count = llvm_ty.countStructElementTypes(); |
| 3570 | 3429 | var fields_buf: [3]*llvm.Value = undefined; |
| 3571 | 3430 | fields_buf[0] = try dg.lowerValue(.{ |
| 3572 | 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 | 3437 | fields_buf[1] = non_null_bit; |
| 3576 | 3438 | if (llvm_field_count > 2) { |
| ... | ... | @@ -3579,76 +3441,100 @@ pub const DeclGen = struct { |
| 3579 | 3441 | } |
| 3580 | 3442 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); |
| 3581 | 3443 | }, |
| 3582 | .Fn => { | |
| 3583 | const fn_decl_index = switch (tv.val.tag()) { | |
| 3584 | .extern_fn => tv.val.castTag(.extern_fn).?.data.owner_decl, | |
| 3585 | .function => tv.val.castTag(.function).?.data.owner_decl, | |
| 3586 | else => unreachable, | |
| 3587 | }; | |
| 3588 | const fn_decl = dg.module.declPtr(fn_decl_index); | |
| 3589 | dg.module.markDeclAlive(fn_decl); | |
| 3590 | return dg.resolveLlvmFunction(fn_decl_index); | |
| 3591 | }, | |
| 3592 | .ErrorSet => { | |
| 3593 | const llvm_ty = try dg.lowerType(Type.anyerror); | |
| 3594 | switch (tv.val.tag()) { | |
| 3595 | .@"error" => { | |
| 3596 | const err_name = tv.val.castTag(.@"error").?.data.name; | |
| 3597 | const kv = try dg.module.getErrorValue(err_name); | |
| 3598 | return llvm_ty.constInt(kv.value, .False); | |
| 3599 | }, | |
| 3600 | else => { | |
| 3601 | // In this case we are rendering an error union which has a 0 bits payload. | |
| 3602 | return llvm_ty.constNull(); | |
| 3444 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(tv.ty.toIntern())) { | |
| 3445 | .array_type => switch (aggregate.storage) { | |
| 3446 | .bytes => |bytes| return dg.context.constString( | |
| 3447 | bytes.ptr, | |
| 3448 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)), | |
| 3449 | .True, // Don't null terminate. Bytes has the sentinel, if any. | |
| 3450 | ), | |
| 3451 | .elems => |elem_vals| { | |
| 3452 | const elem_ty = tv.ty.childType(mod); | |
| 3453 | const gpa = dg.gpa; | |
| 3454 | const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len); | |
| 3455 | defer gpa.free(llvm_elems); | |
| 3456 | var need_unnamed = false; | |
| 3457 | for (elem_vals, 0..) |elem_val, i| { | |
| 3458 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() }); | |
| 3459 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | |
| 3460 | } | |
| 3461 | if (need_unnamed) { | |
| 3462 | return dg.context.constStruct( | |
| 3463 | llvm_elems.ptr, | |
| 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 | } | |
| 3605 | }, | |
| 3606 | .ErrorUnion => { | |
| 3607 | const payload_type = tv.ty.errorUnionPayload(); | |
| 3608 | const is_pl = tv.val.errorUnionIsPayload(); | |
| 3609 | ||
| 3610 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | |
| 3611 | // We use the error type directly as the type. | |
| 3612 | const err_val = if (!is_pl) tv.val else Value.initTag(.zero); | |
| 3613 | return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val }); | |
| 3614 | } | |
| 3615 | ||
| 3616 | const payload_align = payload_type.abiAlignment(target); | |
| 3617 | const error_align = Type.anyerror.abiAlignment(target); | |
| 3618 | const llvm_error_value = try dg.lowerValue(.{ | |
| 3619 | .ty = Type.anyerror, | |
| 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; | |
| 3475 | .repeated_elem => |val| { | |
| 3476 | const elem_ty = tv.ty.childType(mod); | |
| 3477 | const sentinel = tv.ty.sentinel(mod); | |
| 3478 | const len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3479 | const len_including_sent = len + @boolToInt(sentinel != null); | |
| 3480 | const gpa = dg.gpa; | |
| 3481 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | |
| 3482 | defer gpa.free(llvm_elems); | |
| 3483 | ||
| 3484 | var need_unnamed = false; | |
| 3485 | if (len != 0) { | |
| 3486 | for (llvm_elems[0..len]) |*elem| { | |
| 3487 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val.toValue() }); | |
| 3488 | } | |
| 3489 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3490 | } | |
| 3627 | 3491 | |
| 3628 | const llvm_ty = try dg.lowerType(tv.ty); | |
| 3629 | const llvm_field_count = llvm_ty.countStructElementTypes(); | |
| 3630 | if (llvm_field_count > 2) { | |
| 3631 | assert(llvm_field_count == 3); | |
| 3632 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); | |
| 3633 | } | |
| 3492 | if (sentinel) |sent| { | |
| 3493 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); | |
| 3494 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | |
| 3495 | } | |
| 3634 | 3496 | |
| 3635 | if (error_align > payload_align) { | |
| 3636 | fields_buf[0] = llvm_error_value; | |
| 3637 | fields_buf[1] = llvm_payload_value; | |
| 3638 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | |
| 3639 | } else { | |
| 3640 | fields_buf[0] = llvm_payload_value; | |
| 3641 | fields_buf[1] = llvm_error_value; | |
| 3642 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | |
| 3643 | } | |
| 3644 | }, | |
| 3645 | .Struct => { | |
| 3646 | const llvm_struct_ty = try dg.lowerType(tv.ty); | |
| 3647 | const field_vals = tv.val.castTag(.aggregate).?.data; | |
| 3648 | const gpa = dg.gpa; | |
| 3497 | if (need_unnamed) { | |
| 3498 | return dg.context.constStruct( | |
| 3499 | llvm_elems.ptr, | |
| 3500 | @intCast(c_uint, llvm_elems.len), | |
| 3501 | .True, | |
| 3502 | ); | |
| 3503 | } else { | |
| 3504 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3505 | return llvm_elem_ty.constArray( | |
| 3506 | llvm_elems.ptr, | |
| 3507 | @intCast(c_uint, llvm_elems.len), | |
| 3508 | ); | |
| 3509 | } | |
| 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 | 3538 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; |
| 3653 | 3539 | defer llvm_fields.deinit(gpa); |
| 3654 | 3540 | |
| ... | ... | @@ -3659,11 +3545,11 @@ pub const DeclGen = struct { |
| 3659 | 3545 | var big_align: u32 = 0; |
| 3660 | 3546 | var need_unnamed = false; |
| 3661 | 3547 | |
| 3662 | for (tuple.types, 0..) |field_ty, i| { | |
| 3663 | if (tuple.values[i].tag() != .unreachable_value) continue; | |
| 3664 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 3548 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 3549 | if (field_val != .none) 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 | 3553 | big_align = @max(big_align, field_align); |
| 3668 | 3554 | const prev_offset = offset; |
| 3669 | 3555 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| ... | ... | @@ -3677,15 +3563,15 @@ pub const DeclGen = struct { |
| 3677 | 3563 | } |
| 3678 | 3564 | |
| 3679 | 3565 | const field_llvm_val = try dg.lowerValue(.{ |
| 3680 | .ty = field_ty, | |
| 3681 | .val = field_vals[i], | |
| 3566 | .ty = field_ty.toType(), | |
| 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 | 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 | 3577 | const prev_offset = offset; |
| ... | ... | @@ -3704,132 +3590,142 @@ pub const DeclGen = struct { |
| 3704 | 3590 | .False, |
| 3705 | 3591 | ); |
| 3706 | 3592 | } else { |
| 3593 | const llvm_struct_ty = try dg.lowerType(tv.ty); | |
| 3707 | 3594 | return llvm_struct_ty.constNamedStruct( |
| 3708 | 3595 | llvm_fields.items.ptr, |
| 3709 | 3596 | @intCast(c_uint, llvm_fields.items.len), |
| 3710 | 3597 | ); |
| 3711 | 3598 | } |
| 3712 | } | |
| 3713 | ||
| 3714 | const struct_obj = tv.ty.castTag(.@"struct").?.data; | |
| 3715 | ||
| 3716 | if (struct_obj.layout == .Packed) { | |
| 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; | |
| 3599 | }, | |
| 3600 | .struct_type => |struct_type| { | |
| 3601 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3602 | const llvm_struct_ty = try dg.lowerType(tv.ty); | |
| 3603 | const gpa = dg.gpa; | |
| 3727 | 3604 | |
| 3728 | const non_int_val = try dg.lowerValue(.{ | |
| 3729 | .ty = field.ty, | |
| 3730 | .val = field_val, | |
| 3731 | }); | |
| 3732 | const ty_bit_size = @intCast(u16, field.ty.bitSize(target)); | |
| 3733 | const small_int_ty = dg.context.intType(ty_bit_size); | |
| 3734 | const small_int_val = if (field.ty.isPtrAtRuntime()) | |
| 3735 | non_int_val.constPtrToInt(small_int_ty) | |
| 3736 | else | |
| 3737 | non_int_val.constBitCast(small_int_ty); | |
| 3738 | const shift_rhs = int_llvm_ty.constInt(running_bits, .False); | |
| 3739 | // If the field is as large as the entire packed struct, this | |
| 3740 | // zext would go from, e.g. i16 to i16. This is legal with | |
| 3741 | // constZExtOrBitCast but not legal with constZExt. | |
| 3742 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty); | |
| 3743 | const shifted = extended_int_val.constShl(shift_rhs); | |
| 3744 | running_int = running_int.constOr(shifted); | |
| 3745 | running_bits += ty_bit_size; | |
| 3605 | if (struct_obj.layout == .Packed) { | |
| 3606 | assert(struct_obj.haveLayout()); | |
| 3607 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); | |
| 3608 | const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits)); | |
| 3609 | const fields = struct_obj.fields.values(); | |
| 3610 | comptime assert(Type.packed_struct_layout_version == 2); | |
| 3611 | var running_int: *llvm.Value = int_llvm_ty.constNull(); | |
| 3612 | var running_bits: u16 = 0; | |
| 3613 | for (fields, 0..) |field, i| { | |
| 3614 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3615 | ||
| 3616 | const non_int_val = try dg.lowerValue(.{ | |
| 3617 | .ty = field.ty, | |
| 3618 | .val = try tv.val.fieldValue(mod, i), | |
| 3619 | }); | |
| 3620 | const ty_bit_size = @intCast(u16, field.ty.bitSize(mod)); | |
| 3621 | const small_int_ty = dg.context.intType(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(); | |
| 3751 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); | |
| 3752 | defer llvm_fields.deinit(gpa); | |
| 3638 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); | |
| 3639 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); | |
| 3640 | defer llvm_fields.deinit(gpa); | |
| 3753 | 3641 | |
| 3754 | comptime assert(struct_layout_version == 2); | |
| 3755 | var offset: u64 = 0; | |
| 3756 | var big_align: u32 = 0; | |
| 3757 | var need_unnamed = false; | |
| 3642 | comptime assert(struct_layout_version == 2); | |
| 3643 | var offset: u64 = 0; | |
| 3644 | var big_align: u32 = 0; | |
| 3645 | var need_unnamed = false; | |
| 3758 | 3646 | |
| 3759 | var it = struct_obj.runtimeFieldIterator(); | |
| 3760 | while (it.next()) |field_and_index| { | |
| 3761 | const field = field_and_index.field; | |
| 3762 | const field_align = field.alignment(target, struct_obj.layout); | |
| 3763 | big_align = @max(big_align, field_align); | |
| 3764 | const prev_offset = offset; | |
| 3765 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 3647 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 3648 | while (it.next()) |field_and_index| { | |
| 3649 | const field = field_and_index.field; | |
| 3650 | const field_align = field.alignment(mod, struct_obj.layout); | |
| 3651 | big_align = @max(big_align, field_align); | |
| 3652 | const prev_offset = offset; | |
| 3653 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 3766 | 3654 | |
| 3767 | const padding_len = offset - prev_offset; | |
| 3768 | if (padding_len > 0) { | |
| 3769 | 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 | |
| 3771 | // builds be 0xaa not undef. | |
| 3772 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3773 | } | |
| 3655 | const padding_len = offset - prev_offset; | |
| 3656 | if (padding_len > 0) { | |
| 3657 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3658 | // TODO make this and all other padding elsewhere in debug | |
| 3659 | // builds be 0xaa not undef. | |
| 3660 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3661 | } | |
| 3774 | 3662 | |
| 3775 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3776 | .ty = field.ty, | |
| 3777 | .val = field_vals[field_and_index.index], | |
| 3778 | }); | |
| 3663 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3664 | .ty = field.ty, | |
| 3665 | .val = try tv.val.fieldValue(mod, field_and_index.index), | |
| 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); | |
| 3785 | } | |
| 3786 | { | |
| 3787 | const prev_offset = offset; | |
| 3788 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3789 | const padding_len = offset - prev_offset; | |
| 3790 | if (padding_len > 0) { | |
| 3791 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3792 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3672 | offset += field.ty.abiSize(mod); | |
| 3673 | } | |
| 3674 | { | |
| 3675 | const prev_offset = offset; | |
| 3676 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3677 | const padding_len = offset - prev_offset; | |
| 3678 | if (padding_len > 0) { | |
| 3679 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3680 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3681 | } | |
| 3793 | 3682 | } |
| 3794 | } | |
| 3795 | 3683 | |
| 3796 | if (need_unnamed) { | |
| 3797 | return dg.context.constStruct( | |
| 3798 | llvm_fields.items.ptr, | |
| 3799 | @intCast(c_uint, llvm_fields.items.len), | |
| 3800 | .False, | |
| 3801 | ); | |
| 3802 | } else { | |
| 3803 | return llvm_struct_ty.constNamedStruct( | |
| 3804 | llvm_fields.items.ptr, | |
| 3805 | @intCast(c_uint, llvm_fields.items.len), | |
| 3806 | ); | |
| 3807 | } | |
| 3684 | if (need_unnamed) { | |
| 3685 | return dg.context.constStruct( | |
| 3686 | llvm_fields.items.ptr, | |
| 3687 | @intCast(c_uint, llvm_fields.items.len), | |
| 3688 | .False, | |
| 3689 | ); | |
| 3690 | } else { | |
| 3691 | return llvm_struct_ty.constNamedStruct( | |
| 3692 | llvm_fields.items.ptr, | |
| 3693 | @intCast(c_uint, llvm_fields.items.len), | |
| 3694 | ); | |
| 3695 | } | |
| 3696 | }, | |
| 3697 | else => unreachable, | |
| 3808 | 3698 | }, |
| 3809 | .Union => { | |
| 3699 | .un => { | |
| 3810 | 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 | 3711 | if (layout.payload_size == 0) { |
| 3816 | 3712 | return lowerValue(dg, .{ |
| 3817 | .ty = tv.ty.unionTagTypeSafety().?, | |
| 3713 | .ty = tv.ty.unionTagTypeSafety(mod).?, | |
| 3818 | 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 | 3718 | const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?; |
| 3823 | 3719 | assert(union_obj.haveFieldTypes()); |
| 3824 | 3720 | |
| 3825 | 3721 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 3826 | 3722 | if (union_obj.layout == .Packed) { |
| 3827 | if (!field_ty.hasRuntimeBits()) | |
| 3723 | if (!field_ty.hasRuntimeBits(mod)) | |
| 3828 | 3724 | return llvm_union_ty.constNull(); |
| 3829 | 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 | 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 | 3729 | non_int_val.constPtrToInt(small_int_ty) |
| 3834 | 3730 | else |
| 3835 | 3731 | non_int_val.constBitCast(small_int_ty); |
| ... | ... | @@ -3842,13 +3738,13 @@ pub const DeclGen = struct { |
| 3842 | 3738 | // must pointer cast to the expected type before accessing the union. |
| 3843 | 3739 | var need_unnamed: bool = layout.most_aligned_field != field_index; |
| 3844 | 3740 | const payload = p: { |
| 3845 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 3741 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3846 | 3742 | const padding_len = @intCast(c_uint, layout.payload_size); |
| 3847 | 3743 | break :p dg.context.intType(8).arrayType(padding_len).getUndef(); |
| 3848 | 3744 | } |
| 3849 | 3745 | const field = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); |
| 3850 | 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 | 3748 | if (field_size == layout.payload_size) { |
| 3853 | 3749 | break :p field; |
| 3854 | 3750 | } |
| ... | ... | @@ -3868,7 +3764,7 @@ pub const DeclGen = struct { |
| 3868 | 3764 | } |
| 3869 | 3765 | } |
| 3870 | 3766 | const llvm_tag_value = try lowerValue(dg, .{ |
| 3871 | .ty = tv.ty.unionTagTypeSafety().?, | |
| 3767 | .ty = tv.ty.unionTagTypeSafety(mod).?, | |
| 3872 | 3768 | .val = tag_and_val.tag, |
| 3873 | 3769 | }); |
| 3874 | 3770 | var fields: [3]*llvm.Value = undefined; |
| ... | ... | @@ -3888,107 +3784,45 @@ pub const DeclGen = struct { |
| 3888 | 3784 | return llvm_union_ty.constNamedStruct(&fields, fields_len); |
| 3889 | 3785 | } |
| 3890 | 3786 | }, |
| 3891 | .Vector => switch (tv.val.tag()) { | |
| 3892 | .bytes => { | |
| 3893 | // Note, sentinel is not stored even if the type has a sentinel. | |
| 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 | }; | |
| 3787 | .memoized_call => unreachable, | |
| 3788 | } | |
| 3789 | } | |
| 3964 | 3790 | |
| 3965 | elem.* = try dg.lowerValue(.{ | |
| 3966 | .ty = elem_ty, | |
| 3967 | .val = Value.initPayload(&byte_payload.base), | |
| 3968 | }); | |
| 3969 | } | |
| 3970 | return llvm.constVector( | |
| 3971 | llvm_elems.ptr, | |
| 3972 | @intCast(c_uint, llvm_elems.len), | |
| 3973 | ); | |
| 3974 | }, | |
| 3975 | else => unreachable, | |
| 3791 | fn lowerIntAsPtr(dg: *DeclGen, val: Value) Error!*llvm.Value { | |
| 3792 | switch (dg.module.intern_pool.indexToKey(val.toIntern())) { | |
| 3793 | .undef => return dg.context.pointerType(0).getUndef(), | |
| 3794 | .int => { | |
| 3795 | var bigint_space: Value.BigIntSpace = undefined; | |
| 3796 | const bigint = val.toBigInt(&bigint_space, dg.module); | |
| 3797 | const llvm_int = lowerBigInt(dg, Type.usize, bigint); | |
| 3798 | return llvm_int.constIntToPtr(dg.context.pointerType(0)); | |
| 3976 | 3799 | }, |
| 3800 | else => unreachable, | |
| 3801 | } | |
| 3802 | } | |
| 3977 | 3803 | |
| 3978 | .ComptimeInt => unreachable, | |
| 3979 | .ComptimeFloat => unreachable, | |
| 3980 | .Type => unreachable, | |
| 3981 | .EnumLiteral => unreachable, | |
| 3982 | .Void => unreachable, | |
| 3983 | .NoReturn => unreachable, | |
| 3984 | .Undefined => unreachable, | |
| 3985 | .Null => unreachable, | |
| 3986 | .Opaque => unreachable, | |
| 3804 | fn lowerBigInt(dg: *DeclGen, ty: Type, bigint: std.math.big.int.Const) *llvm.Value { | |
| 3805 | const mod = dg.module; | |
| 3806 | const int_info = ty.intInfo(mod); | |
| 3807 | assert(int_info.bits != 0); | |
| 3808 | const llvm_type = dg.context.intType(int_info.bits); | |
| 3987 | 3809 | |
| 3988 | .Frame, | |
| 3989 | .AnyFrame, | |
| 3990 | => return dg.todo("implement const of type '{}'", .{tv.ty.fmtDebug()}), | |
| 3810 | const unsigned_val = v: { | |
| 3811 | if (bigint.limbs.len == 1) { | |
| 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 | 3828 | const ParentPtr = struct { |
| ... | ... | @@ -4001,57 +3835,86 @@ pub const DeclGen = struct { |
| 4001 | 3835 | ptr_val: Value, |
| 4002 | 3836 | decl_index: Module.Decl.Index, |
| 4003 | 3837 | ) Error!*llvm.Value { |
| 4004 | const decl = dg.module.declPtr(decl_index); | |
| 4005 | dg.module.markDeclAlive(decl); | |
| 4006 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 4007 | .base = .{ .tag = .single_mut_pointer }, | |
| 4008 | .data = decl.ty, | |
| 4009 | }; | |
| 4010 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 3838 | const mod = dg.module; | |
| 3839 | const decl = mod.declPtr(decl_index); | |
| 3840 | try mod.markDeclAlive(decl); | |
| 3841 | const ptr_ty = try mod.singleMutPtrType(decl.ty); | |
| 4011 | 3842 | return try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index); |
| 4012 | 3843 | } |
| 4013 | 3844 | |
| 4014 | 3845 | fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value { |
| 4015 | const target = dg.module.getTarget(); | |
| 4016 | switch (ptr_val.tag()) { | |
| 4017 | .decl_ref_mut => { | |
| 4018 | const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 4019 | return dg.lowerParentPtrDecl(ptr_val, decl); | |
| 4020 | }, | |
| 4021 | .decl_ref => { | |
| 4022 | const decl = ptr_val.castTag(.decl_ref).?.data; | |
| 4023 | return dg.lowerParentPtrDecl(ptr_val, decl); | |
| 4024 | }, | |
| 4025 | .variable => { | |
| 4026 | const decl = ptr_val.castTag(.variable).?.data.owner_decl; | |
| 4027 | return dg.lowerParentPtrDecl(ptr_val, decl); | |
| 3846 | const mod = dg.module; | |
| 3847 | const target = mod.getTarget(); | |
| 3848 | return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { | |
| 3849 | .decl => |decl| dg.lowerParentPtrDecl(ptr_val, decl), | |
| 3850 | .mut_decl => |mut_decl| dg.lowerParentPtrDecl(ptr_val, mut_decl.decl), | |
| 3851 | .int => |int| dg.lowerIntAsPtr(int.toValue()), | |
| 3852 | .eu_payload => |eu_ptr| { | |
| 3853 | const parent_llvm_ptr = try dg.lowerParentPtr(eu_ptr.toValue(), true); | |
| 3854 | ||
| 3855 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); | |
| 3856 | const payload_ty = eu_ty.errorUnionPayload(mod); | |
| 3857 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 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 => { | |
| 4030 | const int = ptr_val.castTag(.int_i64).?.data; | |
| 4031 | const llvm_usize = try dg.lowerType(Type.usize); | |
| 4032 | const llvm_int = llvm_usize.constInt(@bitCast(u64, int), .False); | |
| 4033 | return llvm_int.constIntToPtr(dg.context.pointerType(0)); | |
| 3872 | .opt_payload => |opt_ptr| { | |
| 3873 | const parent_llvm_ptr = try dg.lowerParentPtr(opt_ptr.toValue(), true); | |
| 3874 | ||
| 3875 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); | |
| 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 => { | |
| 4036 | const int = ptr_val.castTag(.int_u64).?.data; | |
| 3893 | .comptime_field => unreachable, | |
| 3894 | .elem => |elem_ptr| { | |
| 3895 | const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.base.toValue(), true); | |
| 3896 | ||
| 4037 | 3897 | const llvm_usize = try dg.lowerType(Type.usize); |
| 4038 | const llvm_int = llvm_usize.constInt(int, .False); | |
| 4039 | return llvm_int.constIntToPtr(dg.context.pointerType(0)); | |
| 3898 | const indices: [1]*llvm.Value = .{ | |
| 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 => { | |
| 4042 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 4043 | const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr, byte_aligned); | |
| 4044 | const parent_ty = field_ptr.container_ty; | |
| 3905 | .field => |field_ptr| { | |
| 3906 | const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.base.toValue(), byte_aligned); | |
| 3907 | const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | |
| 4045 | 3908 | |
| 4046 | const field_index = @intCast(u32, field_ptr.field_index); | |
| 3909 | const field_index = @intCast(u32, field_ptr.index); | |
| 4047 | 3910 | const llvm_u32 = dg.context.intType(32); |
| 4048 | switch (parent_ty.zigTypeTag()) { | |
| 3911 | switch (parent_ty.zigTypeTag(mod)) { | |
| 4049 | 3912 | .Union => { |
| 4050 | if (parent_ty.containerLayout() == .Packed) { | |
| 3913 | if (parent_ty.containerLayout(mod) == .Packed) { | |
| 4051 | 3914 | return parent_llvm_ptr; |
| 4052 | 3915 | } |
| 4053 | 3916 | |
| 4054 | const layout = parent_ty.unionGetLayout(target); | |
| 3917 | const layout = parent_ty.unionGetLayout(mod); | |
| 4055 | 3918 | if (layout.payload_size == 0) { |
| 4056 | 3919 | // In this case a pointer to the union and a pointer to any |
| 4057 | 3920 | // (void) payload is the same. |
| ... | ... | @@ -4069,16 +3932,16 @@ pub const DeclGen = struct { |
| 4069 | 3932 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4070 | 3933 | }, |
| 4071 | 3934 | .Struct => { |
| 4072 | if (parent_ty.containerLayout() == .Packed) { | |
| 3935 | if (parent_ty.containerLayout(mod) == .Packed) { | |
| 4073 | 3936 | if (!byte_aligned) return parent_llvm_ptr; |
| 4074 | 3937 | const llvm_usize = dg.context.intType(target.ptrBitWidth()); |
| 4075 | 3938 | const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); |
| 4076 | 3939 | // count bits of fields before this one |
| 4077 | 3940 | const prev_bits = b: { |
| 4078 | 3941 | var b: usize = 0; |
| 4079 | for (parent_ty.structFields().values()[0..field_index]) |field| { | |
| 4080 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 4081 | b += @intCast(usize, field.ty.bitSize(target)); | |
| 3942 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { | |
| 3943 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3944 | b += @intCast(usize, field.ty.bitSize(mod)); | |
| 4082 | 3945 | } |
| 4083 | 3946 | break :b b; |
| 4084 | 3947 | }; |
| ... | ... | @@ -4088,23 +3951,21 @@ pub const DeclGen = struct { |
| 4088 | 3951 | return field_addr.constIntToPtr(final_llvm_ty); |
| 4089 | 3952 | } |
| 4090 | 3953 | |
| 4091 | var ty_buf: Type.Payload.Pointer = undefined; | |
| 4092 | ||
| 4093 | 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 | 3956 | const indices: [2]*llvm.Value = .{ |
| 4096 | 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 | 3960 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4100 | 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 | 3963 | const indices: [1]*llvm.Value = .{llvm_index}; |
| 4103 | 3964 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4104 | 3965 | } |
| 4105 | 3966 | }, |
| 4106 | 3967 | .Pointer => { |
| 4107 | assert(parent_ty.isSlice()); | |
| 3968 | assert(parent_ty.isSlice(mod)); | |
| 4108 | 3969 | const indices: [2]*llvm.Value = .{ |
| 4109 | 3970 | llvm_u32.constInt(0, .False), |
| 4110 | 3971 | llvm_u32.constInt(field_index, .False), |
| ... | ... | @@ -4115,61 +3976,7 @@ pub const DeclGen = struct { |
| 4115 | 3976 | else => unreachable, |
| 4116 | 3977 | } |
| 4117 | 3978 | }, |
| 4118 | .elem_ptr => { | |
| 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 | } | |
| 3979 | }; | |
| 4173 | 3980 | } |
| 4174 | 3981 | |
| 4175 | 3982 | fn lowerDeclRefValue( |
| ... | ... | @@ -4177,57 +3984,39 @@ pub const DeclGen = struct { |
| 4177 | 3984 | tv: TypedValue, |
| 4178 | 3985 | decl_index: Module.Decl.Index, |
| 4179 | 3986 | ) Error!*llvm.Value { |
| 4180 | if (tv.ty.isSlice()) { | |
| 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 | } | |
| 3987 | const mod = self.module; | |
| 4199 | 3988 | |
| 4200 | 3989 | // In the case of something like: |
| 4201 | 3990 | // fn foo() void {} |
| 4202 | 3991 | // const bar = foo; |
| 4203 | 3992 | // ... &bar; |
| 4204 | 3993 | // `bar` is just an alias and we actually want to lower a reference to `foo`. |
| 4205 | const decl = self.module.declPtr(decl_index); | |
| 4206 | if (decl.val.castTag(.function)) |func| { | |
| 4207 | if (func.data.owner_decl != decl_index) { | |
| 4208 | return self.lowerDeclRefValue(tv, func.data.owner_decl); | |
| 3994 | const decl = mod.declPtr(decl_index); | |
| 3995 | if (decl.val.getFunction(mod)) |func| { | |
| 3996 | if (func.owner_decl != decl_index) { | |
| 3997 | return self.lowerDeclRefValue(tv, func.owner_decl); | |
| 4209 | 3998 | } |
| 4210 | } else if (decl.val.castTag(.extern_fn)) |func| { | |
| 4211 | if (func.data.owner_decl != decl_index) { | |
| 4212 | return self.lowerDeclRefValue(tv, func.data.owner_decl); | |
| 3999 | } else if (decl.val.getExternFunc(mod)) |func| { | |
| 4000 | if (func.decl != decl_index) { | |
| 4001 | return self.lowerDeclRefValue(tv, func.decl); | |
| 4213 | 4002 | } |
| 4214 | 4003 | } |
| 4215 | 4004 | |
| 4216 | const is_fn_body = decl.ty.zigTypeTag() == .Fn; | |
| 4217 | if ((!is_fn_body and !decl.ty.hasRuntimeBits()) or | |
| 4218 | (is_fn_body and decl.ty.fnInfo().is_generic)) | |
| 4005 | const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn; | |
| 4006 | if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or | |
| 4007 | (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) | |
| 4219 | 4008 | { |
| 4220 | 4009 | return self.lowerPtrToVoid(tv.ty); |
| 4221 | 4010 | } |
| 4222 | 4011 | |
| 4223 | self.module.markDeclAlive(decl); | |
| 4012 | try mod.markDeclAlive(decl); | |
| 4224 | 4013 | |
| 4225 | 4014 | const llvm_decl_val = if (is_fn_body) |
| 4226 | 4015 | try self.resolveLlvmFunction(decl_index) |
| 4227 | 4016 | else |
| 4228 | 4017 | try self.resolveGlobalDecl(decl_index); |
| 4229 | 4018 | |
| 4230 | const target = self.module.getTarget(); | |
| 4019 | const target = mod.getTarget(); | |
| 4231 | 4020 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 4232 | 4021 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| 4233 | 4022 | const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: { |
| ... | ... | @@ -4236,7 +4025,7 @@ pub const DeclGen = struct { |
| 4236 | 4025 | } else llvm_decl_val; |
| 4237 | 4026 | |
| 4238 | 4027 | const llvm_type = try self.lowerType(tv.ty); |
| 4239 | if (tv.ty.zigTypeTag() == .Int) { | |
| 4028 | if (tv.ty.zigTypeTag(mod) == .Int) { | |
| 4240 | 4029 | return llvm_val.constPtrToInt(llvm_type); |
| 4241 | 4030 | } else { |
| 4242 | 4031 | return llvm_val.constBitCast(llvm_type); |
| ... | ... | @@ -4244,7 +4033,8 @@ pub const DeclGen = struct { |
| 4244 | 4033 | } |
| 4245 | 4034 | |
| 4246 | 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 | 4038 | // Even though we are pointing at something which has zero bits (e.g. `void`), |
| 4249 | 4039 | // Pointers are defined to have bits. So we must return something here. |
| 4250 | 4040 | // The value cannot be undefined, because we use the `nonnull` annotation |
| ... | ... | @@ -4338,21 +4128,20 @@ pub const DeclGen = struct { |
| 4338 | 4128 | /// RMW exchange of floating-point values is bitcasted to same-sized integer |
| 4339 | 4129 | /// types to work around a LLVM deficiency when targeting ARM/AArch64. |
| 4340 | 4130 | fn getAtomicAbiType(dg: *DeclGen, ty: Type, is_rmw_xchg: bool) ?*llvm.Type { |
| 4341 | const target = dg.module.getTarget(); | |
| 4342 | var buffer: Type.Payload.Bits = undefined; | |
| 4343 | const int_ty = switch (ty.zigTypeTag()) { | |
| 4131 | const mod = dg.module; | |
| 4132 | const int_ty = switch (ty.zigTypeTag(mod)) { | |
| 4344 | 4133 | .Int => ty, |
| 4345 | .Enum => ty.intTagType(&buffer), | |
| 4134 | .Enum => ty.intTagType(mod), | |
| 4346 | 4135 | .Float => { |
| 4347 | 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 | 4139 | .Bool => return dg.context.intType(8), |
| 4351 | 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 | 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 | 4145 | } else { |
| 4357 | 4146 | return null; |
| 4358 | 4147 | } |
| ... | ... | @@ -4363,18 +4152,18 @@ pub const DeclGen = struct { |
| 4363 | 4152 | llvm_fn: *llvm.Value, |
| 4364 | 4153 | param_ty: Type, |
| 4365 | 4154 | param_index: u32, |
| 4366 | fn_info: Type.Payload.Function.Data, | |
| 4155 | fn_info: InternPool.Key.FuncType, | |
| 4367 | 4156 | llvm_arg_i: u32, |
| 4368 | 4157 | ) void { |
| 4369 | const target = dg.module.getTarget(); | |
| 4370 | if (param_ty.isPtrAtRuntime()) { | |
| 4371 | const ptr_info = param_ty.ptrInfo().data; | |
| 4158 | const mod = dg.module; | |
| 4159 | if (param_ty.isPtrAtRuntime(mod)) { | |
| 4160 | const ptr_info = param_ty.ptrInfo(mod); | |
| 4372 | 4161 | if (math.cast(u5, param_index)) |i| { |
| 4373 | 4162 | if (@truncate(u1, fn_info.noalias_bits >> i) != 0) { |
| 4374 | 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 | 4167 | dg.addArgAttr(llvm_fn, llvm_arg_i, "nonnull"); |
| 4379 | 4168 | } |
| 4380 | 4169 | if (!ptr_info.mutable) { |
| ... | ... | @@ -4383,13 +4172,10 @@ pub const DeclGen = struct { |
| 4383 | 4172 | if (ptr_info.@"align" != 0) { |
| 4384 | 4173 | dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", ptr_info.@"align"); |
| 4385 | 4174 | } else { |
| 4386 | const elem_align = @max( | |
| 4387 | ptr_info.pointee_type.abiAlignment(target), | |
| 4388 | 1, | |
| 4389 | ); | |
| 4175 | const elem_align = @max(ptr_info.pointee_type.abiAlignment(mod), 1); | |
| 4390 | 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 | 4179 | .signed => dg.addArgAttr(llvm_fn, llvm_arg_i, "signext"), |
| 4394 | 4180 | .unsigned => dg.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"), |
| 4395 | 4181 | }; |
| ... | ... | @@ -4490,21 +4276,23 @@ pub const FuncGen = struct { |
| 4490 | 4276 | const gop = try self.func_inst_table.getOrPut(self.dg.gpa, inst); |
| 4491 | 4277 | if (gop.found_existing) return gop.value_ptr.*; |
| 4492 | 4278 | |
| 4279 | const mod = self.dg.module; | |
| 4493 | 4280 | const llvm_val = try self.resolveValue(.{ |
| 4494 | .ty = self.air.typeOf(inst), | |
| 4495 | .val = self.air.value(inst).?, | |
| 4281 | .ty = self.typeOf(inst), | |
| 4282 | .val = (try self.air.value(inst, mod)).?, | |
| 4496 | 4283 | }); |
| 4497 | 4284 | gop.value_ptr.* = llvm_val; |
| 4498 | 4285 | return llvm_val; |
| 4499 | 4286 | } |
| 4500 | 4287 | |
| 4501 | 4288 | fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value { |
| 4289 | const mod = self.dg.module; | |
| 4502 | 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 | 4293 | // We have an LLVM value but we need to create a global constant and |
| 4506 | 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 | 4296 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); |
| 4509 | 4297 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); |
| 4510 | 4298 | const global = self.dg.object.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", llvm_actual_addrspace); |
| ... | ... | @@ -4512,7 +4300,7 @@ pub const FuncGen = struct { |
| 4512 | 4300 | global.setLinkage(.Private); |
| 4513 | 4301 | global.setGlobalConstant(.True); |
| 4514 | 4302 | global.setUnnamedAddr(.True); |
| 4515 | global.setAlignment(tv.ty.abiAlignment(target)); | |
| 4303 | global.setAlignment(tv.ty.abiAlignment(mod)); | |
| 4516 | 4304 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) |
| 4517 | 4305 | global.constAddrSpaceCast(self.context.pointerType(llvm_wanted_addrspace)) |
| 4518 | 4306 | else |
| ... | ... | @@ -4521,11 +4309,12 @@ pub const FuncGen = struct { |
| 4521 | 4309 | } |
| 4522 | 4310 | |
| 4523 | 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 | 4314 | const air_tags = self.air.instructions.items(.tag); |
| 4525 | 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 | 4317 | continue; |
| 4528 | } | |
| 4529 | 4318 | |
| 4530 | 4319 | const opt_value: ?*llvm.Value = switch (air_tags[inst]) { |
| 4531 | 4320 | // zig fmt: off |
| ... | ... | @@ -4742,8 +4531,8 @@ pub const FuncGen = struct { |
| 4742 | 4531 | |
| 4743 | 4532 | .vector_store_elem => try self.airVectorStoreElem(inst), |
| 4744 | 4533 | |
| 4745 | .constant => unreachable, | |
| 4746 | .const_ty => unreachable, | |
| 4534 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, | |
| 4535 | ||
| 4747 | 4536 | .unreach => self.airUnreach(inst), |
| 4748 | 4537 | .dbg_stmt => self.airDbgStmt(inst), |
| 4749 | 4538 | .dbg_inline_begin => try self.airDbgInlineBegin(inst), |
| ... | ... | @@ -4774,29 +4563,30 @@ pub const FuncGen = struct { |
| 4774 | 4563 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4775 | 4564 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 4776 | 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); | |
| 4778 | const zig_fn_ty = switch (callee_ty.zigTypeTag()) { | |
| 4566 | const mod = self.dg.module; | |
| 4567 | const callee_ty = self.typeOf(pl_op.operand); | |
| 4568 | const zig_fn_ty = switch (callee_ty.zigTypeTag(mod)) { | |
| 4779 | 4569 | .Fn => callee_ty, |
| 4780 | .Pointer => callee_ty.childType(), | |
| 4570 | .Pointer => callee_ty.childType(mod), | |
| 4781 | 4571 | else => unreachable, |
| 4782 | 4572 | }; |
| 4783 | const fn_info = zig_fn_ty.fnInfo(); | |
| 4784 | const return_type = fn_info.return_type; | |
| 4573 | const fn_info = mod.typeToFunc(zig_fn_ty).?; | |
| 4574 | const return_type = fn_info.return_type.toType(); | |
| 4785 | 4575 | const llvm_fn = try self.resolveInst(pl_op.operand); |
| 4786 | const target = self.dg.module.getTarget(); | |
| 4787 | const sret = firstParamSRet(fn_info, target); | |
| 4576 | const target = mod.getTarget(); | |
| 4577 | const sret = firstParamSRet(fn_info, mod); | |
| 4788 | 4578 | |
| 4789 | 4579 | var llvm_args = std.ArrayList(*llvm.Value).init(self.gpa); |
| 4790 | 4580 | defer llvm_args.deinit(); |
| 4791 | 4581 | |
| 4792 | 4582 | const ret_ptr = if (!sret) null else blk: { |
| 4793 | 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 | 4585 | try llvm_args.append(ret_ptr); |
| 4796 | 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 | 4590 | self.dg.module.comp.bin_file.options.error_return_tracing; |
| 4801 | 4591 | if (err_return_tracing) { |
| 4802 | 4592 | try llvm_args.append(self.err_ret_trace.?); |
| ... | ... | @@ -4807,11 +4597,11 @@ pub const FuncGen = struct { |
| 4807 | 4597 | .no_bits => continue, |
| 4808 | 4598 | .byval => { |
| 4809 | 4599 | const arg = args[it.zig_index - 1]; |
| 4810 | const param_ty = self.air.typeOf(arg); | |
| 4600 | const param_ty = self.typeOf(arg); | |
| 4811 | 4601 | const llvm_arg = try self.resolveInst(arg); |
| 4812 | 4602 | const llvm_param_ty = try self.dg.lowerType(param_ty); |
| 4813 | if (isByRef(param_ty)) { | |
| 4814 | const alignment = param_ty.abiAlignment(target); | |
| 4603 | if (isByRef(param_ty, mod)) { | |
| 4604 | const alignment = param_ty.abiAlignment(mod); | |
| 4815 | 4605 | const load_inst = self.builder.buildLoad(llvm_param_ty, llvm_arg, ""); |
| 4816 | 4606 | load_inst.setAlignment(alignment); |
| 4817 | 4607 | try llvm_args.append(load_inst); |
| ... | ... | @@ -4821,12 +4611,12 @@ pub const FuncGen = struct { |
| 4821 | 4611 | }, |
| 4822 | 4612 | .byref => { |
| 4823 | 4613 | const arg = args[it.zig_index - 1]; |
| 4824 | const param_ty = self.air.typeOf(arg); | |
| 4614 | const param_ty = self.typeOf(arg); | |
| 4825 | 4615 | const llvm_arg = try self.resolveInst(arg); |
| 4826 | if (isByRef(param_ty)) { | |
| 4616 | if (isByRef(param_ty, mod)) { | |
| 4827 | 4617 | try llvm_args.append(llvm_arg); |
| 4828 | 4618 | } else { |
| 4829 | const alignment = param_ty.abiAlignment(target); | |
| 4619 | const alignment = param_ty.abiAlignment(mod); | |
| 4830 | 4620 | const param_llvm_ty = llvm_arg.typeOf(); |
| 4831 | 4621 | const arg_ptr = self.buildAlloca(param_llvm_ty, alignment); |
| 4832 | 4622 | const store_inst = self.builder.buildStore(llvm_arg, arg_ptr); |
| ... | ... | @@ -4836,13 +4626,13 @@ pub const FuncGen = struct { |
| 4836 | 4626 | }, |
| 4837 | 4627 | .byref_mut => { |
| 4838 | 4628 | const arg = args[it.zig_index - 1]; |
| 4839 | const param_ty = self.air.typeOf(arg); | |
| 4629 | const param_ty = self.typeOf(arg); | |
| 4840 | 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 | 4633 | const param_llvm_ty = try self.dg.lowerType(param_ty); |
| 4844 | 4634 | const arg_ptr = self.buildAlloca(param_llvm_ty, alignment); |
| 4845 | if (isByRef(param_ty)) { | |
| 4635 | if (isByRef(param_ty, mod)) { | |
| 4846 | 4636 | const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, ""); |
| 4847 | 4637 | load_inst.setAlignment(alignment); |
| 4848 | 4638 | |
| ... | ... | @@ -4857,13 +4647,13 @@ pub const FuncGen = struct { |
| 4857 | 4647 | }, |
| 4858 | 4648 | .abi_sized_int => { |
| 4859 | 4649 | const arg = args[it.zig_index - 1]; |
| 4860 | const param_ty = self.air.typeOf(arg); | |
| 4650 | const param_ty = self.typeOf(arg); | |
| 4861 | 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 | 4653 | const int_llvm_ty = self.context.intType(abi_size * 8); |
| 4864 | 4654 | |
| 4865 | if (isByRef(param_ty)) { | |
| 4866 | const alignment = param_ty.abiAlignment(target); | |
| 4655 | if (isByRef(param_ty, mod)) { | |
| 4656 | const alignment = param_ty.abiAlignment(mod); | |
| 4867 | 4657 | const load_inst = self.builder.buildLoad(int_llvm_ty, llvm_arg, ""); |
| 4868 | 4658 | load_inst.setAlignment(alignment); |
| 4869 | 4659 | try llvm_args.append(load_inst); |
| ... | ... | @@ -4871,7 +4661,7 @@ pub const FuncGen = struct { |
| 4871 | 4661 | // LLVM does not allow bitcasting structs so we must allocate |
| 4872 | 4662 | // a local, store as one type, and then load as another type. |
| 4873 | 4663 | const alignment = @max( |
| 4874 | param_ty.abiAlignment(target), | |
| 4664 | param_ty.abiAlignment(mod), | |
| 4875 | 4665 | self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty), |
| 4876 | 4666 | ); |
| 4877 | 4667 | const int_ptr = self.buildAlloca(int_llvm_ty, alignment); |
| ... | ... | @@ -4893,14 +4683,14 @@ pub const FuncGen = struct { |
| 4893 | 4683 | }, |
| 4894 | 4684 | .multiple_llvm_types => { |
| 4895 | 4685 | const arg = args[it.zig_index - 1]; |
| 4896 | const param_ty = self.air.typeOf(arg); | |
| 4686 | const param_ty = self.typeOf(arg); | |
| 4897 | 4687 | const llvm_types = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 4898 | 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 | 4690 | const arg_ptr = if (is_by_ref) llvm_arg else p: { |
| 4901 | 4691 | const p = self.buildAlloca(llvm_arg.typeOf(), null); |
| 4902 | 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 | 4694 | break :p p; |
| 4905 | 4695 | }; |
| 4906 | 4696 | |
| ... | ... | @@ -4922,19 +4712,19 @@ pub const FuncGen = struct { |
| 4922 | 4712 | }, |
| 4923 | 4713 | .float_array => |count| { |
| 4924 | 4714 | const arg = args[it.zig_index - 1]; |
| 4925 | const arg_ty = self.air.typeOf(arg); | |
| 4715 | const arg_ty = self.typeOf(arg); | |
| 4926 | 4716 | var llvm_arg = try self.resolveInst(arg); |
| 4927 | if (!isByRef(arg_ty)) { | |
| 4717 | if (!isByRef(arg_ty, mod)) { | |
| 4928 | 4718 | const p = self.buildAlloca(llvm_arg.typeOf(), null); |
| 4929 | 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 | 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 | 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 | 4728 | const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, ""); |
| 4939 | 4729 | load_inst.setAlignment(alignment); |
| 4940 | 4730 | try llvm_args.append(load_inst); |
| ... | ... | @@ -4942,17 +4732,17 @@ pub const FuncGen = struct { |
| 4942 | 4732 | .i32_array, .i64_array => |arr_len| { |
| 4943 | 4733 | const elem_size: u8 = if (lowering == .i32_array) 32 else 64; |
| 4944 | 4734 | const arg = args[it.zig_index - 1]; |
| 4945 | const arg_ty = self.air.typeOf(arg); | |
| 4735 | const arg_ty = self.typeOf(arg); | |
| 4946 | 4736 | var llvm_arg = try self.resolveInst(arg); |
| 4947 | if (!isByRef(arg_ty)) { | |
| 4737 | if (!isByRef(arg_ty, mod)) { | |
| 4948 | 4738 | const p = self.buildAlloca(llvm_arg.typeOf(), null); |
| 4949 | 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 | 4741 | llvm_arg = store_inst; |
| 4952 | 4742 | } |
| 4953 | 4743 | |
| 4954 | 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 | 4746 | const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, ""); |
| 4957 | 4747 | load_inst.setAlignment(alignment); |
| 4958 | 4748 | try llvm_args.append(load_inst); |
| ... | ... | @@ -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 | 4763 | // Add argument attributes for function pointer calls. |
| 4974 | 4764 | it = iterateParamTypes(self.dg, fn_info); |
| 4975 | 4765 | it.llvm_index += @boolToInt(sret); |
| ... | ... | @@ -4977,16 +4767,16 @@ pub const FuncGen = struct { |
| 4977 | 4767 | while (it.next()) |lowering| switch (lowering) { |
| 4978 | 4768 | .byval => { |
| 4979 | 4769 | const param_index = it.zig_index - 1; |
| 4980 | const param_ty = fn_info.param_types[param_index]; | |
| 4981 | if (!isByRef(param_ty)) { | |
| 4770 | const param_ty = fn_info.param_types[param_index].toType(); | |
| 4771 | if (!isByRef(param_ty, mod)) { | |
| 4982 | 4772 | self.dg.addByValParamAttrs(call, param_ty, param_index, fn_info, it.llvm_index - 1); |
| 4983 | 4773 | } |
| 4984 | 4774 | }, |
| 4985 | 4775 | .byref => { |
| 4986 | 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 | 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 | 4780 | self.dg.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); |
| 4991 | 4781 | }, |
| 4992 | 4782 | .byref_mut => { |
| ... | ... | @@ -5004,8 +4794,8 @@ pub const FuncGen = struct { |
| 5004 | 4794 | |
| 5005 | 4795 | .slice => { |
| 5006 | 4796 | assert(!it.byval_attr); |
| 5007 | const param_ty = fn_info.param_types[it.zig_index - 1]; | |
| 5008 | const ptr_info = param_ty.ptrInfo().data; | |
| 4797 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); | |
| 4798 | const ptr_info = param_ty.ptrInfo(mod); | |
| 5009 | 4799 | const llvm_arg_i = it.llvm_index - 2; |
| 5010 | 4800 | |
| 5011 | 4801 | if (math.cast(u5, it.zig_index - 1)) |i| { |
| ... | ... | @@ -5013,7 +4803,7 @@ pub const FuncGen = struct { |
| 5013 | 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 | 4807 | self.dg.addArgAttr(call, llvm_arg_i, "nonnull"); |
| 5018 | 4808 | } |
| 5019 | 4809 | if (!ptr_info.mutable) { |
| ... | ... | @@ -5022,18 +4812,18 @@ pub const FuncGen = struct { |
| 5022 | 4812 | if (ptr_info.@"align" != 0) { |
| 5023 | 4813 | self.dg.addArgAttrInt(call, llvm_arg_i, "align", ptr_info.@"align"); |
| 5024 | 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 | 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 | 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 | 4827 | return null; |
| 5038 | 4828 | } |
| 5039 | 4829 | |
| ... | ... | @@ -5041,12 +4831,12 @@ pub const FuncGen = struct { |
| 5041 | 4831 | |
| 5042 | 4832 | if (ret_ptr) |rp| { |
| 5043 | 4833 | call.setCallSret(llvm_ret_ty); |
| 5044 | if (isByRef(return_type)) { | |
| 4834 | if (isByRef(return_type, mod)) { | |
| 5045 | 4835 | return rp; |
| 5046 | 4836 | } else { |
| 5047 | 4837 | // our by-ref status disagrees with sret so we must load. |
| 5048 | 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 | 4840 | return loaded; |
| 5051 | 4841 | } |
| 5052 | 4842 | } |
| ... | ... | @@ -5061,7 +4851,7 @@ pub const FuncGen = struct { |
| 5061 | 4851 | const rp = self.buildAlloca(llvm_ret_ty, alignment); |
| 5062 | 4852 | const store_inst = self.builder.buildStore(call, rp); |
| 5063 | 4853 | store_inst.setAlignment(alignment); |
| 5064 | if (isByRef(return_type)) { | |
| 4854 | if (isByRef(return_type, mod)) { | |
| 5065 | 4855 | return rp; |
| 5066 | 4856 | } else { |
| 5067 | 4857 | const load_inst = self.builder.buildLoad(llvm_ret_ty, rp, ""); |
| ... | ... | @@ -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 | 4864 | // our by-ref status disagrees with sret so we must allocate, store, |
| 5075 | 4865 | // and return the allocation pointer. |
| 5076 | const alignment = return_type.abiAlignment(target); | |
| 4866 | const alignment = return_type.abiAlignment(mod); | |
| 5077 | 4867 | const rp = self.buildAlloca(llvm_ret_ty, alignment); |
| 5078 | 4868 | const store_inst = self.builder.buildStore(call, rp); |
| 5079 | 4869 | store_inst.setAlignment(alignment); |
| ... | ... | @@ -5084,22 +4874,19 @@ pub const FuncGen = struct { |
| 5084 | 4874 | } |
| 5085 | 4875 | |
| 5086 | 4876 | fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 4877 | const mod = self.dg.module; | |
| 5087 | 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 | 4880 | if (self.ret_ptr) |ret_ptr| { |
| 5090 | 4881 | const operand = try self.resolveInst(un_op); |
| 5091 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 5092 | .base = .{ .tag = .single_mut_pointer }, | |
| 5093 | .data = ret_ty, | |
| 5094 | }; | |
| 5095 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 4882 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | |
| 5096 | 4883 | try self.store(ret_ptr, ptr_ty, operand, .NotAtomic); |
| 5097 | 4884 | _ = self.builder.buildRetVoid(); |
| 5098 | 4885 | return null; |
| 5099 | 4886 | } |
| 5100 | const fn_info = self.dg.decl.ty.fnInfo(); | |
| 5101 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5102 | if (fn_info.return_type.isError()) { | |
| 4887 | const fn_info = mod.typeToFunc(self.dg.decl.ty).?; | |
| 4888 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4889 | if (fn_info.return_type.toType().isError(mod)) { | |
| 5103 | 4890 | // Functions with an empty error set are emitted with an error code |
| 5104 | 4891 | // return type and return zero so they can be function pointers coerced |
| 5105 | 4892 | // to functions that return anyerror. |
| ... | ... | @@ -5113,10 +4900,9 @@ pub const FuncGen = struct { |
| 5113 | 4900 | |
| 5114 | 4901 | const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info); |
| 5115 | 4902 | const operand = try self.resolveInst(un_op); |
| 5116 | const target = self.dg.module.getTarget(); | |
| 5117 | const alignment = ret_ty.abiAlignment(target); | |
| 4903 | const alignment = ret_ty.abiAlignment(mod); | |
| 5118 | 4904 | |
| 5119 | if (isByRef(ret_ty)) { | |
| 4905 | if (isByRef(ret_ty, mod)) { | |
| 5120 | 4906 | // operand is a pointer however self.ret_ptr is null so that means |
| 5121 | 4907 | // we need to return a value. |
| 5122 | 4908 | const load_inst = self.builder.buildLoad(abi_ret_ty, operand, ""); |
| ... | ... | @@ -5141,12 +4927,13 @@ pub const FuncGen = struct { |
| 5141 | 4927 | } |
| 5142 | 4928 | |
| 5143 | 4929 | fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 4930 | const mod = self.dg.module; | |
| 5144 | 4931 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5145 | const ptr_ty = self.air.typeOf(un_op); | |
| 5146 | const ret_ty = ptr_ty.childType(); | |
| 5147 | const fn_info = self.dg.decl.ty.fnInfo(); | |
| 5148 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5149 | if (fn_info.return_type.isError()) { | |
| 4932 | const ptr_ty = self.typeOf(un_op); | |
| 4933 | const ret_ty = ptr_ty.childType(mod); | |
| 4934 | const fn_info = mod.typeToFunc(self.dg.decl.ty).?; | |
| 4935 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4936 | if (fn_info.return_type.toType().isError(mod)) { | |
| 5150 | 4937 | // Functions with an empty error set are emitted with an error code |
| 5151 | 4938 | // return type and return zero so they can be function pointers coerced |
| 5152 | 4939 | // to functions that return anyerror. |
| ... | ... | @@ -5162,10 +4949,9 @@ pub const FuncGen = struct { |
| 5162 | 4949 | return null; |
| 5163 | 4950 | } |
| 5164 | 4951 | const ptr = try self.resolveInst(un_op); |
| 5165 | const target = self.dg.module.getTarget(); | |
| 5166 | 4952 | const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info); |
| 5167 | 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 | 4955 | _ = self.builder.buildRet(loaded); |
| 5170 | 4956 | return null; |
| 5171 | 4957 | } |
| ... | ... | @@ -5184,9 +4970,9 @@ pub const FuncGen = struct { |
| 5184 | 4970 | const src_list = try self.resolveInst(ty_op.operand); |
| 5185 | 4971 | const va_list_ty = self.air.getRefType(ty_op.ty); |
| 5186 | 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(); | |
| 5189 | const result_alignment = va_list_ty.abiAlignment(target); | |
| 4975 | const result_alignment = va_list_ty.abiAlignment(mod); | |
| 5190 | 4976 | const dest_list = self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5191 | 4977 | |
| 5192 | 4978 | const llvm_fn_name = "llvm.va_copy"; |
| ... | ... | @@ -5202,7 +4988,7 @@ pub const FuncGen = struct { |
| 5202 | 4988 | const args: [2]*llvm.Value = .{ dest_list, src_list }; |
| 5203 | 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 | 4992 | return dest_list; |
| 5207 | 4993 | } else { |
| 5208 | 4994 | const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, ""); |
| ... | ... | @@ -5227,11 +5013,11 @@ pub const FuncGen = struct { |
| 5227 | 5013 | } |
| 5228 | 5014 | |
| 5229 | 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 | 5018 | const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); |
| 5232 | 5019 | |
| 5233 | const target = self.dg.module.getTarget(); | |
| 5234 | const result_alignment = va_list_ty.abiAlignment(target); | |
| 5020 | const result_alignment = va_list_ty.abiAlignment(mod); | |
| 5235 | 5021 | const list = self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5236 | 5022 | |
| 5237 | 5023 | const llvm_fn_name = "llvm.va_start"; |
| ... | ... | @@ -5243,7 +5029,7 @@ pub const FuncGen = struct { |
| 5243 | 5029 | const args: [1]*llvm.Value = .{list}; |
| 5244 | 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 | 5033 | return list; |
| 5248 | 5034 | } else { |
| 5249 | 5035 | const loaded = self.builder.buildLoad(llvm_va_list_ty, list, ""); |
| ... | ... | @@ -5258,7 +5044,7 @@ pub const FuncGen = struct { |
| 5258 | 5044 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5259 | 5045 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5260 | 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 | 5049 | return self.cmp(lhs, rhs, operand_ty, op); |
| 5264 | 5050 | } |
| ... | ... | @@ -5271,7 +5057,7 @@ pub const FuncGen = struct { |
| 5271 | 5057 | |
| 5272 | 5058 | const lhs = try self.resolveInst(extra.lhs); |
| 5273 | 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 | 5061 | const cmp_op = extra.compareOperator(); |
| 5276 | 5062 | |
| 5277 | 5063 | return self.cmp(lhs, rhs, vec_ty, cmp_op); |
| ... | ... | @@ -5292,23 +5078,21 @@ pub const FuncGen = struct { |
| 5292 | 5078 | operand_ty: Type, |
| 5293 | 5079 | op: math.CompareOperator, |
| 5294 | 5080 | ) Allocator.Error!*llvm.Value { |
| 5295 | var int_buffer: Type.Payload.Bits = undefined; | |
| 5296 | var opt_buffer: Type.Payload.ElemType = undefined; | |
| 5297 | ||
| 5298 | const scalar_ty = operand_ty.scalarType(); | |
| 5299 | const int_ty = switch (scalar_ty.zigTypeTag()) { | |
| 5300 | .Enum => scalar_ty.intTagType(&int_buffer), | |
| 5081 | const mod = self.dg.module; | |
| 5082 | const scalar_ty = operand_ty.scalarType(mod); | |
| 5083 | const int_ty = switch (scalar_ty.zigTypeTag(mod)) { | |
| 5084 | .Enum => scalar_ty.intTagType(mod), | |
| 5301 | 5085 | .Int, .Bool, .Pointer, .ErrorSet => scalar_ty, |
| 5302 | 5086 | .Optional => blk: { |
| 5303 | const payload_ty = operand_ty.optionalChild(&opt_buffer); | |
| 5304 | if (!payload_ty.hasRuntimeBitsIgnoreComptime() or | |
| 5305 | operand_ty.optionalReprIsPayload()) | |
| 5087 | const payload_ty = operand_ty.optionalChild(mod); | |
| 5088 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or | |
| 5089 | operand_ty.optionalReprIsPayload(mod)) | |
| 5306 | 5090 | { |
| 5307 | 5091 | break :blk operand_ty; |
| 5308 | 5092 | } |
| 5309 | 5093 | // We need to emit instructions to check for equality/inequality |
| 5310 | 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 | 5096 | const opt_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 5313 | 5097 | const lhs_non_null = self.optIsNonNull(opt_llvm_ty, lhs, is_by_ref); |
| 5314 | 5098 | const rhs_non_null = self.optIsNonNull(opt_llvm_ty, rhs, is_by_ref); |
| ... | ... | @@ -5375,7 +5159,7 @@ pub const FuncGen = struct { |
| 5375 | 5159 | .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }), |
| 5376 | 5160 | else => unreachable, |
| 5377 | 5161 | }; |
| 5378 | const is_signed = int_ty.isSignedInt(); | |
| 5162 | const is_signed = int_ty.isSignedInt(mod); | |
| 5379 | 5163 | const operation: llvm.IntPredicate = switch (op) { |
| 5380 | 5164 | .eq => .EQ, |
| 5381 | 5165 | .neq => .NE, |
| ... | ... | @@ -5388,13 +5172,14 @@ pub const FuncGen = struct { |
| 5388 | 5172 | } |
| 5389 | 5173 | |
| 5390 | 5174 | fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5175 | const mod = self.dg.module; | |
| 5391 | 5176 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5392 | 5177 | const extra = self.air.extraData(Air.Block, ty_pl.payload); |
| 5393 | 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 | 5180 | const parent_bb = self.context.createBasicBlock("Block"); |
| 5396 | 5181 | |
| 5397 | if (inst_ty.isNoReturn()) { | |
| 5182 | if (inst_ty.isNoReturn(mod)) { | |
| 5398 | 5183 | try self.genBody(body); |
| 5399 | 5184 | return null; |
| 5400 | 5185 | } |
| ... | ... | @@ -5414,8 +5199,8 @@ pub const FuncGen = struct { |
| 5414 | 5199 | self.builder.positionBuilderAtEnd(parent_bb); |
| 5415 | 5200 | |
| 5416 | 5201 | // Create a phi node only if the block returns a value. |
| 5417 | const is_body = inst_ty.zigTypeTag() == .Fn; | |
| 5418 | if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime()) return null; | |
| 5202 | const is_body = inst_ty.zigTypeTag(mod) == .Fn; | |
| 5203 | if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; | |
| 5419 | 5204 | |
| 5420 | 5205 | const raw_llvm_ty = try self.dg.lowerType(inst_ty); |
| 5421 | 5206 | |
| ... | ... | @@ -5424,7 +5209,7 @@ pub const FuncGen = struct { |
| 5424 | 5209 | // a pointer to it. LLVM IR allows the call instruction to use function bodies instead |
| 5425 | 5210 | // of function pointers, however the phi makes it a runtime value and therefore |
| 5426 | 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 | 5213 | break :ty self.context.pointerType(0); |
| 5429 | 5214 | } |
| 5430 | 5215 | break :ty raw_llvm_ty; |
| ... | ... | @@ -5444,8 +5229,9 @@ pub const FuncGen = struct { |
| 5444 | 5229 | const block = self.blocks.get(branch.block_inst).?; |
| 5445 | 5230 | |
| 5446 | 5231 | // Add the values to the lists only if the break provides a value. |
| 5447 | const operand_ty = self.air.typeOf(branch.operand); | |
| 5448 | if (operand_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.zigTypeTag() == .Fn) { | |
| 5232 | const operand_ty = self.typeOf(branch.operand); | |
| 5233 | const mod = self.dg.module; | |
| 5234 | if (operand_ty.hasRuntimeBitsIgnoreComptime(mod) or operand_ty.zigTypeTag(mod) == .Fn) { | |
| 5449 | 5235 | const val = try self.resolveInst(branch.operand); |
| 5450 | 5236 | |
| 5451 | 5237 | // For the phi node, we need the basic blocks and the values of the |
| ... | ... | @@ -5481,24 +5267,26 @@ pub const FuncGen = struct { |
| 5481 | 5267 | } |
| 5482 | 5268 | |
| 5483 | 5269 | fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5270 | const mod = self.dg.module; | |
| 5484 | 5271 | const inst = body_tail[0]; |
| 5485 | 5272 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5486 | 5273 | const err_union = try self.resolveInst(pl_op.operand); |
| 5487 | 5274 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 5488 | 5275 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 5489 | const err_union_ty = self.air.typeOf(pl_op.operand); | |
| 5490 | const payload_ty = self.air.typeOfIndex(inst); | |
| 5491 | const can_elide_load = if (isByRef(payload_ty)) self.canElideLoad(body_tail) else false; | |
| 5276 | const err_union_ty = self.typeOf(pl_op.operand); | |
| 5277 | const payload_ty = self.typeOfIndex(inst); | |
| 5278 | const can_elide_load = if (isByRef(payload_ty, mod)) self.canElideLoad(body_tail) else false; | |
| 5492 | 5279 | const is_unused = self.liveness.isUnused(inst); |
| 5493 | 5280 | return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused); |
| 5494 | 5281 | } |
| 5495 | 5282 | |
| 5496 | 5283 | fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5284 | const mod = self.dg.module; | |
| 5497 | 5285 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5498 | 5286 | const extra = self.air.extraData(Air.TryPtr, ty_pl.payload); |
| 5499 | 5287 | const err_union_ptr = try self.resolveInst(extra.data.ptr); |
| 5500 | 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 | 5290 | const is_unused = self.liveness.isUnused(inst); |
| 5503 | 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 | 5300 | can_elide_load: bool, |
| 5513 | 5301 | is_unused: bool, |
| 5514 | 5302 | ) !?*llvm.Value { |
| 5515 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 5516 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(); | |
| 5517 | const target = fg.dg.module.getTarget(); | |
| 5303 | const mod = fg.dg.module; | |
| 5304 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 5305 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod); | |
| 5518 | 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 | 5309 | const is_err = err: { |
| 5522 | 5310 | const err_set_ty = try fg.dg.lowerType(Type.anyerror); |
| 5523 | 5311 | const zero = err_set_ty.constNull(); |
| ... | ... | @@ -5529,8 +5317,8 @@ pub const FuncGen = struct { |
| 5529 | 5317 | err_union; |
| 5530 | 5318 | break :err fg.builder.buildICmp(.NE, loaded, zero, ""); |
| 5531 | 5319 | } |
| 5532 | const err_field_index = errUnionErrorOffset(payload_ty, target); | |
| 5533 | if (operand_is_ptr or isByRef(err_union_ty)) { | |
| 5320 | const err_field_index = errUnionErrorOffset(payload_ty, mod); | |
| 5321 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { | |
| 5534 | 5322 | const err_field_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, err_field_index, ""); |
| 5535 | 5323 | // TODO add alignment to this load |
| 5536 | 5324 | const loaded = fg.builder.buildLoad(err_set_ty, err_field_ptr, ""); |
| ... | ... | @@ -5555,30 +5343,31 @@ pub const FuncGen = struct { |
| 5555 | 5343 | if (!payload_has_bits) { |
| 5556 | 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 | 5347 | if (operand_is_ptr) { |
| 5560 | 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 | 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 | 5352 | if (can_elide_load) |
| 5565 | 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 | 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 | 5359 | return load_inst; |
| 5572 | 5360 | } |
| 5573 | 5361 | return fg.builder.buildExtractValue(err_union, offset, ""); |
| 5574 | 5362 | } |
| 5575 | 5363 | |
| 5576 | 5364 | fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5365 | const mod = self.dg.module; | |
| 5577 | 5366 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5578 | 5367 | const cond = try self.resolveInst(pl_op.operand); |
| 5579 | 5368 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 5580 | 5369 | const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); |
| 5581 | const target = self.dg.module.getTarget(); | |
| 5370 | const target = mod.getTarget(); | |
| 5582 | 5371 | const llvm_usize = self.context.intType(target.ptrBitWidth()); |
| 5583 | 5372 | const cond_int = if (cond.typeOf().getTypeKind() == .Pointer) |
| 5584 | 5373 | self.builder.buildPtrToInt(cond, llvm_usize, "") |
| ... | ... | @@ -5623,6 +5412,7 @@ pub const FuncGen = struct { |
| 5623 | 5412 | } |
| 5624 | 5413 | |
| 5625 | 5414 | fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5415 | const mod = self.dg.module; | |
| 5626 | 5416 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5627 | 5417 | const loop = self.air.extraData(Air.Block, ty_pl.payload); |
| 5628 | 5418 | const body = self.air.extra[loop.end..][0..loop.data.body_len]; |
| ... | ... | @@ -5638,21 +5428,22 @@ pub const FuncGen = struct { |
| 5638 | 5428 | // would have been emitted already. Also the main loop in genBody can |
| 5639 | 5429 | // be while(true) instead of for(body), which will eliminate 1 branch on |
| 5640 | 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 | 5432 | _ = self.builder.buildBr(loop_block); |
| 5643 | 5433 | } |
| 5644 | 5434 | return null; |
| 5645 | 5435 | } |
| 5646 | 5436 | |
| 5647 | 5437 | fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5438 | const mod = self.dg.module; | |
| 5648 | 5439 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5649 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 5650 | const array_ty = operand_ty.childType(); | |
| 5440 | const operand_ty = self.typeOf(ty_op.operand); | |
| 5441 | const array_ty = operand_ty.childType(mod); | |
| 5651 | 5442 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 5652 | const len = llvm_usize.constInt(array_ty.arrayLen(), .False); | |
| 5653 | const slice_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); | |
| 5443 | const len = llvm_usize.constInt(array_ty.arrayLen(mod), .False); | |
| 5444 | const slice_llvm_ty = try self.dg.lowerType(self.typeOfIndex(inst)); | |
| 5654 | 5445 | const operand = try self.resolveInst(ty_op.operand); |
| 5655 | if (!array_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5446 | if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 5656 | 5447 | const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, ""); |
| 5657 | 5448 | return self.builder.buildInsertValue(partial, len, 1, ""); |
| 5658 | 5449 | } |
| ... | ... | @@ -5666,30 +5457,31 @@ pub const FuncGen = struct { |
| 5666 | 5457 | } |
| 5667 | 5458 | |
| 5668 | 5459 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5460 | const mod = self.dg.module; | |
| 5669 | 5461 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5670 | 5462 | |
| 5671 | 5463 | const operand = try self.resolveInst(ty_op.operand); |
| 5672 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 5673 | const operand_scalar_ty = operand_ty.scalarType(); | |
| 5464 | const operand_ty = self.typeOf(ty_op.operand); | |
| 5465 | const operand_scalar_ty = operand_ty.scalarType(mod); | |
| 5674 | 5466 | |
| 5675 | const dest_ty = self.air.typeOfIndex(inst); | |
| 5676 | const dest_scalar_ty = dest_ty.scalarType(); | |
| 5467 | const dest_ty = self.typeOfIndex(inst); | |
| 5468 | const dest_scalar_ty = dest_ty.scalarType(mod); | |
| 5677 | 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 | 5472 | if (intrinsicsAllowed(dest_scalar_ty, target)) { |
| 5681 | if (operand_scalar_ty.isSignedInt()) { | |
| 5473 | if (operand_scalar_ty.isSignedInt(mod)) { | |
| 5682 | 5474 | return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); |
| 5683 | 5475 | } else { |
| 5684 | 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 | 5481 | const rt_int_bits = compilerRtIntBits(operand_bits); |
| 5690 | 5482 | const rt_int_ty = self.context.intType(rt_int_bits); |
| 5691 | 5483 | var extended = e: { |
| 5692 | if (operand_scalar_ty.isSignedInt()) { | |
| 5484 | if (operand_scalar_ty.isSignedInt(mod)) { | |
| 5693 | 5485 | break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty, ""); |
| 5694 | 5486 | } else { |
| 5695 | 5487 | break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty, ""); |
| ... | ... | @@ -5698,7 +5490,7 @@ pub const FuncGen = struct { |
| 5698 | 5490 | const dest_bits = dest_scalar_ty.floatBits(target); |
| 5699 | 5491 | const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits); |
| 5700 | 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 | 5494 | var fn_name_buf: [64]u8 = undefined; |
| 5703 | 5495 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{ |
| 5704 | 5496 | sign_prefix, |
| ... | ... | @@ -5724,27 +5516,28 @@ pub const FuncGen = struct { |
| 5724 | 5516 | fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 5725 | 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 | 5521 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5729 | 5522 | |
| 5730 | 5523 | const operand = try self.resolveInst(ty_op.operand); |
| 5731 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 5732 | const operand_scalar_ty = operand_ty.scalarType(); | |
| 5524 | const operand_ty = self.typeOf(ty_op.operand); | |
| 5525 | const operand_scalar_ty = operand_ty.scalarType(mod); | |
| 5733 | 5526 | |
| 5734 | const dest_ty = self.air.typeOfIndex(inst); | |
| 5735 | const dest_scalar_ty = dest_ty.scalarType(); | |
| 5527 | const dest_ty = self.typeOfIndex(inst); | |
| 5528 | const dest_scalar_ty = dest_ty.scalarType(mod); | |
| 5736 | 5529 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| 5737 | 5530 | |
| 5738 | 5531 | if (intrinsicsAllowed(operand_scalar_ty, target)) { |
| 5739 | 5532 | // TODO set fast math flag |
| 5740 | if (dest_scalar_ty.isSignedInt()) { | |
| 5533 | if (dest_scalar_ty.isSignedInt(mod)) { | |
| 5741 | 5534 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); |
| 5742 | 5535 | } else { |
| 5743 | 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 | 5541 | const ret_ty = self.context.intType(rt_int_bits); |
| 5749 | 5542 | const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: { |
| 5750 | 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 | 5549 | const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); |
| 5757 | 5550 | |
| 5758 | 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 | 5554 | var fn_name_buf: [64]u8 = undefined; |
| 5762 | 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 | 5571 | } |
| 5779 | 5572 | |
| 5780 | 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 | 5576 | return fg.builder.buildExtractValue(ptr, 0, ""); |
| 5783 | 5577 | } else { |
| 5784 | 5578 | return ptr; |
| ... | ... | @@ -5786,22 +5580,23 @@ pub const FuncGen = struct { |
| 5786 | 5580 | } |
| 5787 | 5581 | |
| 5788 | 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 | 5585 | const llvm_usize_ty = fg.context.intType(target.ptrBitWidth()); |
| 5791 | switch (ty.ptrSize()) { | |
| 5586 | switch (ty.ptrSize(mod)) { | |
| 5792 | 5587 | .Slice => { |
| 5793 | 5588 | const len = fg.builder.buildExtractValue(ptr, 1, ""); |
| 5794 | const elem_ty = ty.childType(); | |
| 5795 | const abi_size = elem_ty.abiSize(target); | |
| 5589 | const elem_ty = ty.childType(mod); | |
| 5590 | const abi_size = elem_ty.abiSize(mod); | |
| 5796 | 5591 | if (abi_size == 1) return len; |
| 5797 | 5592 | const abi_size_llvm_val = llvm_usize_ty.constInt(abi_size, .False); |
| 5798 | 5593 | return fg.builder.buildMul(len, abi_size_llvm_val, ""); |
| 5799 | 5594 | }, |
| 5800 | 5595 | .One => { |
| 5801 | const array_ty = ty.childType(); | |
| 5802 | const elem_ty = array_ty.childType(); | |
| 5803 | const abi_size = elem_ty.abiSize(target); | |
| 5804 | return llvm_usize_ty.constInt(array_ty.arrayLen() * abi_size, .False); | |
| 5596 | const array_ty = ty.childType(mod); | |
| 5597 | const elem_ty = array_ty.childType(mod); | |
| 5598 | const abi_size = elem_ty.abiSize(mod); | |
| 5599 | return llvm_usize_ty.constInt(array_ty.arrayLen(mod) * abi_size, .False); | |
| 5805 | 5600 | }, |
| 5806 | 5601 | .Many, .C => unreachable, |
| 5807 | 5602 | } |
| ... | ... | @@ -5814,67 +5609,69 @@ pub const FuncGen = struct { |
| 5814 | 5609 | } |
| 5815 | 5610 | |
| 5816 | 5611 | fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value { |
| 5612 | const mod = self.dg.module; | |
| 5817 | 5613 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5818 | 5614 | const slice_ptr = try self.resolveInst(ty_op.operand); |
| 5819 | const slice_ptr_ty = self.air.typeOf(ty_op.operand); | |
| 5820 | const slice_llvm_ty = try self.dg.lowerPtrElemTy(slice_ptr_ty.childType()); | |
| 5615 | const slice_ptr_ty = self.typeOf(ty_op.operand); | |
| 5616 | const slice_llvm_ty = try self.dg.lowerPtrElemTy(slice_ptr_ty.childType(mod)); | |
| 5821 | 5617 | |
| 5822 | 5618 | return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, ""); |
| 5823 | 5619 | } |
| 5824 | 5620 | |
| 5825 | 5621 | fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5622 | const mod = self.dg.module; | |
| 5826 | 5623 | const inst = body_tail[0]; |
| 5827 | 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 | 5626 | const slice = try self.resolveInst(bin_op.lhs); |
| 5830 | 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 | 5629 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); |
| 5833 | 5630 | const base_ptr = self.builder.buildExtractValue(slice, 0, ""); |
| 5834 | 5631 | const indices: [1]*llvm.Value = .{index}; |
| 5835 | 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 | 5634 | if (self.canElideLoad(body_tail)) |
| 5838 | 5635 | return ptr; |
| 5839 | 5636 | |
| 5840 | const target = self.dg.module.getTarget(); | |
| 5841 | return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(target), false); | |
| 5637 | return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false); | |
| 5842 | 5638 | } |
| 5843 | 5639 | |
| 5844 | 5640 | return self.load(ptr, slice_ty); |
| 5845 | 5641 | } |
| 5846 | 5642 | |
| 5847 | 5643 | fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5644 | const mod = self.dg.module; | |
| 5848 | 5645 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5849 | 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 | 5649 | const slice = try self.resolveInst(bin_op.lhs); |
| 5853 | 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 | 5652 | const base_ptr = self.builder.buildExtractValue(slice, 0, ""); |
| 5856 | 5653 | const indices: [1]*llvm.Value = .{index}; |
| 5857 | 5654 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 5858 | 5655 | } |
| 5859 | 5656 | |
| 5860 | 5657 | fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5658 | const mod = self.dg.module; | |
| 5861 | 5659 | const inst = body_tail[0]; |
| 5862 | 5660 | |
| 5863 | 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 | 5663 | const array_llvm_val = try self.resolveInst(bin_op.lhs); |
| 5866 | 5664 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5867 | 5665 | const array_llvm_ty = try self.dg.lowerType(array_ty); |
| 5868 | const elem_ty = array_ty.childType(); | |
| 5869 | if (isByRef(array_ty)) { | |
| 5666 | const elem_ty = array_ty.childType(mod); | |
| 5667 | if (isByRef(array_ty, mod)) { | |
| 5870 | 5668 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; |
| 5871 | if (isByRef(elem_ty)) { | |
| 5669 | if (isByRef(elem_ty, mod)) { | |
| 5872 | 5670 | const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, ""); |
| 5873 | 5671 | if (canElideLoad(self, body_tail)) |
| 5874 | 5672 | return elem_ptr; |
| 5875 | 5673 | |
| 5876 | const target = self.dg.module.getTarget(); | |
| 5877 | return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(target), false); | |
| 5674 | return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(mod), false); | |
| 5878 | 5675 | } else { |
| 5879 | 5676 | const lhs_index = Air.refToIndex(bin_op.lhs).?; |
| 5880 | 5677 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); |
| ... | ... | @@ -5901,15 +5698,16 @@ pub const FuncGen = struct { |
| 5901 | 5698 | } |
| 5902 | 5699 | |
| 5903 | 5700 | fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5701 | const mod = self.dg.module; | |
| 5904 | 5702 | const inst = body_tail[0]; |
| 5905 | 5703 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5906 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 5907 | const elem_ty = ptr_ty.childType(); | |
| 5704 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 5705 | const elem_ty = ptr_ty.childType(mod); | |
| 5908 | 5706 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); |
| 5909 | 5707 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5910 | 5708 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5911 | 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 | 5711 | // If this is a single-item pointer to an array, we need another index in the GEP. |
| 5914 | 5712 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; |
| 5915 | 5713 | break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| ... | ... | @@ -5917,32 +5715,32 @@ pub const FuncGen = struct { |
| 5917 | 5715 | const indices: [1]*llvm.Value = .{rhs}; |
| 5918 | 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 | 5719 | if (self.canElideLoad(body_tail)) |
| 5922 | 5720 | return ptr; |
| 5923 | 5721 | |
| 5924 | const target = self.dg.module.getTarget(); | |
| 5925 | return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(target), false); | |
| 5722 | return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false); | |
| 5926 | 5723 | } |
| 5927 | 5724 | |
| 5928 | 5725 | return self.load(ptr, ptr_ty); |
| 5929 | 5726 | } |
| 5930 | 5727 | |
| 5931 | 5728 | fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5729 | const mod = self.dg.module; | |
| 5932 | 5730 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5933 | 5731 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5934 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 5935 | const elem_ty = ptr_ty.childType(); | |
| 5936 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 5732 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 5733 | const elem_ty = ptr_ty.childType(mod); | |
| 5734 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 5937 | 5735 | |
| 5938 | 5736 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5939 | 5737 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5940 | 5738 | |
| 5941 | 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 | 5742 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); |
| 5945 | if (ptr_ty.isSinglePointer()) { | |
| 5743 | if (ptr_ty.isSinglePointer(mod)) { | |
| 5946 | 5744 | // If this is a single-item pointer to an array, we need another index in the GEP. |
| 5947 | 5745 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; |
| 5948 | 5746 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| ... | ... | @@ -5956,7 +5754,7 @@ pub const FuncGen = struct { |
| 5956 | 5754 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5957 | 5755 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 5958 | 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 | 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 | 5765 | ) !?*llvm.Value { |
| 5968 | 5766 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5969 | 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 | 5769 | return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index); |
| 5972 | 5770 | } |
| 5973 | 5771 | |
| 5974 | 5772 | fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5773 | const mod = self.dg.module; | |
| 5975 | 5774 | const inst = body_tail[0]; |
| 5976 | 5775 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5977 | 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 | 5778 | const struct_llvm_val = try self.resolveInst(struct_field.struct_operand); |
| 5980 | 5779 | const field_index = struct_field.field_index; |
| 5981 | const field_ty = struct_ty.structFieldType(field_index); | |
| 5982 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 5780 | const field_ty = struct_ty.structFieldType(field_index, mod); | |
| 5781 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 5983 | 5782 | return null; |
| 5984 | 5783 | } |
| 5985 | const target = self.dg.module.getTarget(); | |
| 5986 | 5784 | |
| 5987 | if (!isByRef(struct_ty)) { | |
| 5988 | assert(!isByRef(field_ty)); | |
| 5989 | switch (struct_ty.zigTypeTag()) { | |
| 5990 | .Struct => switch (struct_ty.containerLayout()) { | |
| 5785 | if (!isByRef(struct_ty, mod)) { | |
| 5786 | assert(!isByRef(field_ty, mod)); | |
| 5787 | switch (struct_ty.zigTypeTag(mod)) { | |
| 5788 | .Struct => switch (struct_ty.containerLayout(mod)) { | |
| 5991 | 5789 | .Packed => { |
| 5992 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | |
| 5993 | const bit_offset = struct_obj.packedFieldBitOffset(target, field_index); | |
| 5790 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 5791 | const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index); | |
| 5994 | 5792 | const containing_int = struct_llvm_val; |
| 5995 | 5793 | const shift_amt = containing_int.typeOf().constInt(bit_offset, .False); |
| 5996 | 5794 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); |
| 5997 | 5795 | const elem_llvm_ty = try self.dg.lowerType(field_ty); |
| 5998 | if (field_ty.zigTypeTag() == .Float or field_ty.zigTypeTag() == .Vector) { | |
| 5999 | const elem_bits = @intCast(c_uint, field_ty.bitSize(target)); | |
| 5796 | if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) { | |
| 5797 | const elem_bits = @intCast(c_uint, field_ty.bitSize(mod)); | |
| 6000 | 5798 | const same_size_int = self.context.intType(elem_bits); |
| 6001 | 5799 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| 6002 | 5800 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); |
| 6003 | } else if (field_ty.isPtrAtRuntime()) { | |
| 6004 | const elem_bits = @intCast(c_uint, field_ty.bitSize(target)); | |
| 5801 | } else if (field_ty.isPtrAtRuntime(mod)) { | |
| 5802 | const elem_bits = @intCast(c_uint, field_ty.bitSize(mod)); | |
| 6005 | 5803 | const same_size_int = self.context.intType(elem_bits); |
| 6006 | 5804 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| 6007 | 5805 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); |
| ... | ... | @@ -6009,22 +5807,21 @@ pub const FuncGen = struct { |
| 6009 | 5807 | return self.builder.buildTrunc(shifted_value, elem_llvm_ty, ""); |
| 6010 | 5808 | }, |
| 6011 | 5809 | else => { |
| 6012 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | |
| 6013 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; | |
| 5810 | const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index; | |
| 6014 | 5811 | return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, ""); |
| 6015 | 5812 | }, |
| 6016 | 5813 | }, |
| 6017 | 5814 | .Union => { |
| 6018 | assert(struct_ty.containerLayout() == .Packed); | |
| 5815 | assert(struct_ty.containerLayout(mod) == .Packed); | |
| 6019 | 5816 | const containing_int = struct_llvm_val; |
| 6020 | 5817 | const elem_llvm_ty = try self.dg.lowerType(field_ty); |
| 6021 | if (field_ty.zigTypeTag() == .Float or field_ty.zigTypeTag() == .Vector) { | |
| 6022 | const elem_bits = @intCast(c_uint, field_ty.bitSize(target)); | |
| 5818 | if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) { | |
| 5819 | const elem_bits = @intCast(c_uint, field_ty.bitSize(mod)); | |
| 6023 | 5820 | const same_size_int = self.context.intType(elem_bits); |
| 6024 | 5821 | const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, ""); |
| 6025 | 5822 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); |
| 6026 | } else if (field_ty.isPtrAtRuntime()) { | |
| 6027 | const elem_bits = @intCast(c_uint, field_ty.bitSize(target)); | |
| 5823 | } else if (field_ty.isPtrAtRuntime(mod)) { | |
| 5824 | const elem_bits = @intCast(c_uint, field_ty.bitSize(mod)); | |
| 6028 | 5825 | const same_size_int = self.context.intType(elem_bits); |
| 6029 | 5826 | const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, ""); |
| 6030 | 5827 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); |
| ... | ... | @@ -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 | 5836 | .Struct => { |
| 6040 | assert(struct_ty.containerLayout() != .Packed); | |
| 6041 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | |
| 6042 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; | |
| 5837 | assert(struct_ty.containerLayout(mod) != .Packed); | |
| 5838 | const llvm_field = llvmField(struct_ty, field_index, mod).?; | |
| 6043 | 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, ""); | |
| 6045 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | |
| 6046 | if (isByRef(field_ty)) { | |
| 5840 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field.index, ""); | |
| 5841 | const field_ptr_ty = try mod.ptrType(.{ | |
| 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 | 5848 | if (canElideLoad(self, body_tail)) |
| 6048 | 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 | 5853 | } else { |
| 6052 | 5854 | return self.load(field_ptr, field_ptr_ty); |
| 6053 | 5855 | } |
| 6054 | 5856 | }, |
| 6055 | 5857 | .Union => { |
| 6056 | 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 | 5860 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); |
| 6059 | 5861 | const field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_llvm_val, payload_index, ""); |
| 6060 | 5862 | const llvm_field_ty = try self.dg.lowerType(field_ty); |
| 6061 | if (isByRef(field_ty)) { | |
| 5863 | if (isByRef(field_ty, mod)) { | |
| 6062 | 5864 | if (canElideLoad(self, body_tail)) |
| 6063 | 5865 | return field_ptr; |
| 6064 | 5866 | |
| ... | ... | @@ -6072,14 +5874,15 @@ pub const FuncGen = struct { |
| 6072 | 5874 | } |
| 6073 | 5875 | |
| 6074 | 5876 | fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5877 | const mod = self.dg.module; | |
| 6075 | 5878 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6076 | 5879 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 6077 | 5880 | |
| 6078 | 5881 | const field_ptr = try self.resolveInst(extra.field_ptr); |
| 6079 | 5882 | |
| 6080 | 5883 | const target = self.dg.module.getTarget(); |
| 6081 | const parent_ty = self.air.getRefType(ty_pl.ty).childType(); | |
| 6082 | const field_offset = parent_ty.structFieldOffset(extra.field_index, target); | |
| 5884 | const parent_ty = self.air.getRefType(ty_pl.ty).childType(mod); | |
| 5885 | const field_offset = parent_ty.structFieldOffset(extra.field_index, mod); | |
| 6083 | 5886 | |
| 6084 | 5887 | const res_ty = try self.dg.lowerType(self.air.getRefType(ty_pl.ty)); |
| 6085 | 5888 | if (field_offset == 0) { |
| ... | ... | @@ -6120,12 +5923,13 @@ pub const FuncGen = struct { |
| 6120 | 5923 | |
| 6121 | 5924 | fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6122 | 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 | 5930 | const decl_index = func.owner_decl; |
| 6127 | const decl = self.dg.module.declPtr(decl_index); | |
| 6128 | const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope); | |
| 5931 | const decl = mod.declPtr(decl_index); | |
| 5932 | const di_file = try self.dg.object.getDIFile(self.gpa, mod.namespacePtr(decl.src_namespace).file_scope); | |
| 6129 | 5933 | self.di_file = di_file; |
| 6130 | 5934 | const line_number = decl.src_line + 1; |
| 6131 | 5935 | const cur_debug_location = self.builder.getCurrentDebugLocation2(); |
| ... | ... | @@ -6136,22 +5940,37 @@ pub const FuncGen = struct { |
| 6136 | 5940 | .base_line = self.base_line, |
| 6137 | 5941 | }); |
| 6138 | 5942 | |
| 6139 | const fqn = try decl.getFullyQualifiedName(self.dg.module); | |
| 6140 | defer self.gpa.free(fqn); | |
| 6141 | ||
| 6142 | const is_internal_linkage = !self.dg.module.decl_exports.contains(decl_index); | |
| 5943 | const fqn = try decl.getFullyQualifiedName(mod); | |
| 5944 | ||
| 5945 | const is_internal_linkage = !mod.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 | 5962 | const subprogram = dib.createFunction( |
| 6144 | 5963 | di_file.toScope(), |
| 6145 | decl.name, | |
| 6146 | fqn, | |
| 5964 | mod.intern_pool.stringToSlice(decl.name), | |
| 5965 | mod.intern_pool.stringToSlice(fqn), | |
| 6147 | 5966 | di_file, |
| 6148 | 5967 | line_number, |
| 6149 | try self.dg.object.lowerDebugType(Type.initTag(.fn_void_no_args), .full), | |
| 5968 | fn_di_ty, | |
| 6150 | 5969 | is_internal_linkage, |
| 6151 | 5970 | true, // is definition |
| 6152 | 5971 | line_number + func.lbrace_line, // scope line |
| 6153 | 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 | 5974 | null, // decl_subprogram |
| 6156 | 5975 | ); |
| 6157 | 5976 | |
| ... | ... | @@ -6163,12 +5982,12 @@ pub const FuncGen = struct { |
| 6163 | 5982 | |
| 6164 | 5983 | fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6165 | 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 | 5987 | const mod = self.dg.module; |
| 5988 | const func = mod.funcPtr(ty_fn.func); | |
| 6170 | 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 | 5991 | self.di_file = di_file; |
| 6173 | 5992 | const old = self.dbg_inlined.pop(); |
| 6174 | 5993 | self.di_scope = old.scope; |
| ... | ... | @@ -6192,18 +6011,19 @@ pub const FuncGen = struct { |
| 6192 | 6011 | } |
| 6193 | 6012 | |
| 6194 | 6013 | fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6014 | const mod = self.dg.module; | |
| 6195 | 6015 | const dib = self.dg.object.di_builder orelse return null; |
| 6196 | 6016 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 6197 | 6017 | const operand = try self.resolveInst(pl_op.operand); |
| 6198 | 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 | 6021 | const di_local_var = dib.createAutoVariable( |
| 6202 | 6022 | self.di_scope.?, |
| 6203 | 6023 | name.ptr, |
| 6204 | 6024 | self.di_file.?, |
| 6205 | 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 | 6027 | true, // always preserve |
| 6208 | 6028 | 0, // flags |
| 6209 | 6029 | ); |
| ... | ... | @@ -6221,7 +6041,7 @@ pub const FuncGen = struct { |
| 6221 | 6041 | const dib = self.dg.object.di_builder orelse return null; |
| 6222 | 6042 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 6223 | 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 | 6045 | const name = self.air.nullTerminatedString(pl_op.payload); |
| 6226 | 6046 | |
| 6227 | 6047 | if (needDbgVarWorkaround(self.dg)) { |
| ... | ... | @@ -6243,10 +6063,11 @@ pub const FuncGen = struct { |
| 6243 | 6063 | null; |
| 6244 | 6064 | const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at); |
| 6245 | 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 | 6068 | _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block); |
| 6248 | 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 | 6071 | const alloca = self.buildAlloca(operand.typeOf(), alignment); |
| 6251 | 6072 | const store_inst = self.builder.buildStore(operand, alloca); |
| 6252 | 6073 | store_inst.setAlignment(alignment); |
| ... | ... | @@ -6294,7 +6115,8 @@ pub const FuncGen = struct { |
| 6294 | 6115 | // This stores whether we need to add an elementtype attribute and |
| 6295 | 6116 | // if so, the element type itself. |
| 6296 | 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 | 6121 | var llvm_ret_i: usize = 0; |
| 6300 | 6122 | var llvm_param_i: usize = 0; |
| ... | ... | @@ -6321,9 +6143,9 @@ pub const FuncGen = struct { |
| 6321 | 6143 | llvm_ret_indirect[i] = (output != .none) and constraintAllowsMemory(constraint); |
| 6322 | 6144 | if (output != .none) { |
| 6323 | 6145 | const output_inst = try self.resolveInst(output); |
| 6324 | const output_ty = self.air.typeOf(output); | |
| 6325 | assert(output_ty.zigTypeTag() == .Pointer); | |
| 6326 | const elem_llvm_ty = try self.dg.lowerPtrElemTy(output_ty.childType()); | |
| 6146 | const output_ty = self.typeOf(output); | |
| 6147 | assert(output_ty.zigTypeTag(mod) == .Pointer); | |
| 6148 | const elem_llvm_ty = try self.dg.lowerPtrElemTy(output_ty.childType(mod)); | |
| 6327 | 6149 | |
| 6328 | 6150 | if (llvm_ret_indirect[i]) { |
| 6329 | 6151 | // Pass the result by reference as an indirect output (e.g. "=*m") |
| ... | ... | @@ -6339,7 +6161,7 @@ pub const FuncGen = struct { |
| 6339 | 6161 | llvm_ret_i += 1; |
| 6340 | 6162 | } |
| 6341 | 6163 | } else { |
| 6342 | const ret_ty = self.air.typeOfIndex(inst); | |
| 6164 | const ret_ty = self.typeOfIndex(inst); | |
| 6343 | 6165 | llvm_ret_types[llvm_ret_i] = try self.dg.lowerType(ret_ty); |
| 6344 | 6166 | llvm_ret_i += 1; |
| 6345 | 6167 | } |
| ... | ... | @@ -6374,15 +6196,15 @@ pub const FuncGen = struct { |
| 6374 | 6196 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 6375 | 6197 | |
| 6376 | 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 | 6200 | var llvm_elem_ty: ?*llvm.Type = null; |
| 6379 | if (isByRef(arg_ty)) { | |
| 6201 | if (isByRef(arg_ty, mod)) { | |
| 6380 | 6202 | llvm_elem_ty = try self.dg.lowerPtrElemTy(arg_ty); |
| 6381 | 6203 | if (constraintAllowsMemory(constraint)) { |
| 6382 | 6204 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6383 | 6205 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf(); |
| 6384 | 6206 | } else { |
| 6385 | const alignment = arg_ty.abiAlignment(target); | |
| 6207 | const alignment = arg_ty.abiAlignment(mod); | |
| 6386 | 6208 | const arg_llvm_ty = try self.dg.lowerType(arg_ty); |
| 6387 | 6209 | const load_inst = self.builder.buildLoad(arg_llvm_ty, arg_llvm_value, ""); |
| 6388 | 6210 | load_inst.setAlignment(alignment); |
| ... | ... | @@ -6394,7 +6216,7 @@ pub const FuncGen = struct { |
| 6394 | 6216 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6395 | 6217 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf(); |
| 6396 | 6218 | } else { |
| 6397 | const alignment = arg_ty.abiAlignment(target); | |
| 6219 | const alignment = arg_ty.abiAlignment(mod); | |
| 6398 | 6220 | const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment); |
| 6399 | 6221 | const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr); |
| 6400 | 6222 | store_inst.setAlignment(alignment); |
| ... | ... | @@ -6424,7 +6246,7 @@ pub const FuncGen = struct { |
| 6424 | 6246 | // an elementtype(<ty>) attribute. |
| 6425 | 6247 | if (constraint[0] == '*') { |
| 6426 | 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 | 6250 | } else { |
| 6429 | 6251 | llvm_param_attrs[llvm_param_i] = null; |
| 6430 | 6252 | } |
| ... | ... | @@ -6596,10 +6418,10 @@ pub const FuncGen = struct { |
| 6596 | 6418 | |
| 6597 | 6419 | if (output != .none) { |
| 6598 | 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 | 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 | 6425 | } else { |
| 6604 | 6426 | ret_val = output_value; |
| 6605 | 6427 | } |
| ... | ... | @@ -6615,22 +6437,21 @@ pub const FuncGen = struct { |
| 6615 | 6437 | operand_is_ptr: bool, |
| 6616 | 6438 | pred: llvm.IntPredicate, |
| 6617 | 6439 | ) !?*llvm.Value { |
| 6440 | const mod = self.dg.module; | |
| 6618 | 6441 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6619 | 6442 | const operand = try self.resolveInst(un_op); |
| 6620 | const operand_ty = self.air.typeOf(un_op); | |
| 6621 | const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | |
| 6443 | const operand_ty = self.typeOf(un_op); | |
| 6444 | const optional_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; | |
| 6622 | 6445 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); |
| 6623 | var buf: Type.Payload.ElemType = undefined; | |
| 6624 | const payload_ty = optional_ty.optionalChild(&buf); | |
| 6625 | if (optional_ty.optionalReprIsPayload()) { | |
| 6446 | const payload_ty = optional_ty.optionalChild(mod); | |
| 6447 | if (optional_ty.optionalReprIsPayload(mod)) { | |
| 6626 | 6448 | const loaded = if (operand_is_ptr) |
| 6627 | 6449 | self.builder.buildLoad(optional_llvm_ty, operand, "") |
| 6628 | 6450 | else |
| 6629 | 6451 | operand; |
| 6630 | if (payload_ty.isSlice()) { | |
| 6452 | if (payload_ty.isSlice(mod)) { | |
| 6631 | 6453 | const slice_ptr = self.builder.buildExtractValue(loaded, 0, ""); |
| 6632 | var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 6633 | const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(&slice_buf)); | |
| 6454 | const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(mod)); | |
| 6634 | 6455 | return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), ""); |
| 6635 | 6456 | } |
| 6636 | 6457 | return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); |
| ... | ... | @@ -6638,7 +6459,7 @@ pub const FuncGen = struct { |
| 6638 | 6459 | |
| 6639 | 6460 | comptime assert(optional_layout_version == 3); |
| 6640 | 6461 | |
| 6641 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6462 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6642 | 6463 | const loaded = if (operand_is_ptr) |
| 6643 | 6464 | self.builder.buildLoad(optional_llvm_ty, operand, "") |
| 6644 | 6465 | else |
| ... | ... | @@ -6647,7 +6468,7 @@ pub const FuncGen = struct { |
| 6647 | 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 | 6472 | const non_null_bit = self.optIsNonNull(optional_llvm_ty, operand, is_by_ref); |
| 6652 | 6473 | if (pred == .EQ) { |
| 6653 | 6474 | return self.builder.buildNot(non_null_bit, ""); |
| ... | ... | @@ -6662,15 +6483,16 @@ pub const FuncGen = struct { |
| 6662 | 6483 | op: llvm.IntPredicate, |
| 6663 | 6484 | operand_is_ptr: bool, |
| 6664 | 6485 | ) !?*llvm.Value { |
| 6486 | const mod = self.dg.module; | |
| 6665 | 6487 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6666 | 6488 | const operand = try self.resolveInst(un_op); |
| 6667 | const operand_ty = self.air.typeOf(un_op); | |
| 6668 | const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | |
| 6669 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 6489 | const operand_ty = self.typeOf(un_op); | |
| 6490 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; | |
| 6491 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 6670 | 6492 | const err_set_ty = try self.dg.lowerType(Type.anyerror); |
| 6671 | 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 | 6496 | const llvm_i1 = self.context.intType(1); |
| 6675 | 6497 | switch (op) { |
| 6676 | 6498 | .EQ => return llvm_i1.constInt(1, .False), // 0 == 0 |
| ... | ... | @@ -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 | 6505 | const loaded = if (operand_is_ptr) |
| 6684 | 6506 | self.builder.buildLoad(try self.dg.lowerType(err_union_ty), operand, "") |
| 6685 | 6507 | else |
| ... | ... | @@ -6687,10 +6509,9 @@ pub const FuncGen = struct { |
| 6687 | 6509 | return self.builder.buildICmp(op, loaded, zero, ""); |
| 6688 | 6510 | } |
| 6689 | 6511 | |
| 6690 | const target = self.dg.module.getTarget(); | |
| 6691 | const err_field_index = errUnionErrorOffset(payload_ty, target); | |
| 6512 | const err_field_index = errUnionErrorOffset(payload_ty, mod); | |
| 6692 | 6513 | |
| 6693 | if (operand_is_ptr or isByRef(err_union_ty)) { | |
| 6514 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { | |
| 6694 | 6515 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); |
| 6695 | 6516 | const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, ""); |
| 6696 | 6517 | const loaded = self.builder.buildLoad(err_set_ty, err_field_ptr, ""); |
| ... | ... | @@ -6702,17 +6523,17 @@ pub const FuncGen = struct { |
| 6702 | 6523 | } |
| 6703 | 6524 | |
| 6704 | 6525 | fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6526 | const mod = self.dg.module; | |
| 6705 | 6527 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6706 | 6528 | const operand = try self.resolveInst(ty_op.operand); |
| 6707 | const optional_ty = self.air.typeOf(ty_op.operand).childType(); | |
| 6708 | var buf: Type.Payload.ElemType = undefined; | |
| 6709 | const payload_ty = optional_ty.optionalChild(&buf); | |
| 6710 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6529 | const optional_ty = self.typeOf(ty_op.operand).childType(mod); | |
| 6530 | const payload_ty = optional_ty.optionalChild(mod); | |
| 6531 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6711 | 6532 | // We have a pointer to a zero-bit value and we need to return |
| 6712 | 6533 | // a pointer to a zero-bit value. |
| 6713 | 6534 | return operand; |
| 6714 | 6535 | } |
| 6715 | if (optional_ty.optionalReprIsPayload()) { | |
| 6536 | if (optional_ty.optionalReprIsPayload(mod)) { | |
| 6716 | 6537 | // The payload and the optional are the same value. |
| 6717 | 6538 | return operand; |
| 6718 | 6539 | } |
| ... | ... | @@ -6723,18 +6544,18 @@ pub const FuncGen = struct { |
| 6723 | 6544 | fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6724 | 6545 | comptime assert(optional_layout_version == 3); |
| 6725 | 6546 | |
| 6547 | const mod = self.dg.module; | |
| 6726 | 6548 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6727 | 6549 | const operand = try self.resolveInst(ty_op.operand); |
| 6728 | const optional_ty = self.air.typeOf(ty_op.operand).childType(); | |
| 6729 | var buf: Type.Payload.ElemType = undefined; | |
| 6730 | const payload_ty = optional_ty.optionalChild(&buf); | |
| 6550 | const optional_ty = self.typeOf(ty_op.operand).childType(mod); | |
| 6551 | const payload_ty = optional_ty.optionalChild(mod); | |
| 6731 | 6552 | const non_null_bit = self.context.intType(8).constInt(1, .False); |
| 6732 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6553 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6733 | 6554 | // We have a pointer to a i8. We need to set it to 1 and then return the same pointer. |
| 6734 | 6555 | _ = self.builder.buildStore(non_null_bit, operand); |
| 6735 | 6556 | return operand; |
| 6736 | 6557 | } |
| 6737 | if (optional_ty.optionalReprIsPayload()) { | |
| 6558 | if (optional_ty.optionalReprIsPayload(mod)) { | |
| 6738 | 6559 | // The payload and the optional are the same value. |
| 6739 | 6560 | // Setting to non-null will be done when the payload is set. |
| 6740 | 6561 | return operand; |
| ... | ... | @@ -6754,20 +6575,21 @@ pub const FuncGen = struct { |
| 6754 | 6575 | } |
| 6755 | 6576 | |
| 6756 | 6577 | fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 6578 | const mod = self.dg.module; | |
| 6757 | 6579 | const inst = body_tail[0]; |
| 6758 | 6580 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6759 | 6581 | const operand = try self.resolveInst(ty_op.operand); |
| 6760 | const optional_ty = self.air.typeOf(ty_op.operand); | |
| 6761 | const payload_ty = self.air.typeOfIndex(inst); | |
| 6762 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null; | |
| 6582 | const optional_ty = self.typeOf(ty_op.operand); | |
| 6583 | const payload_ty = self.typeOfIndex(inst); | |
| 6584 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; | |
| 6763 | 6585 | |
| 6764 | if (optional_ty.optionalReprIsPayload()) { | |
| 6586 | if (optional_ty.optionalReprIsPayload(mod)) { | |
| 6765 | 6587 | // Payload value is the same as the optional value. |
| 6766 | 6588 | return operand; |
| 6767 | 6589 | } |
| 6768 | 6590 | |
| 6769 | 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 | 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 | 6598 | body_tail: []const Air.Inst.Index, |
| 6777 | 6599 | operand_is_ptr: bool, |
| 6778 | 6600 | ) !?*llvm.Value { |
| 6601 | const mod = self.dg.module; | |
| 6779 | 6602 | const inst = body_tail[0]; |
| 6780 | 6603 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6781 | 6604 | const operand = try self.resolveInst(ty_op.operand); |
| 6782 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 6783 | const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | |
| 6784 | const result_ty = self.air.typeOfIndex(inst); | |
| 6785 | const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty; | |
| 6786 | const target = self.dg.module.getTarget(); | |
| 6605 | const operand_ty = self.typeOf(ty_op.operand); | |
| 6606 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; | |
| 6607 | const result_ty = self.typeOfIndex(inst); | |
| 6608 | const payload_ty = if (operand_is_ptr) result_ty.childType(mod) else result_ty; | |
| 6787 | 6609 | |
| 6788 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6610 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6789 | 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 | 6614 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); |
| 6793 | 6615 | if (operand_is_ptr) { |
| 6794 | 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 | 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 | 6620 | if (self.canElideLoad(body_tail)) |
| 6799 | 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 | 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 | 6627 | return load_inst; |
| 6806 | 6628 | } |
| 6807 | 6629 | return self.builder.buildExtractValue(operand, offset, ""); |
| ... | ... | @@ -6812,11 +6634,12 @@ pub const FuncGen = struct { |
| 6812 | 6634 | inst: Air.Inst.Index, |
| 6813 | 6635 | operand_is_ptr: bool, |
| 6814 | 6636 | ) !?*llvm.Value { |
| 6637 | const mod = self.dg.module; | |
| 6815 | 6638 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6816 | 6639 | const operand = try self.resolveInst(ty_op.operand); |
| 6817 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 6818 | const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | |
| 6819 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { | |
| 6640 | const operand_ty = self.typeOf(ty_op.operand); | |
| 6641 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; | |
| 6642 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { | |
| 6820 | 6643 | const err_llvm_ty = try self.dg.lowerType(Type.anyerror); |
| 6821 | 6644 | if (operand_is_ptr) { |
| 6822 | 6645 | return operand; |
| ... | ... | @@ -6827,16 +6650,15 @@ pub const FuncGen = struct { |
| 6827 | 6650 | |
| 6828 | 6651 | const err_set_llvm_ty = try self.dg.lowerType(Type.anyerror); |
| 6829 | 6652 | |
| 6830 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 6831 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6653 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 6654 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6832 | 6655 | if (!operand_is_ptr) return operand; |
| 6833 | 6656 | return self.builder.buildLoad(err_set_llvm_ty, operand, ""); |
| 6834 | 6657 | } |
| 6835 | 6658 | |
| 6836 | const target = self.dg.module.getTarget(); | |
| 6837 | const offset = errUnionErrorOffset(payload_ty, target); | |
| 6659 | const offset = errUnionErrorOffset(payload_ty, mod); | |
| 6838 | 6660 | |
| 6839 | if (operand_is_ptr or isByRef(err_union_ty)) { | |
| 6661 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { | |
| 6840 | 6662 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); |
| 6841 | 6663 | const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); |
| 6842 | 6664 | return self.builder.buildLoad(err_set_llvm_ty, err_field_ptr, ""); |
| ... | ... | @@ -6846,30 +6668,30 @@ pub const FuncGen = struct { |
| 6846 | 6668 | } |
| 6847 | 6669 | |
| 6848 | 6670 | fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6671 | const mod = self.dg.module; | |
| 6849 | 6672 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6850 | 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(); | |
| 6854 | const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = Value.zero }); | |
| 6855 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6676 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 6677 | const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.err_int, 0) }); | |
| 6678 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6856 | 6679 | _ = self.builder.buildStore(non_error_val, operand); |
| 6857 | 6680 | return operand; |
| 6858 | 6681 | } |
| 6859 | const target = self.dg.module.getTarget(); | |
| 6860 | 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 | 6685 | // First set the non-error value. |
| 6864 | 6686 | const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, ""); |
| 6865 | 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 | 6690 | // Then return the payload pointer (only if it is used). |
| 6869 | 6691 | if (self.liveness.isUnused(inst)) |
| 6870 | 6692 | return null; |
| 6871 | 6693 | |
| 6872 | const payload_offset = errUnionPayloadOffset(payload_ty, target); | |
| 6694 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); | |
| 6873 | 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 | 6707 | } |
| 6886 | 6708 | |
| 6887 | 6709 | fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6888 | const target = self.dg.module.getTarget(); | |
| 6889 | ||
| 6890 | 6710 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6891 | 6711 | //const struct_ty = try self.resolveInst(ty_pl.ty); |
| 6892 | 6712 | const struct_ty = self.air.getRefType(ty_pl.ty); |
| 6893 | 6713 | const field_index = ty_pl.payload; |
| 6894 | 6714 | |
| 6895 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | |
| 6896 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; | |
| 6715 | const mod = self.dg.module; | |
| 6716 | const llvm_field = llvmField(struct_ty, field_index, mod).?; | |
| 6897 | 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, ""); | |
| 6899 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | |
| 6718 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field.index, ""); | |
| 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 | 6725 | return self.load(field_ptr, field_ptr_ty); |
| 6901 | 6726 | } |
| 6902 | 6727 | |
| 6903 | 6728 | fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6729 | const mod = self.dg.module; | |
| 6904 | 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 | 6732 | const non_null_bit = self.context.intType(8).constInt(1, .False); |
| 6907 | 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 | 6735 | const operand = try self.resolveInst(ty_op.operand); |
| 6910 | const optional_ty = self.air.typeOfIndex(inst); | |
| 6911 | if (optional_ty.optionalReprIsPayload()) { | |
| 6736 | const optional_ty = self.typeOfIndex(inst); | |
| 6737 | if (optional_ty.optionalReprIsPayload(mod)) { | |
| 6912 | 6738 | return operand; |
| 6913 | 6739 | } |
| 6914 | 6740 | const llvm_optional_ty = try self.dg.lowerType(optional_ty); |
| 6915 | if (isByRef(optional_ty)) { | |
| 6916 | const target = self.dg.module.getTarget(); | |
| 6917 | const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(target)); | |
| 6741 | if (isByRef(optional_ty, mod)) { | |
| 6742 | const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(mod)); | |
| 6918 | 6743 | const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, ""); |
| 6919 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 6920 | .base = .{ .tag = .single_mut_pointer }, | |
| 6921 | .data = payload_ty, | |
| 6922 | }; | |
| 6923 | const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 6744 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); | |
| 6924 | 6745 | try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); |
| 6925 | 6746 | const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, ""); |
| 6926 | 6747 | _ = self.builder.buildStore(non_null_bit, non_null_ptr); |
| ... | ... | @@ -6931,30 +6752,26 @@ pub const FuncGen = struct { |
| 6931 | 6752 | } |
| 6932 | 6753 | |
| 6933 | 6754 | fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6755 | const mod = self.dg.module; | |
| 6934 | 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 | 6758 | const operand = try self.resolveInst(ty_op.operand); |
| 6937 | const payload_ty = self.air.typeOf(ty_op.operand); | |
| 6938 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6759 | const payload_ty = self.typeOf(ty_op.operand); | |
| 6760 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6939 | 6761 | return operand; |
| 6940 | 6762 | } |
| 6941 | 6763 | const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull(); |
| 6942 | 6764 | const err_un_llvm_ty = try self.dg.lowerType(err_un_ty); |
| 6943 | 6765 | |
| 6944 | const target = self.dg.module.getTarget(); | |
| 6945 | const payload_offset = errUnionPayloadOffset(payload_ty, target); | |
| 6946 | const error_offset = errUnionErrorOffset(payload_ty, target); | |
| 6947 | if (isByRef(err_un_ty)) { | |
| 6948 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target)); | |
| 6766 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); | |
| 6767 | const error_offset = errUnionErrorOffset(payload_ty, mod); | |
| 6768 | if (isByRef(err_un_ty, mod)) { | |
| 6769 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod)); | |
| 6949 | 6770 | const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 6950 | 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 | 6773 | const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 6953 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 6954 | .base = .{ .tag = .single_mut_pointer }, | |
| 6955 | .data = payload_ty, | |
| 6956 | }; | |
| 6957 | const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 6774 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); | |
| 6958 | 6775 | try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); |
| 6959 | 6776 | return result_ptr; |
| 6960 | 6777 | } |
| ... | ... | @@ -6964,29 +6781,25 @@ pub const FuncGen = struct { |
| 6964 | 6781 | } |
| 6965 | 6782 | |
| 6966 | 6783 | fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6784 | const mod = self.dg.module; | |
| 6967 | 6785 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6968 | const err_un_ty = self.air.typeOfIndex(inst); | |
| 6969 | const payload_ty = err_un_ty.errorUnionPayload(); | |
| 6786 | const err_un_ty = self.typeOfIndex(inst); | |
| 6787 | const payload_ty = err_un_ty.errorUnionPayload(mod); | |
| 6970 | 6788 | const operand = try self.resolveInst(ty_op.operand); |
| 6971 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 6789 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 6972 | 6790 | return operand; |
| 6973 | 6791 | } |
| 6974 | 6792 | const err_un_llvm_ty = try self.dg.lowerType(err_un_ty); |
| 6975 | 6793 | |
| 6976 | const target = self.dg.module.getTarget(); | |
| 6977 | const payload_offset = errUnionPayloadOffset(payload_ty, target); | |
| 6978 | const error_offset = errUnionErrorOffset(payload_ty, target); | |
| 6979 | if (isByRef(err_un_ty)) { | |
| 6980 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target)); | |
| 6794 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); | |
| 6795 | const error_offset = errUnionErrorOffset(payload_ty, mod); | |
| 6796 | if (isByRef(err_un_ty, mod)) { | |
| 6797 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod)); | |
| 6981 | 6798 | const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 6982 | 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 | 6801 | const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 6985 | var ptr_ty_payload: Type.Payload.ElemType = .{ | |
| 6986 | .base = .{ .tag = .single_mut_pointer }, | |
| 6987 | .data = payload_ty, | |
| 6988 | }; | |
| 6989 | const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); | |
| 6802 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); | |
| 6990 | 6803 | // TODO store undef to payload_ptr |
| 6991 | 6804 | _ = payload_ptr; |
| 6992 | 6805 | _ = payload_ptr_ty; |
| ... | ... | @@ -7021,20 +6834,20 @@ pub const FuncGen = struct { |
| 7021 | 6834 | } |
| 7022 | 6835 | |
| 7023 | 6836 | fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6837 | const mod = self.dg.module; | |
| 7024 | 6838 | const data = self.air.instructions.items(.data)[inst].vector_store_elem; |
| 7025 | 6839 | const extra = self.air.extraData(Air.Bin, data.payload).data; |
| 7026 | 6840 | |
| 7027 | 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 | 6843 | const index = try self.resolveInst(extra.lhs); |
| 7030 | 6844 | const operand = try self.resolveInst(extra.rhs); |
| 7031 | 6845 | |
| 7032 | 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 | 6848 | const load_inst = self.builder.buildLoad(elem_llvm_ty, vector_ptr, ""); |
| 7035 | const target = self.dg.module.getTarget(); | |
| 7036 | load_inst.setAlignment(vector_ptr_ty.ptrAlignment(target)); | |
| 7037 | load_inst.setVolatile(llvm.Bool.fromBool(vector_ptr_ty.isVolatilePtr())); | |
| 6849 | load_inst.setAlignment(vector_ptr_ty.ptrAlignment(mod)); | |
| 6850 | load_inst.setVolatile(llvm.Bool.fromBool(vector_ptr_ty.isVolatilePtr(mod))); | |
| 7038 | 6851 | break :blk load_inst; |
| 7039 | 6852 | }; |
| 7040 | 6853 | const modified_vector = self.builder.buildInsertElement(loaded_vector, operand, index, ""); |
| ... | ... | @@ -7043,24 +6856,26 @@ pub const FuncGen = struct { |
| 7043 | 6856 | } |
| 7044 | 6857 | |
| 7045 | 6858 | fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6859 | const mod = self.dg.module; | |
| 7046 | 6860 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7047 | 6861 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7048 | 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 | 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 | 6867 | return self.builder.buildUMin(lhs, rhs, ""); |
| 7054 | 6868 | } |
| 7055 | 6869 | |
| 7056 | 6870 | fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6871 | const mod = self.dg.module; | |
| 7057 | 6872 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7058 | 6873 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7059 | 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 | 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 | 6879 | return self.builder.buildUMax(lhs, rhs, ""); |
| 7065 | 6880 | } |
| 7066 | 6881 | |
| ... | ... | @@ -7069,7 +6884,7 @@ pub const FuncGen = struct { |
| 7069 | 6884 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7070 | 6885 | const ptr = try self.resolveInst(bin_op.lhs); |
| 7071 | 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 | 6888 | const llvm_slice_ty = try self.dg.lowerType(inst_ty); |
| 7074 | 6889 | |
| 7075 | 6890 | // In case of slicing a global, the result type looks something like `{ i8*, i64 }` |
| ... | ... | @@ -7081,14 +6896,15 @@ pub const FuncGen = struct { |
| 7081 | 6896 | fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7082 | 6897 | self.builder.setFastMath(want_fast_math); |
| 7083 | 6898 | |
| 6899 | const mod = self.dg.module; | |
| 7084 | 6900 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7085 | 6901 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7086 | 6902 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7087 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7088 | const scalar_ty = inst_ty.scalarType(); | |
| 6903 | const inst_ty = self.typeOfIndex(inst); | |
| 6904 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7089 | 6905 | |
| 7090 | 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 | 6908 | return self.builder.buildNUWAdd(lhs, rhs, ""); |
| 7093 | 6909 | } |
| 7094 | 6910 | |
| ... | ... | @@ -7103,14 +6919,15 @@ pub const FuncGen = struct { |
| 7103 | 6919 | } |
| 7104 | 6920 | |
| 7105 | 6921 | fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6922 | const mod = self.dg.module; | |
| 7106 | 6923 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7107 | 6924 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7108 | 6925 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7109 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7110 | const scalar_ty = inst_ty.scalarType(); | |
| 6926 | const inst_ty = self.typeOfIndex(inst); | |
| 6927 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7111 | 6928 | |
| 7112 | 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 | 6932 | return self.builder.buildUAddSat(lhs, rhs, ""); |
| 7116 | 6933 | } |
| ... | ... | @@ -7118,14 +6935,15 @@ pub const FuncGen = struct { |
| 7118 | 6935 | fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7119 | 6936 | self.builder.setFastMath(want_fast_math); |
| 7120 | 6937 | |
| 6938 | const mod = self.dg.module; | |
| 7121 | 6939 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7122 | 6940 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7123 | 6941 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7124 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7125 | const scalar_ty = inst_ty.scalarType(); | |
| 6942 | const inst_ty = self.typeOfIndex(inst); | |
| 6943 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7126 | 6944 | |
| 7127 | 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 | 6947 | return self.builder.buildNUWSub(lhs, rhs, ""); |
| 7130 | 6948 | } |
| 7131 | 6949 | |
| ... | ... | @@ -7140,28 +6958,30 @@ pub const FuncGen = struct { |
| 7140 | 6958 | } |
| 7141 | 6959 | |
| 7142 | 6960 | fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6961 | const mod = self.dg.module; | |
| 7143 | 6962 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7144 | 6963 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7145 | 6964 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7146 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7147 | const scalar_ty = inst_ty.scalarType(); | |
| 6965 | const inst_ty = self.typeOfIndex(inst); | |
| 6966 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7148 | 6967 | |
| 7149 | 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 | 6970 | return self.builder.buildUSubSat(lhs, rhs, ""); |
| 7152 | 6971 | } |
| 7153 | 6972 | |
| 7154 | 6973 | fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7155 | 6974 | self.builder.setFastMath(want_fast_math); |
| 7156 | 6975 | |
| 6976 | const mod = self.dg.module; | |
| 7157 | 6977 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7158 | 6978 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7159 | 6979 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7160 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7161 | const scalar_ty = inst_ty.scalarType(); | |
| 6980 | const inst_ty = self.typeOfIndex(inst); | |
| 6981 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7162 | 6982 | |
| 7163 | 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 | 6985 | return self.builder.buildNUWMul(lhs, rhs, ""); |
| 7166 | 6986 | } |
| 7167 | 6987 | |
| ... | ... | @@ -7176,14 +6996,15 @@ pub const FuncGen = struct { |
| 7176 | 6996 | } |
| 7177 | 6997 | |
| 7178 | 6998 | fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6999 | const mod = self.dg.module; | |
| 7179 | 7000 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7180 | 7001 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7181 | 7002 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7182 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7183 | const scalar_ty = inst_ty.scalarType(); | |
| 7003 | const inst_ty = self.typeOfIndex(inst); | |
| 7004 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7184 | 7005 | |
| 7185 | 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 | 7008 | return self.builder.buildUMulFixSat(lhs, rhs, ""); |
| 7188 | 7009 | } |
| 7189 | 7010 | |
| ... | ... | @@ -7193,7 +7014,7 @@ pub const FuncGen = struct { |
| 7193 | 7014 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7194 | 7015 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7195 | 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 | 7019 | return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); |
| 7199 | 7020 | } |
| ... | ... | @@ -7201,39 +7022,40 @@ pub const FuncGen = struct { |
| 7201 | 7022 | fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7202 | 7023 | self.builder.setFastMath(want_fast_math); |
| 7203 | 7024 | |
| 7025 | const mod = self.dg.module; | |
| 7204 | 7026 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7205 | 7027 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7206 | 7028 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7207 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7208 | const scalar_ty = inst_ty.scalarType(); | |
| 7029 | const inst_ty = self.typeOfIndex(inst); | |
| 7030 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7209 | 7031 | |
| 7210 | 7032 | if (scalar_ty.isRuntimeFloat()) { |
| 7211 | 7033 | const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); |
| 7212 | 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 | 7037 | return self.builder.buildUDiv(lhs, rhs, ""); |
| 7216 | 7038 | } |
| 7217 | 7039 | |
| 7218 | 7040 | fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7219 | 7041 | self.builder.setFastMath(want_fast_math); |
| 7220 | 7042 | |
| 7043 | const mod = self.dg.module; | |
| 7221 | 7044 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7222 | 7045 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7223 | 7046 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7224 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7225 | const scalar_ty = inst_ty.scalarType(); | |
| 7047 | const inst_ty = self.typeOfIndex(inst); | |
| 7048 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7226 | 7049 | |
| 7227 | 7050 | if (scalar_ty.isRuntimeFloat()) { |
| 7228 | 7051 | const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); |
| 7229 | 7052 | return self.buildFloatOp(.floor, inst_ty, 1, .{result}); |
| 7230 | 7053 | } |
| 7231 | if (scalar_ty.isSignedInt()) { | |
| 7232 | const target = self.dg.module.getTarget(); | |
| 7054 | if (scalar_ty.isSignedInt(mod)) { | |
| 7233 | 7055 | const inst_llvm_ty = try self.dg.lowerType(inst_ty); |
| 7234 | const scalar_bit_size_minus_one = scalar_ty.bitSize(target) - 1; | |
| 7235 | const bit_size_minus_one = if (inst_ty.zigTypeTag() == .Vector) const_vector: { | |
| 7236 | const vec_len = inst_ty.vectorLen(); | |
| 7056 | const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1; | |
| 7057 | const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: { | |
| 7058 | const vec_len = inst_ty.vectorLen(mod); | |
| 7237 | 7059 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 7238 | 7060 | |
| 7239 | 7061 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); |
| ... | ... | @@ -7258,40 +7080,43 @@ pub const FuncGen = struct { |
| 7258 | 7080 | fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7259 | 7081 | self.builder.setFastMath(want_fast_math); |
| 7260 | 7082 | |
| 7083 | const mod = self.dg.module; | |
| 7261 | 7084 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7262 | 7085 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7263 | 7086 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7264 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7265 | const scalar_ty = inst_ty.scalarType(); | |
| 7087 | const inst_ty = self.typeOfIndex(inst); | |
| 7088 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7266 | 7089 | |
| 7267 | 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 | 7092 | return self.builder.buildExactUDiv(lhs, rhs, ""); |
| 7270 | 7093 | } |
| 7271 | 7094 | |
| 7272 | 7095 | fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7273 | 7096 | self.builder.setFastMath(want_fast_math); |
| 7274 | 7097 | |
| 7098 | const mod = self.dg.module; | |
| 7275 | 7099 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7276 | 7100 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7277 | 7101 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7278 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7279 | const scalar_ty = inst_ty.scalarType(); | |
| 7102 | const inst_ty = self.typeOfIndex(inst); | |
| 7103 | const scalar_ty = inst_ty.scalarType(mod); | |
| 7280 | 7104 | |
| 7281 | 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 | 7107 | return self.builder.buildURem(lhs, rhs, ""); |
| 7284 | 7108 | } |
| 7285 | 7109 | |
| 7286 | 7110 | fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7287 | 7111 | self.builder.setFastMath(want_fast_math); |
| 7288 | 7112 | |
| 7113 | const mod = self.dg.module; | |
| 7289 | 7114 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7290 | 7115 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7291 | 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 | 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 | 7121 | if (scalar_ty.isRuntimeFloat()) { |
| 7297 | 7122 | const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs }); |
| ... | ... | @@ -7301,11 +7126,10 @@ pub const FuncGen = struct { |
| 7301 | 7126 | const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero }); |
| 7302 | 7127 | return self.builder.buildSelect(ltz, c, a, ""); |
| 7303 | 7128 | } |
| 7304 | if (scalar_ty.isSignedInt()) { | |
| 7305 | const target = self.dg.module.getTarget(); | |
| 7306 | const scalar_bit_size_minus_one = scalar_ty.bitSize(target) - 1; | |
| 7307 | const bit_size_minus_one = if (inst_ty.zigTypeTag() == .Vector) const_vector: { | |
| 7308 | const vec_len = inst_ty.vectorLen(); | |
| 7129 | if (scalar_ty.isSignedInt(mod)) { | |
| 7130 | const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1; | |
| 7131 | const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: { | |
| 7132 | const vec_len = inst_ty.vectorLen(mod); | |
| 7309 | 7133 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 7310 | 7134 | |
| 7311 | 7135 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); |
| ... | ... | @@ -7328,13 +7152,14 @@ pub const FuncGen = struct { |
| 7328 | 7152 | } |
| 7329 | 7153 | |
| 7330 | 7154 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7155 | const mod = self.dg.module; | |
| 7331 | 7156 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7332 | 7157 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7333 | 7158 | const ptr = try self.resolveInst(bin_op.lhs); |
| 7334 | 7159 | const offset = try self.resolveInst(bin_op.rhs); |
| 7335 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 7336 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); | |
| 7337 | switch (ptr_ty.ptrSize()) { | |
| 7160 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 7161 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType(mod)); | |
| 7162 | switch (ptr_ty.ptrSize(mod)) { | |
| 7338 | 7163 | .One => { |
| 7339 | 7164 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7340 | 7165 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), offset }; |
| ... | ... | @@ -7353,14 +7178,15 @@ pub const FuncGen = struct { |
| 7353 | 7178 | } |
| 7354 | 7179 | |
| 7355 | 7180 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7181 | const mod = self.dg.module; | |
| 7356 | 7182 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7357 | 7183 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7358 | 7184 | const ptr = try self.resolveInst(bin_op.lhs); |
| 7359 | 7185 | const offset = try self.resolveInst(bin_op.rhs); |
| 7360 | 7186 | const negative_offset = self.builder.buildNeg(offset, ""); |
| 7361 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 7362 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); | |
| 7363 | switch (ptr_ty.ptrSize()) { | |
| 7187 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 7188 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType(mod)); | |
| 7189 | switch (ptr_ty.ptrSize(mod)) { | |
| 7364 | 7190 | .One => { |
| 7365 | 7191 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7366 | 7192 | const indices: [2]*llvm.Value = .{ |
| ... | ... | @@ -7386,36 +7212,33 @@ pub const FuncGen = struct { |
| 7386 | 7212 | signed_intrinsic: []const u8, |
| 7387 | 7213 | unsigned_intrinsic: []const u8, |
| 7388 | 7214 | ) !?*llvm.Value { |
| 7215 | const mod = self.dg.module; | |
| 7389 | 7216 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7390 | 7217 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7391 | 7218 | |
| 7392 | 7219 | const lhs = try self.resolveInst(extra.lhs); |
| 7393 | 7220 | const rhs = try self.resolveInst(extra.rhs); |
| 7394 | 7221 | |
| 7395 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 7396 | const scalar_ty = lhs_ty.scalarType(); | |
| 7397 | const dest_ty = self.air.typeOfIndex(inst); | |
| 7222 | const lhs_ty = self.typeOf(extra.lhs); | |
| 7223 | const scalar_ty = lhs_ty.scalarType(mod); | |
| 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 | 7228 | const llvm_lhs_ty = try self.dg.lowerType(lhs_ty); |
| 7402 | 7229 | const llvm_dest_ty = try self.dg.lowerType(dest_ty); |
| 7403 | 7230 | |
| 7404 | const tg = self.dg.module.getTarget(); | |
| 7405 | ||
| 7406 | 7231 | const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty}); |
| 7407 | 7232 | const result_struct = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &[_]*llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, ""); |
| 7408 | 7233 | |
| 7409 | 7234 | const result = self.builder.buildExtractValue(result_struct, 0, ""); |
| 7410 | 7235 | const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); |
| 7411 | 7236 | |
| 7412 | var ty_buf: Type.Payload.Pointer = undefined; | |
| 7413 | const result_index = llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?; | |
| 7414 | const overflow_index = llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?; | |
| 7237 | const result_index = llvmField(dest_ty, 0, mod).?.index; | |
| 7238 | const overflow_index = llvmField(dest_ty, 1, mod).?.index; | |
| 7415 | 7239 | |
| 7416 | if (isByRef(dest_ty)) { | |
| 7417 | const target = self.dg.module.getTarget(); | |
| 7418 | const result_alignment = dest_ty.abiAlignment(target); | |
| 7240 | if (isByRef(dest_ty, mod)) { | |
| 7241 | const result_alignment = dest_ty.abiAlignment(mod); | |
| 7419 | 7242 | const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment); |
| 7420 | 7243 | { |
| 7421 | 7244 | const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, ""); |
| ... | ... | @@ -7486,8 +7309,9 @@ pub const FuncGen = struct { |
| 7486 | 7309 | ty: Type, |
| 7487 | 7310 | params: [2]*llvm.Value, |
| 7488 | 7311 | ) !*llvm.Value { |
| 7312 | const mod = self.dg.module; | |
| 7489 | 7313 | const target = self.dg.module.getTarget(); |
| 7490 | const scalar_ty = ty.scalarType(); | |
| 7314 | const scalar_ty = ty.scalarType(mod); | |
| 7491 | 7315 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 7492 | 7316 | |
| 7493 | 7317 | if (intrinsicsAllowed(scalar_ty, target)) { |
| ... | ... | @@ -7531,8 +7355,8 @@ pub const FuncGen = struct { |
| 7531 | 7355 | .gte => .SGE, |
| 7532 | 7356 | }; |
| 7533 | 7357 | |
| 7534 | if (ty.zigTypeTag() == .Vector) { | |
| 7535 | const vec_len = ty.vectorLen(); | |
| 7358 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 7359 | const vec_len = ty.vectorLen(mod); | |
| 7536 | 7360 | const vector_result_ty = llvm_i32.vectorType(vec_len); |
| 7537 | 7361 | |
| 7538 | 7362 | var result = vector_result_ty.getUndef(); |
| ... | ... | @@ -7587,8 +7411,9 @@ pub const FuncGen = struct { |
| 7587 | 7411 | comptime params_len: usize, |
| 7588 | 7412 | params: [params_len]*llvm.Value, |
| 7589 | 7413 | ) !*llvm.Value { |
| 7590 | const target = self.dg.module.getTarget(); | |
| 7591 | const scalar_ty = ty.scalarType(); | |
| 7414 | const mod = self.dg.module; | |
| 7415 | const target = mod.getTarget(); | |
| 7416 | const scalar_ty = ty.scalarType(mod); | |
| 7592 | 7417 | const llvm_ty = try self.dg.lowerType(ty); |
| 7593 | 7418 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 7594 | 7419 | |
| ... | ... | @@ -7615,9 +7440,9 @@ pub const FuncGen = struct { |
| 7615 | 7440 | const one = int_llvm_ty.constInt(1, .False); |
| 7616 | 7441 | const shift_amt = int_llvm_ty.constInt(float_bits - 1, .False); |
| 7617 | 7442 | const sign_mask = one.constShl(shift_amt); |
| 7618 | const result = if (ty.zigTypeTag() == .Vector) blk: { | |
| 7619 | const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(), sign_mask, ""); | |
| 7620 | const cast_ty = int_llvm_ty.vectorType(ty.vectorLen()); | |
| 7443 | const result = if (ty.zigTypeTag(mod) == .Vector) blk: { | |
| 7444 | const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(mod), sign_mask, ""); | |
| 7445 | const cast_ty = int_llvm_ty.vectorType(ty.vectorLen(mod)); | |
| 7621 | 7446 | const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty, ""); |
| 7622 | 7447 | break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, ""); |
| 7623 | 7448 | } else blk: { |
| ... | ... | @@ -7662,9 +7487,9 @@ pub const FuncGen = struct { |
| 7662 | 7487 | .libc => |fn_name| b: { |
| 7663 | 7488 | const param_types = [3]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty, scalar_llvm_ty }; |
| 7664 | 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 | 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 | 7495 | break :b libc_fn; |
| ... | ... | @@ -7681,47 +7506,44 @@ pub const FuncGen = struct { |
| 7681 | 7506 | const mulend2 = try self.resolveInst(extra.rhs); |
| 7682 | 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 | 7510 | return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend }); |
| 7686 | 7511 | } |
| 7687 | 7512 | |
| 7688 | 7513 | fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7514 | const mod = self.dg.module; | |
| 7689 | 7515 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7690 | 7516 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7691 | 7517 | |
| 7692 | 7518 | const lhs = try self.resolveInst(extra.lhs); |
| 7693 | 7519 | const rhs = try self.resolveInst(extra.rhs); |
| 7694 | 7520 | |
| 7695 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 7696 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 7697 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 7698 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 7521 | const lhs_ty = self.typeOf(extra.lhs); | |
| 7522 | const rhs_ty = self.typeOf(extra.rhs); | |
| 7523 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 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 | 7527 | const llvm_dest_ty = try self.dg.lowerType(dest_ty); |
| 7702 | 7528 | |
| 7703 | const tg = self.dg.module.getTarget(); | |
| 7704 | ||
| 7705 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) | |
| 7529 | const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod)) | |
| 7706 | 7530 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") |
| 7707 | 7531 | else |
| 7708 | 7532 | rhs; |
| 7709 | 7533 | |
| 7710 | 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 | 7536 | self.builder.buildAShr(result, casted_rhs, "") |
| 7713 | 7537 | else |
| 7714 | 7538 | self.builder.buildLShr(result, casted_rhs, ""); |
| 7715 | 7539 | |
| 7716 | 7540 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); |
| 7717 | 7541 | |
| 7718 | var ty_buf: Type.Payload.Pointer = undefined; | |
| 7719 | const result_index = llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?; | |
| 7720 | const overflow_index = llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?; | |
| 7542 | const result_index = llvmField(dest_ty, 0, mod).?.index; | |
| 7543 | const overflow_index = llvmField(dest_ty, 1, mod).?.index; | |
| 7721 | 7544 | |
| 7722 | if (isByRef(dest_ty)) { | |
| 7723 | const target = self.dg.module.getTarget(); | |
| 7724 | const result_alignment = dest_ty.abiAlignment(target); | |
| 7545 | if (isByRef(dest_ty, mod)) { | |
| 7546 | const result_alignment = dest_ty.abiAlignment(mod); | |
| 7725 | 7547 | const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment); |
| 7726 | 7548 | { |
| 7727 | 7549 | const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, ""); |
| ... | ... | @@ -7763,40 +7585,38 @@ pub const FuncGen = struct { |
| 7763 | 7585 | } |
| 7764 | 7586 | |
| 7765 | 7587 | fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7588 | const mod = self.dg.module; | |
| 7766 | 7589 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7767 | 7590 | |
| 7768 | 7591 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7769 | 7592 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7770 | 7593 | |
| 7771 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 7772 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 7773 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 7774 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 7775 | ||
| 7776 | const tg = self.dg.module.getTarget(); | |
| 7594 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 7595 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 7596 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 7597 | const rhs_scalar_ty = rhs_ty.scalarType(mod); | |
| 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 | 7600 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") |
| 7780 | 7601 | else |
| 7781 | 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 | 7604 | return self.builder.buildNUWShl(lhs, casted_rhs, ""); |
| 7784 | 7605 | } |
| 7785 | 7606 | |
| 7786 | 7607 | fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7608 | const mod = self.dg.module; | |
| 7787 | 7609 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7788 | 7610 | |
| 7789 | 7611 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7790 | 7612 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7791 | 7613 | |
| 7792 | const lhs_type = self.air.typeOf(bin_op.lhs); | |
| 7793 | const rhs_type = self.air.typeOf(bin_op.rhs); | |
| 7794 | const lhs_scalar_ty = lhs_type.scalarType(); | |
| 7795 | const rhs_scalar_ty = rhs_type.scalarType(); | |
| 7796 | ||
| 7797 | const tg = self.dg.module.getTarget(); | |
| 7614 | const lhs_type = self.typeOf(bin_op.lhs); | |
| 7615 | const rhs_type = self.typeOf(bin_op.rhs); | |
| 7616 | const lhs_scalar_ty = lhs_type.scalarType(mod); | |
| 7617 | const rhs_scalar_ty = rhs_type.scalarType(mod); | |
| 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 | 7620 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_type), "") |
| 7801 | 7621 | else |
| 7802 | 7622 | rhs; |
| ... | ... | @@ -7804,24 +7624,24 @@ pub const FuncGen = struct { |
| 7804 | 7624 | } |
| 7805 | 7625 | |
| 7806 | 7626 | fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7627 | const mod = self.dg.module; | |
| 7807 | 7628 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7808 | 7629 | |
| 7809 | 7630 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7810 | 7631 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7811 | 7632 | |
| 7812 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 7813 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 7814 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 7815 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 7816 | const tg = self.dg.module.getTarget(); | |
| 7817 | const lhs_bits = lhs_scalar_ty.bitSize(tg); | |
| 7633 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 7634 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 7635 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 7636 | const rhs_scalar_ty = rhs_ty.scalarType(mod); | |
| 7637 | const lhs_bits = lhs_scalar_ty.bitSize(mod); | |
| 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 | 7640 | self.builder.buildZExt(rhs, lhs.typeOf(), "") |
| 7821 | 7641 | else |
| 7822 | 7642 | rhs; |
| 7823 | 7643 | |
| 7824 | const result = if (lhs_scalar_ty.isSignedInt()) | |
| 7644 | const result = if (lhs_scalar_ty.isSignedInt(mod)) | |
| 7825 | 7645 | self.builder.buildSShlSat(lhs, casted_rhs, "") |
| 7826 | 7646 | else |
| 7827 | 7647 | self.builder.buildUShlSat(lhs, casted_rhs, ""); |
| ... | ... | @@ -7834,8 +7654,8 @@ pub const FuncGen = struct { |
| 7834 | 7654 | const lhs_scalar_llvm_ty = try self.dg.lowerType(lhs_scalar_ty); |
| 7835 | 7655 | const bits = lhs_scalar_llvm_ty.constInt(lhs_bits, .False); |
| 7836 | 7656 | const lhs_max = lhs_scalar_llvm_ty.constAllOnes(); |
| 7837 | if (rhs_ty.zigTypeTag() == .Vector) { | |
| 7838 | const vec_len = rhs_ty.vectorLen(); | |
| 7657 | if (rhs_ty.zigTypeTag(mod) == .Vector) { | |
| 7658 | const vec_len = rhs_ty.vectorLen(mod); | |
| 7839 | 7659 | const bits_vec = self.builder.buildVectorSplat(vec_len, bits, ""); |
| 7840 | 7660 | const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, ""); |
| 7841 | 7661 | const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, ""); |
| ... | ... | @@ -7847,23 +7667,22 @@ pub const FuncGen = struct { |
| 7847 | 7667 | } |
| 7848 | 7668 | |
| 7849 | 7669 | fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*llvm.Value { |
| 7670 | const mod = self.dg.module; | |
| 7850 | 7671 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7851 | 7672 | |
| 7852 | 7673 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7853 | 7674 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7854 | 7675 | |
| 7855 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 7856 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 7857 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 7858 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 7676 | const lhs_ty = self.typeOf(bin_op.lhs); | |
| 7677 | const rhs_ty = self.typeOf(bin_op.rhs); | |
| 7678 | const lhs_scalar_ty = lhs_ty.scalarType(mod); | |
| 7679 | const rhs_scalar_ty = rhs_ty.scalarType(mod); | |
| 7859 | 7680 | |
| 7860 | const tg = self.dg.module.getTarget(); | |
| 7861 | ||
| 7862 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) | |
| 7681 | const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod)) | |
| 7863 | 7682 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") |
| 7864 | 7683 | else |
| 7865 | 7684 | rhs; |
| 7866 | const is_signed_int = lhs_scalar_ty.isSignedInt(); | |
| 7685 | const is_signed_int = lhs_scalar_ty.isSignedInt(mod); | |
| 7867 | 7686 | |
| 7868 | 7687 | if (is_exact) { |
| 7869 | 7688 | if (is_signed_int) { |
| ... | ... | @@ -7881,14 +7700,14 @@ pub const FuncGen = struct { |
| 7881 | 7700 | } |
| 7882 | 7701 | |
| 7883 | 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 | 7704 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7886 | const dest_ty = self.air.typeOfIndex(inst); | |
| 7887 | const dest_info = dest_ty.intInfo(target); | |
| 7705 | const dest_ty = self.typeOfIndex(inst); | |
| 7706 | const dest_info = dest_ty.intInfo(mod); | |
| 7888 | 7707 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| 7889 | 7708 | const operand = try self.resolveInst(ty_op.operand); |
| 7890 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 7891 | const operand_info = operand_ty.intInfo(target); | |
| 7709 | const operand_ty = self.typeOf(ty_op.operand); | |
| 7710 | const operand_info = operand_ty.intInfo(mod); | |
| 7892 | 7711 | |
| 7893 | 7712 | if (operand_info.bits < dest_info.bits) { |
| 7894 | 7713 | switch (operand_info.signedness) { |
| ... | ... | @@ -7905,16 +7724,17 @@ pub const FuncGen = struct { |
| 7905 | 7724 | fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7906 | 7725 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7907 | 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 | 7728 | return self.builder.buildTrunc(operand, dest_llvm_ty, ""); |
| 7910 | 7729 | } |
| 7911 | 7730 | |
| 7912 | 7731 | fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7732 | const mod = self.dg.module; | |
| 7913 | 7733 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7914 | 7734 | const operand = try self.resolveInst(ty_op.operand); |
| 7915 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 7916 | const dest_ty = self.air.typeOfIndex(inst); | |
| 7917 | const target = self.dg.module.getTarget(); | |
| 7735 | const operand_ty = self.typeOf(ty_op.operand); | |
| 7736 | const dest_ty = self.typeOfIndex(inst); | |
| 7737 | const target = mod.getTarget(); | |
| 7918 | 7738 | const dest_bits = dest_ty.floatBits(target); |
| 7919 | 7739 | const src_bits = operand_ty.floatBits(target); |
| 7920 | 7740 | |
| ... | ... | @@ -7939,11 +7759,12 @@ pub const FuncGen = struct { |
| 7939 | 7759 | } |
| 7940 | 7760 | |
| 7941 | 7761 | fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7762 | const mod = self.dg.module; | |
| 7942 | 7763 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7943 | 7764 | const operand = try self.resolveInst(ty_op.operand); |
| 7944 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 7945 | const dest_ty = self.air.typeOfIndex(inst); | |
| 7946 | const target = self.dg.module.getTarget(); | |
| 7765 | const operand_ty = self.typeOf(ty_op.operand); | |
| 7766 | const dest_ty = self.typeOfIndex(inst); | |
| 7767 | const target = mod.getTarget(); | |
| 7947 | 7768 | const dest_bits = dest_ty.floatBits(target); |
| 7948 | 7769 | const src_bits = operand_ty.floatBits(target); |
| 7949 | 7770 | |
| ... | ... | @@ -7970,25 +7791,25 @@ pub const FuncGen = struct { |
| 7970 | 7791 | fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7971 | 7792 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 7972 | 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 | 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 | 7797 | return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, ""); |
| 7977 | 7798 | } |
| 7978 | 7799 | |
| 7979 | 7800 | fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !*llvm.Value { |
| 7980 | 7801 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7981 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 7982 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7802 | const operand_ty = self.typeOf(ty_op.operand); | |
| 7803 | const inst_ty = self.typeOfIndex(inst); | |
| 7983 | 7804 | const operand = try self.resolveInst(ty_op.operand); |
| 7984 | 7805 | return self.bitCast(operand, operand_ty, inst_ty); |
| 7985 | 7806 | } |
| 7986 | 7807 | |
| 7987 | 7808 | fn bitCast(self: *FuncGen, operand: *llvm.Value, operand_ty: Type, inst_ty: Type) !*llvm.Value { |
| 7988 | const operand_is_ref = isByRef(operand_ty); | |
| 7989 | const result_is_ref = isByRef(inst_ty); | |
| 7809 | const mod = self.dg.module; | |
| 7810 | const operand_is_ref = isByRef(operand_ty, mod); | |
| 7811 | const result_is_ref = isByRef(inst_ty, mod); | |
| 7990 | 7812 | const llvm_dest_ty = try self.dg.lowerType(inst_ty); |
| 7991 | const target = self.dg.module.getTarget(); | |
| 7992 | 7813 | |
| 7993 | 7814 | if (operand_is_ref and result_is_ref) { |
| 7994 | 7815 | // They are both pointers, so just return the same opaque pointer :) |
| ... | ... | @@ -8001,27 +7822,27 @@ pub const FuncGen = struct { |
| 8001 | 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 | 7826 | return self.builder.buildIntToPtr(operand, llvm_dest_ty, ""); |
| 8006 | 7827 | } |
| 8007 | 7828 | |
| 8008 | if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) { | |
| 8009 | const elem_ty = operand_ty.childType(); | |
| 7829 | if (operand_ty.zigTypeTag(mod) == .Vector and inst_ty.zigTypeTag(mod) == .Array) { | |
| 7830 | const elem_ty = operand_ty.childType(mod); | |
| 8010 | 7831 | if (!result_is_ref) { |
| 8011 | 7832 | return self.dg.todo("implement bitcast vector to non-ref array", .{}); |
| 8012 | 7833 | } |
| 8013 | 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 | 7836 | if (bitcast_ok) { |
| 8016 | 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 | 7839 | } else { |
| 8019 | 7840 | // If the ABI size of the element type is not evenly divisible by size in bits; |
| 8020 | 7841 | // a simple bitcast will not work, and we fall back to extractelement. |
| 8021 | 7842 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 8022 | 7843 | const llvm_u32 = self.context.intType(32); |
| 8023 | 7844 | const zero = llvm_usize.constNull(); |
| 8024 | const vector_len = operand_ty.arrayLen(); | |
| 7845 | const vector_len = operand_ty.arrayLen(mod); | |
| 8025 | 7846 | var i: u64 = 0; |
| 8026 | 7847 | while (i < vector_len) : (i += 1) { |
| 8027 | 7848 | const index_usize = llvm_usize.constInt(i, .False); |
| ... | ... | @@ -8033,19 +7854,19 @@ pub const FuncGen = struct { |
| 8033 | 7854 | } |
| 8034 | 7855 | } |
| 8035 | 7856 | return array_ptr; |
| 8036 | } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) { | |
| 8037 | const elem_ty = operand_ty.childType(); | |
| 7857 | } else if (operand_ty.zigTypeTag(mod) == .Array and inst_ty.zigTypeTag(mod) == .Vector) { | |
| 7858 | const elem_ty = operand_ty.childType(mod); | |
| 8038 | 7859 | const llvm_vector_ty = try self.dg.lowerType(inst_ty); |
| 8039 | 7860 | if (!operand_is_ref) { |
| 8040 | 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 | 7865 | if (bitcast_ok) { |
| 8045 | 7866 | const vector = self.builder.buildLoad(llvm_vector_ty, operand, ""); |
| 8046 | 7867 | // The array is aligned to the element's alignment, while the vector might have a completely |
| 8047 | 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 | 7870 | return vector; |
| 8050 | 7871 | } else { |
| 8051 | 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 | 7876 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 8056 | 7877 | const llvm_u32 = self.context.intType(32); |
| 8057 | 7878 | const zero = llvm_usize.constNull(); |
| 8058 | const vector_len = operand_ty.arrayLen(); | |
| 7879 | const vector_len = operand_ty.arrayLen(mod); | |
| 8059 | 7880 | var vector = llvm_vector_ty.getUndef(); |
| 8060 | 7881 | var i: u64 = 0; |
| 8061 | 7882 | while (i < vector_len) : (i += 1) { |
| ... | ... | @@ -8073,12 +7894,12 @@ pub const FuncGen = struct { |
| 8073 | 7894 | |
| 8074 | 7895 | if (operand_is_ref) { |
| 8075 | 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 | 7898 | return load_inst; |
| 8078 | 7899 | } |
| 8079 | 7900 | |
| 8080 | 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 | 7903 | const result_ptr = self.buildAlloca(llvm_dest_ty, alignment); |
| 8083 | 7904 | const store_inst = self.builder.buildStore(operand, result_ptr); |
| 8084 | 7905 | store_inst.setAlignment(alignment); |
| ... | ... | @@ -8089,7 +7910,7 @@ pub const FuncGen = struct { |
| 8089 | 7910 | // Both our operand and our result are values, not pointers, |
| 8090 | 7911 | // but LLVM won't let us bitcast struct values. |
| 8091 | 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 | 7914 | const result_ptr = self.buildAlloca(llvm_dest_ty, alignment); |
| 8094 | 7915 | const store_inst = self.builder.buildStore(operand, result_ptr); |
| 8095 | 7916 | store_inst.setAlignment(alignment); |
| ... | ... | @@ -8108,22 +7929,23 @@ pub const FuncGen = struct { |
| 8108 | 7929 | } |
| 8109 | 7930 | |
| 8110 | 7931 | fn airArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7932 | const mod = self.dg.module; | |
| 8111 | 7933 | const arg_val = self.args[self.arg_index]; |
| 8112 | 7934 | self.arg_index += 1; |
| 8113 | 7935 | |
| 8114 | const inst_ty = self.air.typeOfIndex(inst); | |
| 7936 | const inst_ty = self.typeOfIndex(inst); | |
| 8115 | 7937 | if (self.dg.object.di_builder) |dib| { |
| 8116 | 7938 | if (needDbgVarWorkaround(self.dg)) { |
| 8117 | 7939 | return arg_val; |
| 8118 | 7940 | } |
| 8119 | 7941 | |
| 8120 | 7942 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 8121 | const func = self.dg.decl.getFunction().?; | |
| 8122 | const lbrace_line = self.dg.module.declPtr(func.owner_decl).src_line + func.lbrace_line + 1; | |
| 7943 | const func = self.dg.decl.getOwnedFunction(mod).?; | |
| 7944 | const lbrace_line = mod.declPtr(func.owner_decl).src_line + func.lbrace_line + 1; | |
| 8123 | 7945 | const lbrace_col = func.lbrace_column + 1; |
| 8124 | 7946 | const di_local_var = dib.createParameterVariable( |
| 8125 | 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 | 7949 | self.di_file.?, |
| 8128 | 7950 | lbrace_line, |
| 8129 | 7951 | try self.dg.object.lowerDebugType(inst_ty, .full), |
| ... | ... | @@ -8134,10 +7956,10 @@ pub const FuncGen = struct { |
| 8134 | 7956 | |
| 8135 | 7957 | const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null); |
| 8136 | 7958 | const insert_block = self.builder.getInsertBlock(); |
| 8137 | if (isByRef(inst_ty)) { | |
| 7959 | if (isByRef(inst_ty, mod)) { | |
| 8138 | 7960 | _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block); |
| 8139 | 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 | 7963 | const alloca = self.buildAlloca(arg_val.typeOf(), alignment); |
| 8142 | 7964 | const store_inst = self.builder.buildStore(arg_val, alloca); |
| 8143 | 7965 | store_inst.setAlignment(alignment); |
| ... | ... | @@ -8151,24 +7973,24 @@ pub const FuncGen = struct { |
| 8151 | 7973 | } |
| 8152 | 7974 | |
| 8153 | 7975 | fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8154 | const ptr_ty = self.air.typeOfIndex(inst); | |
| 8155 | const pointee_type = ptr_ty.childType(); | |
| 8156 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 7976 | const mod = self.dg.module; | |
| 7977 | const ptr_ty = self.typeOfIndex(inst); | |
| 7978 | const pointee_type = ptr_ty.childType(mod); | |
| 7979 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 8157 | 7980 | |
| 8158 | 7981 | const pointee_llvm_ty = try self.dg.lowerType(pointee_type); |
| 8159 | const target = self.dg.module.getTarget(); | |
| 8160 | const alignment = ptr_ty.ptrAlignment(target); | |
| 7982 | const alignment = ptr_ty.ptrAlignment(mod); | |
| 8161 | 7983 | return self.buildAlloca(pointee_llvm_ty, alignment); |
| 8162 | 7984 | } |
| 8163 | 7985 | |
| 8164 | 7986 | fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8165 | const ptr_ty = self.air.typeOfIndex(inst); | |
| 8166 | const ret_ty = ptr_ty.childType(); | |
| 8167 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 7987 | const mod = self.dg.module; | |
| 7988 | const ptr_ty = self.typeOfIndex(inst); | |
| 7989 | const ret_ty = ptr_ty.childType(mod); | |
| 7990 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return self.dg.lowerPtrToVoid(ptr_ty); | |
| 8168 | 7991 | if (self.ret_ptr) |ret_ptr| return ret_ptr; |
| 8169 | 7992 | const ret_llvm_ty = try self.dg.lowerType(ret_ty); |
| 8170 | const target = self.dg.module.getTarget(); | |
| 8171 | return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(target)); | |
| 7993 | return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod)); | |
| 8172 | 7994 | } |
| 8173 | 7995 | |
| 8174 | 7996 | /// Use this instead of builder.buildAlloca, because this function makes sure to |
| ... | ... | @@ -8178,12 +8000,13 @@ pub const FuncGen = struct { |
| 8178 | 8000 | } |
| 8179 | 8001 | |
| 8180 | 8002 | fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value { |
| 8003 | const mod = self.dg.module; | |
| 8181 | 8004 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8182 | 8005 | const dest_ptr = try self.resolveInst(bin_op.lhs); |
| 8183 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 8184 | const operand_ty = ptr_ty.childType(); | |
| 8006 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 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 | 8010 | if (val_is_undef) { |
| 8188 | 8011 | // Even if safety is disabled, we still emit a memset to undefined since it conveys |
| 8189 | 8012 | // extra information to LLVM. However, safety makes the difference between using |
| ... | ... | @@ -8193,13 +8016,12 @@ pub const FuncGen = struct { |
| 8193 | 8016 | u8_llvm_ty.constInt(0xaa, .False) |
| 8194 | 8017 | else |
| 8195 | 8018 | u8_llvm_ty.getUndef(); |
| 8196 | const target = self.dg.module.getTarget(); | |
| 8197 | const operand_size = operand_ty.abiSize(target); | |
| 8019 | const operand_size = operand_ty.abiSize(mod); | |
| 8198 | 8020 | const usize_llvm_ty = try self.dg.lowerType(Type.usize); |
| 8199 | 8021 | const len = usize_llvm_ty.constInt(operand_size, .False); |
| 8200 | const dest_ptr_align = ptr_ty.ptrAlignment(target); | |
| 8201 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr()); | |
| 8202 | if (safety and self.dg.module.comp.bin_file.options.valgrind) { | |
| 8022 | const dest_ptr_align = ptr_ty.ptrAlignment(mod); | |
| 8023 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr(mod)); | |
| 8024 | if (safety and mod.comp.bin_file.options.valgrind) { | |
| 8203 | 8025 | self.valgrindMarkUndef(dest_ptr, len); |
| 8204 | 8026 | } |
| 8205 | 8027 | return null; |
| ... | ... | @@ -8217,8 +8039,10 @@ pub const FuncGen = struct { |
| 8217 | 8039 | /// |
| 8218 | 8040 | /// The first instruction of `body_tail` is the one whose copy we want to elide. |
| 8219 | 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 | 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 | 8046 | .none => continue, |
| 8223 | 8047 | .write, .noret, .complex => return false, |
| 8224 | 8048 | .tomb => return true, |
| ... | ... | @@ -8230,14 +8054,15 @@ pub const FuncGen = struct { |
| 8230 | 8054 | } |
| 8231 | 8055 | |
| 8232 | 8056 | fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 8057 | const mod = fg.dg.module; | |
| 8233 | 8058 | const inst = body_tail[0]; |
| 8234 | 8059 | const ty_op = fg.air.instructions.items(.data)[inst].ty_op; |
| 8235 | const ptr_ty = fg.air.typeOf(ty_op.operand); | |
| 8236 | const ptr_info = ptr_ty.ptrInfo().data; | |
| 8060 | const ptr_ty = fg.typeOf(ty_op.operand); | |
| 8061 | const ptr_info = ptr_ty.ptrInfo(mod); | |
| 8237 | 8062 | const ptr = try fg.resolveInst(ty_op.operand); |
| 8238 | 8063 | |
| 8239 | 8064 | elide: { |
| 8240 | if (!isByRef(ptr_info.pointee_type)) break :elide; | |
| 8065 | if (!isByRef(ptr_info.pointee_type, mod)) break :elide; | |
| 8241 | 8066 | if (!canElideLoad(fg, body_tail)) break :elide; |
| 8242 | 8067 | return ptr; |
| 8243 | 8068 | } |
| ... | ... | @@ -8261,8 +8086,9 @@ pub const FuncGen = struct { |
| 8261 | 8086 | |
| 8262 | 8087 | fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8263 | 8088 | _ = inst; |
| 8089 | const mod = self.dg.module; | |
| 8264 | 8090 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 8265 | const target = self.dg.module.getTarget(); | |
| 8091 | const target = mod.getTarget(); | |
| 8266 | 8092 | if (!target_util.supportsReturnAddress(target)) { |
| 8267 | 8093 | // https://github.com/ziglang/zig/issues/11946 |
| 8268 | 8094 | return llvm_usize.constNull(); |
| ... | ... | @@ -8301,16 +8127,17 @@ pub const FuncGen = struct { |
| 8301 | 8127 | } |
| 8302 | 8128 | |
| 8303 | 8129 | fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !?*llvm.Value { |
| 8130 | const mod = self.dg.module; | |
| 8304 | 8131 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 8305 | 8132 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 8306 | 8133 | const ptr = try self.resolveInst(extra.ptr); |
| 8307 | 8134 | var expected_value = try self.resolveInst(extra.expected_value); |
| 8308 | 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 | 8137 | const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false); |
| 8311 | 8138 | if (opt_abi_ty) |abi_ty| { |
| 8312 | 8139 | // operand needs widening and truncating |
| 8313 | if (operand_ty.isSignedInt()) { | |
| 8140 | if (operand_ty.isSignedInt(mod)) { | |
| 8314 | 8141 | expected_value = self.builder.buildSExt(expected_value, abi_ty, ""); |
| 8315 | 8142 | new_value = self.builder.buildSExt(new_value, abi_ty, ""); |
| 8316 | 8143 | } else { |
| ... | ... | @@ -8328,7 +8155,7 @@ pub const FuncGen = struct { |
| 8328 | 8155 | ); |
| 8329 | 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 | 8160 | var payload = self.builder.buildExtractValue(result, 0, ""); |
| 8334 | 8161 | if (opt_abi_ty != null) { |
| ... | ... | @@ -8336,7 +8163,7 @@ pub const FuncGen = struct { |
| 8336 | 8163 | } |
| 8337 | 8164 | const success_bit = self.builder.buildExtractValue(result, 1, ""); |
| 8338 | 8165 | |
| 8339 | if (optional_ty.optionalReprIsPayload()) { | |
| 8166 | if (optional_ty.optionalReprIsPayload(mod)) { | |
| 8340 | 8167 | return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, ""); |
| 8341 | 8168 | } |
| 8342 | 8169 | |
| ... | ... | @@ -8347,13 +8174,14 @@ pub const FuncGen = struct { |
| 8347 | 8174 | } |
| 8348 | 8175 | |
| 8349 | 8176 | fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8177 | const mod = self.dg.module; | |
| 8350 | 8178 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8351 | 8179 | const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 8352 | 8180 | const ptr = try self.resolveInst(pl_op.operand); |
| 8353 | const ptr_ty = self.air.typeOf(pl_op.operand); | |
| 8354 | const operand_ty = ptr_ty.elemType(); | |
| 8181 | const ptr_ty = self.typeOf(pl_op.operand); | |
| 8182 | const operand_ty = ptr_ty.childType(mod); | |
| 8355 | 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 | 8185 | const is_float = operand_ty.isRuntimeFloat(); |
| 8358 | 8186 | const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float); |
| 8359 | 8187 | const ordering = toLlvmAtomicOrdering(extra.ordering()); |
| ... | ... | @@ -8402,17 +8230,17 @@ pub const FuncGen = struct { |
| 8402 | 8230 | } |
| 8403 | 8231 | |
| 8404 | 8232 | fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8233 | const mod = self.dg.module; | |
| 8405 | 8234 | const atomic_load = self.air.instructions.items(.data)[inst].atomic_load; |
| 8406 | 8235 | const ptr = try self.resolveInst(atomic_load.ptr); |
| 8407 | const ptr_ty = self.air.typeOf(atomic_load.ptr); | |
| 8408 | const ptr_info = ptr_ty.ptrInfo().data; | |
| 8236 | const ptr_ty = self.typeOf(atomic_load.ptr); | |
| 8237 | const ptr_info = ptr_ty.ptrInfo(mod); | |
| 8409 | 8238 | const elem_ty = ptr_info.pointee_type; |
| 8410 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) | |
| 8239 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 8411 | 8240 | return null; |
| 8412 | 8241 | const ordering = toLlvmAtomicOrdering(atomic_load.order); |
| 8413 | 8242 | const opt_abi_llvm_ty = self.dg.getAtomicAbiType(elem_ty, false); |
| 8414 | const target = self.dg.module.getTarget(); | |
| 8415 | const ptr_alignment = ptr_info.alignment(target); | |
| 8243 | const ptr_alignment = ptr_info.alignment(mod); | |
| 8416 | 8244 | const ptr_volatile = llvm.Bool.fromBool(ptr_info.@"volatile"); |
| 8417 | 8245 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); |
| 8418 | 8246 | |
| ... | ... | @@ -8436,17 +8264,18 @@ pub const FuncGen = struct { |
| 8436 | 8264 | inst: Air.Inst.Index, |
| 8437 | 8265 | ordering: llvm.AtomicOrdering, |
| 8438 | 8266 | ) !?*llvm.Value { |
| 8267 | const mod = self.dg.module; | |
| 8439 | 8268 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8440 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 8441 | const operand_ty = ptr_ty.childType(); | |
| 8442 | if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null; | |
| 8269 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 8270 | const operand_ty = ptr_ty.childType(mod); | |
| 8271 | if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return null; | |
| 8443 | 8272 | const ptr = try self.resolveInst(bin_op.lhs); |
| 8444 | 8273 | var element = try self.resolveInst(bin_op.rhs); |
| 8445 | 8274 | const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false); |
| 8446 | 8275 | |
| 8447 | 8276 | if (opt_abi_ty) |abi_ty| { |
| 8448 | 8277 | // operand needs widening |
| 8449 | if (operand_ty.isSignedInt()) { | |
| 8278 | if (operand_ty.isSignedInt(mod)) { | |
| 8450 | 8279 | element = self.builder.buildSExt(element, abi_ty, ""); |
| 8451 | 8280 | } else { |
| 8452 | 8281 | element = self.builder.buildZExt(element, abi_ty, ""); |
| ... | ... | @@ -8457,19 +8286,19 @@ pub const FuncGen = struct { |
| 8457 | 8286 | } |
| 8458 | 8287 | |
| 8459 | 8288 | fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value { |
| 8289 | const mod = self.dg.module; | |
| 8460 | 8290 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8461 | 8291 | const dest_slice = try self.resolveInst(bin_op.lhs); |
| 8462 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 8463 | const elem_ty = self.air.typeOf(bin_op.rhs); | |
| 8464 | const module = self.dg.module; | |
| 8465 | const target = module.getTarget(); | |
| 8466 | const dest_ptr_align = ptr_ty.ptrAlignment(target); | |
| 8292 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 8293 | const elem_ty = self.typeOf(bin_op.rhs); | |
| 8294 | const target = mod.getTarget(); | |
| 8295 | const dest_ptr_align = ptr_ty.ptrAlignment(mod); | |
| 8467 | 8296 | const u8_llvm_ty = self.context.intType(8); |
| 8468 | 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| { | |
| 8472 | if (elem_val.isUndefDeep()) { | |
| 8300 | if (try self.air.value(bin_op.rhs, mod)) |elem_val| { | |
| 8301 | if (elem_val.isUndefDeep(mod)) { | |
| 8473 | 8302 | // Even if safety is disabled, we still emit a memset to undefined since it conveys |
| 8474 | 8303 | // extra information to LLVM. However, safety makes the difference between using |
| 8475 | 8304 | // 0xaa or actual undefined for the fill byte. |
| ... | ... | @@ -8480,7 +8309,7 @@ pub const FuncGen = struct { |
| 8480 | 8309 | const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8481 | 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 | 8313 | self.valgrindMarkUndef(dest_ptr, len); |
| 8485 | 8314 | } |
| 8486 | 8315 | return null; |
| ... | ... | @@ -8490,8 +8319,7 @@ pub const FuncGen = struct { |
| 8490 | 8319 | // repeating byte pattern, for example, `@as(u64, 0)` has a |
| 8491 | 8320 | // repeating byte pattern of 0 bytes. In such case, the memset |
| 8492 | 8321 | // intrinsic can be used. |
| 8493 | var value_buffer: Value.Payload.U64 = undefined; | |
| 8494 | if (try elem_val.hasRepeatedByteRepr(elem_ty, module, &value_buffer)) |byte_val| { | |
| 8322 | if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| { | |
| 8495 | 8323 | const fill_byte = try self.resolveValue(.{ |
| 8496 | 8324 | .ty = Type.u8, |
| 8497 | 8325 | .val = byte_val, |
| ... | ... | @@ -8503,7 +8331,7 @@ pub const FuncGen = struct { |
| 8503 | 8331 | } |
| 8504 | 8332 | |
| 8505 | 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 | 8336 | if (elem_abi_size == 1) { |
| 8509 | 8337 | // In this case we can take advantage of LLVM's intrinsic. |
| ... | ... | @@ -8535,9 +8363,9 @@ pub const FuncGen = struct { |
| 8535 | 8363 | const end_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetEnd"); |
| 8536 | 8364 | |
| 8537 | 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 | 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 | 8369 | .Many, .C => unreachable, |
| 8542 | 8370 | }; |
| 8543 | 8371 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); |
| ... | ... | @@ -8551,9 +8379,9 @@ pub const FuncGen = struct { |
| 8551 | 8379 | _ = self.builder.buildCondBr(end, body_block, end_block); |
| 8552 | 8380 | |
| 8553 | 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 | 8383 | const it_ptr_alignment = @min(elem_abi_alignment, dest_ptr_align); |
| 8556 | if (isByRef(elem_ty)) { | |
| 8384 | if (isByRef(elem_ty, mod)) { | |
| 8557 | 8385 | _ = self.builder.buildMemCpy( |
| 8558 | 8386 | it_ptr, |
| 8559 | 8387 | it_ptr_alignment, |
| ... | ... | @@ -8583,19 +8411,19 @@ pub const FuncGen = struct { |
| 8583 | 8411 | fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8584 | 8412 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8585 | 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 | 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 | 8417 | const src_ptr = self.sliceOrArrayPtr(src_slice, src_ptr_ty); |
| 8590 | 8418 | const len = self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty); |
| 8591 | 8419 | const dest_ptr = self.sliceOrArrayPtr(dest_slice, dest_ptr_ty); |
| 8592 | const is_volatile = src_ptr_ty.isVolatilePtr() or dest_ptr_ty.isVolatilePtr(); | |
| 8593 | const target = self.dg.module.getTarget(); | |
| 8420 | const mod = self.dg.module; | |
| 8421 | const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod); | |
| 8594 | 8422 | _ = self.builder.buildMemCpy( |
| 8595 | 8423 | dest_ptr, |
| 8596 | dest_ptr_ty.ptrAlignment(target), | |
| 8424 | dest_ptr_ty.ptrAlignment(mod), | |
| 8597 | 8425 | src_ptr, |
| 8598 | src_ptr_ty.ptrAlignment(target), | |
| 8426 | src_ptr_ty.ptrAlignment(mod), | |
| 8599 | 8427 | len, |
| 8600 | 8428 | is_volatile, |
| 8601 | 8429 | ); |
| ... | ... | @@ -8603,10 +8431,10 @@ pub const FuncGen = struct { |
| 8603 | 8431 | } |
| 8604 | 8432 | |
| 8605 | 8433 | fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8434 | const mod = self.dg.module; | |
| 8606 | 8435 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8607 | const un_ty = self.air.typeOf(bin_op.lhs).childType(); | |
| 8608 | const target = self.dg.module.getTarget(); | |
| 8609 | const layout = un_ty.unionGetLayout(target); | |
| 8436 | const un_ty = self.typeOf(bin_op.lhs).childType(mod); | |
| 8437 | const layout = un_ty.unionGetLayout(mod); | |
| 8610 | 8438 | if (layout.tag_size == 0) return null; |
| 8611 | 8439 | const union_ptr = try self.resolveInst(bin_op.lhs); |
| 8612 | 8440 | const new_tag = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -8624,13 +8452,13 @@ pub const FuncGen = struct { |
| 8624 | 8452 | } |
| 8625 | 8453 | |
| 8626 | 8454 | fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8455 | const mod = self.dg.module; | |
| 8627 | 8456 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8628 | const un_ty = self.air.typeOf(ty_op.operand); | |
| 8629 | const target = self.dg.module.getTarget(); | |
| 8630 | const layout = un_ty.unionGetLayout(target); | |
| 8457 | const un_ty = self.typeOf(ty_op.operand); | |
| 8458 | const layout = un_ty.unionGetLayout(mod); | |
| 8631 | 8459 | if (layout.tag_size == 0) return null; |
| 8632 | 8460 | const union_handle = try self.resolveInst(ty_op.operand); |
| 8633 | if (isByRef(un_ty)) { | |
| 8461 | if (isByRef(un_ty, mod)) { | |
| 8634 | 8462 | const llvm_un_ty = try self.dg.lowerType(un_ty); |
| 8635 | 8463 | if (layout.payload_size == 0) { |
| 8636 | 8464 | return self.builder.buildLoad(llvm_un_ty, union_handle, ""); |
| ... | ... | @@ -8650,7 +8478,7 @@ pub const FuncGen = struct { |
| 8650 | 8478 | fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*llvm.Value { |
| 8651 | 8479 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8652 | 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 | 8483 | return self.buildFloatOp(op, operand_ty, 1, .{operand}); |
| 8656 | 8484 | } |
| ... | ... | @@ -8660,14 +8488,15 @@ pub const FuncGen = struct { |
| 8660 | 8488 | |
| 8661 | 8489 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8662 | 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 | 8493 | return self.buildFloatOp(.neg, operand_ty, 1, .{operand}); |
| 8666 | 8494 | } |
| 8667 | 8495 | |
| 8668 | 8496 | fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value { |
| 8497 | const mod = self.dg.module; | |
| 8669 | 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 | 8500 | const operand = try self.resolveInst(ty_op.operand); |
| 8672 | 8501 | |
| 8673 | 8502 | const llvm_i1 = self.context.intType(1); |
| ... | ... | @@ -8676,12 +8505,11 @@ pub const FuncGen = struct { |
| 8676 | 8505 | |
| 8677 | 8506 | const params = [_]*llvm.Value{ operand, llvm_i1.constNull() }; |
| 8678 | 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 | 8509 | const result_llvm_ty = try self.dg.lowerType(result_ty); |
| 8681 | 8510 | |
| 8682 | const target = self.dg.module.getTarget(); | |
| 8683 | const bits = operand_ty.intInfo(target).bits; | |
| 8684 | const result_bits = result_ty.intInfo(target).bits; | |
| 8511 | const bits = operand_ty.intInfo(mod).bits; | |
| 8512 | const result_bits = result_ty.intInfo(mod).bits; | |
| 8685 | 8513 | if (bits > result_bits) { |
| 8686 | 8514 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); |
| 8687 | 8515 | } else if (bits < result_bits) { |
| ... | ... | @@ -8692,8 +8520,9 @@ pub const FuncGen = struct { |
| 8692 | 8520 | } |
| 8693 | 8521 | |
| 8694 | 8522 | fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value { |
| 8523 | const mod = self.dg.module; | |
| 8695 | 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 | 8526 | const operand = try self.resolveInst(ty_op.operand); |
| 8698 | 8527 | |
| 8699 | 8528 | const params = [_]*llvm.Value{operand}; |
| ... | ... | @@ -8701,12 +8530,11 @@ pub const FuncGen = struct { |
| 8701 | 8530 | const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty}); |
| 8702 | 8531 | |
| 8703 | 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 | 8534 | const result_llvm_ty = try self.dg.lowerType(result_ty); |
| 8706 | 8535 | |
| 8707 | const target = self.dg.module.getTarget(); | |
| 8708 | const bits = operand_ty.intInfo(target).bits; | |
| 8709 | const result_bits = result_ty.intInfo(target).bits; | |
| 8536 | const bits = operand_ty.intInfo(mod).bits; | |
| 8537 | const result_bits = result_ty.intInfo(mod).bits; | |
| 8710 | 8538 | if (bits > result_bits) { |
| 8711 | 8539 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); |
| 8712 | 8540 | } else if (bits < result_bits) { |
| ... | ... | @@ -8717,10 +8545,10 @@ pub const FuncGen = struct { |
| 8717 | 8545 | } |
| 8718 | 8546 | |
| 8719 | 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 | 8549 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8722 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 8723 | var bits = operand_ty.intInfo(target).bits; | |
| 8550 | const operand_ty = self.typeOf(ty_op.operand); | |
| 8551 | var bits = operand_ty.intInfo(mod).bits; | |
| 8724 | 8552 | assert(bits % 8 == 0); |
| 8725 | 8553 | |
| 8726 | 8554 | var operand = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -8730,8 +8558,8 @@ pub const FuncGen = struct { |
| 8730 | 8558 | // If not an even byte-multiple, we need zero-extend + shift-left 1 byte |
| 8731 | 8559 | // The truncated result at the end will be the correct bswap |
| 8732 | 8560 | const scalar_llvm_ty = self.context.intType(bits + 8); |
| 8733 | if (operand_ty.zigTypeTag() == .Vector) { | |
| 8734 | const vec_len = operand_ty.vectorLen(); | |
| 8561 | if (operand_ty.zigTypeTag(mod) == .Vector) { | |
| 8562 | const vec_len = operand_ty.vectorLen(mod); | |
| 8735 | 8563 | operand_llvm_ty = scalar_llvm_ty.vectorType(vec_len); |
| 8736 | 8564 | |
| 8737 | 8565 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); |
| ... | ... | @@ -8757,9 +8585,9 @@ pub const FuncGen = struct { |
| 8757 | 8585 | |
| 8758 | 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 | 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 | 8591 | if (bits > result_bits) { |
| 8764 | 8592 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); |
| 8765 | 8593 | } else if (bits < result_bits) { |
| ... | ... | @@ -8770,28 +8598,23 @@ pub const FuncGen = struct { |
| 8770 | 8598 | } |
| 8771 | 8599 | |
| 8772 | 8600 | fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8601 | const mod = self.dg.module; | |
| 8773 | 8602 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8774 | 8603 | const operand = try self.resolveInst(ty_op.operand); |
| 8775 | 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 | 8607 | const valid_block = self.context.appendBasicBlock(self.llvm_func, "Valid"); |
| 8779 | 8608 | const invalid_block = self.context.appendBasicBlock(self.llvm_func, "Invalid"); |
| 8780 | 8609 | const end_block = self.context.appendBasicBlock(self.llvm_func, "End"); |
| 8781 | 8610 | const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len)); |
| 8782 | 8611 | |
| 8783 | 8612 | for (names) |name| { |
| 8784 | const err_int = self.dg.module.global_error_set.get(name).?; | |
| 8785 | const this_tag_int_value = int: { | |
| 8786 | var tag_val_payload: Value.Payload.U64 = .{ | |
| 8787 | .base = .{ .tag = .int_u64 }, | |
| 8788 | .data = err_int, | |
| 8789 | }; | |
| 8790 | break :int try self.dg.lowerValue(.{ | |
| 8791 | .ty = Type.err_int, | |
| 8792 | .val = Value.initPayload(&tag_val_payload.base), | |
| 8793 | }); | |
| 8794 | }; | |
| 8613 | const err_int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(name).?); | |
| 8614 | const this_tag_int_value = try self.dg.lowerValue(.{ | |
| 8615 | .ty = Type.err_int, | |
| 8616 | .val = try mod.intValue(Type.err_int, err_int), | |
| 8617 | }); | |
| 8795 | 8618 | switch_instr.addCase(this_tag_int_value, valid_block); |
| 8796 | 8619 | } |
| 8797 | 8620 | self.builder.positionBuilderAtEnd(valid_block); |
| ... | ... | @@ -8817,7 +8640,7 @@ pub const FuncGen = struct { |
| 8817 | 8640 | fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8818 | 8641 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8819 | 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 | 8645 | const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty); |
| 8823 | 8646 | const params = [_]*llvm.Value{operand}; |
| ... | ... | @@ -8825,25 +8648,22 @@ pub const FuncGen = struct { |
| 8825 | 8648 | } |
| 8826 | 8649 | |
| 8827 | 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 | 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 | 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 | 8659 | var arena_allocator = std.heap.ArenaAllocator.init(self.gpa); |
| 8836 | 8660 | defer arena_allocator.deinit(); |
| 8837 | 8661 | const arena = arena_allocator.allocator(); |
| 8838 | 8662 | |
| 8839 | const mod = self.dg.module; | |
| 8840 | const fqn = try mod.declPtr(enum_decl).getFullyQualifiedName(mod); | |
| 8841 | defer self.gpa.free(fqn); | |
| 8842 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{s}", .{fqn}); | |
| 8663 | const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); | |
| 8664 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{}", .{fqn.fmt(&mod.intern_pool)}); | |
| 8843 | 8665 | |
| 8844 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | |
| 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)}; | |
| 8666 | const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())}; | |
| 8847 | 8667 | |
| 8848 | 8668 | const llvm_ret_ty = try self.dg.lowerType(Type.bool); |
| 8849 | 8669 | const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False); |
| ... | ... | @@ -8866,21 +8686,17 @@ pub const FuncGen = struct { |
| 8866 | 8686 | self.builder.positionBuilderAtEnd(entry_block); |
| 8867 | 8687 | self.builder.clearCurrentDebugLocation(); |
| 8868 | 8688 | |
| 8869 | const fields = enum_ty.enumFields(); | |
| 8870 | 8689 | const named_block = self.context.appendBasicBlock(fn_val, "Named"); |
| 8871 | 8690 | const unnamed_block = self.context.appendBasicBlock(fn_val, "Unnamed"); |
| 8872 | 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 | 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 | 8697 | break :int try self.dg.lowerValue(.{ |
| 8882 | 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 | 8702 | switch_instr.addCase(this_tag_int_value, named_block); |
| ... | ... | @@ -8896,7 +8712,7 @@ pub const FuncGen = struct { |
| 8896 | 8712 | fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8897 | 8713 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8898 | 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 | 8717 | const llvm_fn = try self.getEnumTagNameFunction(enum_ty); |
| 8902 | 8718 | const params = [_]*llvm.Value{operand}; |
| ... | ... | @@ -8904,31 +8720,27 @@ pub const FuncGen = struct { |
| 8904 | 8720 | } |
| 8905 | 8721 | |
| 8906 | 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 | 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 | 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 | 8731 | var arena_allocator = std.heap.ArenaAllocator.init(self.gpa); |
| 8915 | 8732 | defer arena_allocator.deinit(); |
| 8916 | 8733 | const arena = arena_allocator.allocator(); |
| 8917 | 8734 | |
| 8918 | const mod = self.dg.module; | |
| 8919 | const fqn = try mod.declPtr(enum_decl).getFullyQualifiedName(mod); | |
| 8920 | defer self.gpa.free(fqn); | |
| 8921 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); | |
| 8735 | const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); | |
| 8736 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)}); | |
| 8922 | 8737 | |
| 8923 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | |
| 8738 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 8924 | 8739 | const llvm_ret_ty = try self.dg.lowerType(slice_ty); |
| 8925 | 8740 | const usize_llvm_ty = try self.dg.lowerType(Type.usize); |
| 8926 | const target = self.dg.module.getTarget(); | |
| 8927 | const slice_alignment = slice_ty.abiAlignment(target); | |
| 8741 | const slice_alignment = slice_ty.abiAlignment(mod); | |
| 8928 | 8742 | |
| 8929 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | |
| 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)}; | |
| 8743 | const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())}; | |
| 8932 | 8744 | |
| 8933 | 8745 | const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False); |
| 8934 | 8746 | const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); |
| ... | ... | @@ -8950,16 +8762,17 @@ pub const FuncGen = struct { |
| 8950 | 8762 | self.builder.positionBuilderAtEnd(entry_block); |
| 8951 | 8763 | self.builder.clearCurrentDebugLocation(); |
| 8952 | 8764 | |
| 8953 | const fields = enum_ty.enumFields(); | |
| 8954 | 8765 | const bad_value_block = self.context.appendBasicBlock(fn_val, "BadValue"); |
| 8955 | 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 | 8769 | const array_ptr_indices = [_]*llvm.Value{ |
| 8959 | 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 | 8776 | const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False); |
| 8964 | 8777 | const str_init_llvm_ty = str_init.typeOf(); |
| 8965 | 8778 | const str_global = self.dg.object.llvm_module.addGlobal(str_init_llvm_ty, ""); |
| ... | ... | @@ -8982,16 +8795,10 @@ pub const FuncGen = struct { |
| 8982 | 8795 | slice_global.setAlignment(slice_alignment); |
| 8983 | 8796 | |
| 8984 | 8797 | const return_block = self.context.appendBasicBlock(fn_val, "Name"); |
| 8985 | const this_tag_int_value = int: { | |
| 8986 | var tag_val_payload: Value.Payload.U32 = .{ | |
| 8987 | .base = .{ .tag = .enum_field_index }, | |
| 8988 | .data = @intCast(u32, field_index), | |
| 8989 | }; | |
| 8990 | break :int try self.dg.lowerValue(.{ | |
| 8991 | .ty = enum_ty, | |
| 8992 | .val = Value.initPayload(&tag_val_payload.base), | |
| 8993 | }); | |
| 8994 | }; | |
| 8798 | const this_tag_int_value = try self.dg.lowerValue(.{ | |
| 8799 | .ty = enum_ty, | |
| 8800 | .val = try mod.enumValueFieldIndex(enum_ty, field_index), | |
| 8801 | }); | |
| 8995 | 8802 | switch_instr.addCase(this_tag_int_value, return_block); |
| 8996 | 8803 | |
| 8997 | 8804 | self.builder.positionBuilderAtEnd(return_block); |
| ... | ... | @@ -9027,7 +8834,7 @@ pub const FuncGen = struct { |
| 9027 | 8834 | fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 9028 | 8835 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 9029 | 8836 | const operand = try self.resolveInst(un_op); |
| 9030 | const slice_ty = self.air.typeOfIndex(inst); | |
| 8837 | const slice_ty = self.typeOfIndex(inst); | |
| 9031 | 8838 | const slice_llvm_ty = try self.dg.lowerType(slice_ty); |
| 9032 | 8839 | |
| 9033 | 8840 | const error_name_table_ptr = try self.getErrorNameTable(); |
| ... | ... | @@ -9039,10 +8846,11 @@ pub const FuncGen = struct { |
| 9039 | 8846 | } |
| 9040 | 8847 | |
| 9041 | 8848 | fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8849 | const mod = self.dg.module; | |
| 9042 | 8850 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 9043 | 8851 | const scalar = try self.resolveInst(ty_op.operand); |
| 9044 | const vector_ty = self.air.typeOfIndex(inst); | |
| 9045 | const len = vector_ty.vectorLen(); | |
| 8852 | const vector_ty = self.typeOfIndex(inst); | |
| 8853 | const len = vector_ty.vectorLen(mod); | |
| 9046 | 8854 | return self.builder.buildVectorSplat(len, scalar, ""); |
| 9047 | 8855 | } |
| 9048 | 8856 | |
| ... | ... | @@ -9057,13 +8865,14 @@ pub const FuncGen = struct { |
| 9057 | 8865 | } |
| 9058 | 8866 | |
| 9059 | 8867 | fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8868 | const mod = self.dg.module; | |
| 9060 | 8869 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 9061 | 8870 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 9062 | 8871 | const a = try self.resolveInst(extra.a); |
| 9063 | 8872 | const b = try self.resolveInst(extra.b); |
| 9064 | const mask = self.air.values[extra.mask]; | |
| 8873 | const mask = extra.mask.toValue(); | |
| 9065 | 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 | 8877 | // LLVM uses integers larger than the length of the first array to |
| 9069 | 8878 | // index into the second array. This was deemed unnecessarily fragile |
| ... | ... | @@ -9076,12 +8885,11 @@ pub const FuncGen = struct { |
| 9076 | 8885 | const llvm_i32 = self.context.intType(32); |
| 9077 | 8886 | |
| 9078 | 8887 | for (values, 0..) |*val, i| { |
| 9079 | var buf: Value.ElemValueBuffer = undefined; | |
| 9080 | const elem = mask.elemValueBuffer(self.dg.module, i, &buf); | |
| 9081 | if (elem.isUndef()) { | |
| 8888 | const elem = try mask.elemValue(mod, i); | |
| 8889 | if (elem.isUndef(mod)) { | |
| 9082 | 8890 | val.* = llvm_i32.getUndef(); |
| 9083 | 8891 | } else { |
| 9084 | const int = elem.toSignedInt(self.dg.module.getTarget()); | |
| 8892 | const int = elem.toSignedInt(mod); | |
| 9085 | 8893 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); |
| 9086 | 8894 | val.* = llvm_i32.constInt(unsigned, .False); |
| 9087 | 8895 | } |
| ... | ... | @@ -9157,32 +8965,33 @@ pub const FuncGen = struct { |
| 9157 | 8965 | |
| 9158 | 8966 | fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 9159 | 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 | 8971 | const reduce = self.air.instructions.items(.data)[inst].reduce; |
| 9163 | 8972 | const operand = try self.resolveInst(reduce.operand); |
| 9164 | const operand_ty = self.air.typeOf(reduce.operand); | |
| 9165 | const scalar_ty = self.air.typeOfIndex(inst); | |
| 8973 | const operand_ty = self.typeOf(reduce.operand); | |
| 8974 | const scalar_ty = self.typeOfIndex(inst); | |
| 9166 | 8975 | |
| 9167 | 8976 | switch (reduce.operation) { |
| 9168 | 8977 | .And => return self.builder.buildAndReduce(operand), |
| 9169 | 8978 | .Or => return self.builder.buildOrReduce(operand), |
| 9170 | 8979 | .Xor => return self.builder.buildXorReduce(operand), |
| 9171 | .Min => switch (scalar_ty.zigTypeTag()) { | |
| 9172 | .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt()), | |
| 8980 | .Min => switch (scalar_ty.zigTypeTag(mod)) { | |
| 8981 | .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt(mod)), | |
| 9173 | 8982 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9174 | 8983 | return self.builder.buildFPMinReduce(operand); |
| 9175 | 8984 | }, |
| 9176 | 8985 | else => unreachable, |
| 9177 | 8986 | }, |
| 9178 | .Max => switch (scalar_ty.zigTypeTag()) { | |
| 9179 | .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt()), | |
| 8987 | .Max => switch (scalar_ty.zigTypeTag(mod)) { | |
| 8988 | .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt(mod)), | |
| 9180 | 8989 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9181 | 8990 | return self.builder.buildFPMaxReduce(operand); |
| 9182 | 8991 | }, |
| 9183 | 8992 | else => unreachable, |
| 9184 | 8993 | }, |
| 9185 | .Add => switch (scalar_ty.zigTypeTag()) { | |
| 8994 | .Add => switch (scalar_ty.zigTypeTag(mod)) { | |
| 9186 | 8995 | .Int => return self.builder.buildAddReduce(operand), |
| 9187 | 8996 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9188 | 8997 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| ... | ... | @@ -9191,7 +9000,7 @@ pub const FuncGen = struct { |
| 9191 | 9000 | }, |
| 9192 | 9001 | else => unreachable, |
| 9193 | 9002 | }, |
| 9194 | .Mul => switch (scalar_ty.zigTypeTag()) { | |
| 9003 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { | |
| 9195 | 9004 | .Int => return self.builder.buildMulReduce(operand), |
| 9196 | 9005 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9197 | 9006 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| ... | ... | @@ -9221,35 +9030,32 @@ pub const FuncGen = struct { |
| 9221 | 9030 | }) catch unreachable, |
| 9222 | 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 | 9034 | const param_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 9235 | 9035 | const param_types = [2]*llvm.Type{ param_llvm_ty, param_llvm_ty }; |
| 9236 | 9036 | const libc_fn = self.getLibcFunction(fn_name, &param_types, param_llvm_ty); |
| 9237 | 9037 | const init_value = try self.dg.lowerValue(.{ |
| 9238 | 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 | 9050 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 9051 | const mod = self.dg.module; | |
| 9245 | 9052 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 9246 | const result_ty = self.air.typeOfIndex(inst); | |
| 9247 | const len = @intCast(usize, result_ty.arrayLen()); | |
| 9053 | const result_ty = self.typeOfIndex(inst); | |
| 9054 | const len = @intCast(usize, result_ty.arrayLen(mod)); | |
| 9248 | 9055 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 9249 | 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 | 9059 | .Vector => { |
| 9254 | 9060 | const llvm_u32 = self.context.intType(32); |
| 9255 | 9061 | |
| ... | ... | @@ -9262,10 +9068,10 @@ pub const FuncGen = struct { |
| 9262 | 9068 | return vector; |
| 9263 | 9069 | }, |
| 9264 | 9070 | .Struct => { |
| 9265 | if (result_ty.containerLayout() == .Packed) { | |
| 9266 | const struct_obj = result_ty.castTag(.@"struct").?.data; | |
| 9071 | if (result_ty.containerLayout(mod) == .Packed) { | |
| 9072 | const struct_obj = mod.typeToStruct(result_ty).?; | |
| 9267 | 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 | 9075 | const int_llvm_ty = self.context.intType(@intCast(c_uint, big_bits)); |
| 9270 | 9076 | const fields = struct_obj.fields.values(); |
| 9271 | 9077 | comptime assert(Type.packed_struct_layout_version == 2); |
| ... | ... | @@ -9273,12 +9079,12 @@ pub const FuncGen = struct { |
| 9273 | 9079 | var running_bits: u16 = 0; |
| 9274 | 9080 | for (elements, 0..) |elem, i| { |
| 9275 | 9081 | const field = fields[i]; |
| 9276 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 9082 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 9277 | 9083 | |
| 9278 | 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 | 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 | 9088 | self.builder.buildPtrToInt(non_int_val, small_int_ty, "") |
| 9283 | 9089 | else |
| 9284 | 9090 | self.builder.buildBitCast(non_int_val, small_int_ty, ""); |
| ... | ... | @@ -9294,30 +9100,28 @@ pub const FuncGen = struct { |
| 9294 | 9100 | return running_int; |
| 9295 | 9101 | } |
| 9296 | 9102 | |
| 9297 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | |
| 9298 | ||
| 9299 | if (isByRef(result_ty)) { | |
| 9103 | if (isByRef(result_ty, mod)) { | |
| 9300 | 9104 | const llvm_u32 = self.context.intType(32); |
| 9301 | 9105 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| 9302 | 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 | 9109 | var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined }; |
| 9306 | 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 | 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 | 9115 | indices[1] = llvm_u32.constInt(llvm_i, .False); |
| 9312 | 9116 | const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, ""); |
| 9313 | var field_ptr_payload: Type.Payload.Pointer = .{ | |
| 9314 | .data = .{ | |
| 9315 | .pointee_type = self.air.typeOf(elem), | |
| 9316 | .@"align" = result_ty.structFieldAlign(i, target), | |
| 9317 | .@"addrspace" = .generic, | |
| 9117 | const field_ptr_ty = try mod.ptrType(.{ | |
| 9118 | .child = self.typeOf(elem).toIntern(), | |
| 9119 | .flags = .{ | |
| 9120 | .alignment = InternPool.Alignment.fromNonzeroByteUnits( | |
| 9121 | result_ty.structFieldAlign(i, mod), | |
| 9122 | ), | |
| 9318 | 9123 | }, |
| 9319 | }; | |
| 9320 | const field_ptr_ty = Type.initPayload(&field_ptr_payload.base); | |
| 9124 | }); | |
| 9321 | 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 | 9129 | } else { |
| 9326 | 9130 | var result = llvm_result_ty.getUndef(); |
| 9327 | 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 | 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 | 9136 | result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, ""); |
| 9333 | 9137 | } |
| 9334 | 9138 | return result; |
| 9335 | 9139 | } |
| 9336 | 9140 | }, |
| 9337 | 9141 | .Array => { |
| 9338 | assert(isByRef(result_ty)); | |
| 9142 | assert(isByRef(result_ty, mod)); | |
| 9339 | 9143 | |
| 9340 | 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(); | |
| 9344 | var elem_ptr_payload: Type.Payload.Pointer = .{ | |
| 9345 | .data = .{ | |
| 9346 | .pointee_type = array_info.elem_type, | |
| 9347 | .@"addrspace" = .generic, | |
| 9348 | }, | |
| 9349 | }; | |
| 9350 | const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base); | |
| 9147 | const array_info = result_ty.arrayInfo(mod); | |
| 9148 | const elem_ptr_ty = try mod.ptrType(.{ | |
| 9149 | .child = array_info.elem_type.toIntern(), | |
| 9150 | }); | |
| 9351 | 9151 | |
| 9352 | 9152 | for (elements, 0..) |elem, i| { |
| 9353 | 9153 | const indices: [2]*llvm.Value = .{ |
| ... | ... | @@ -9379,22 +9179,22 @@ pub const FuncGen = struct { |
| 9379 | 9179 | } |
| 9380 | 9180 | |
| 9381 | 9181 | fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 9182 | const mod = self.dg.module; | |
| 9382 | 9183 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 9383 | 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 | 9186 | const union_llvm_ty = try self.dg.lowerType(union_ty); |
| 9386 | const target = self.dg.module.getTarget(); | |
| 9387 | const layout = union_ty.unionGetLayout(target); | |
| 9388 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | |
| 9187 | const layout = union_ty.unionGetLayout(mod); | |
| 9188 | const union_obj = mod.typeToUnion(union_ty).?; | |
| 9389 | 9189 | |
| 9390 | 9190 | if (union_obj.layout == .Packed) { |
| 9391 | const big_bits = union_ty.bitSize(target); | |
| 9191 | const big_bits = union_ty.bitSize(mod); | |
| 9392 | 9192 | const int_llvm_ty = self.context.intType(@intCast(c_uint, big_bits)); |
| 9393 | 9193 | const field = union_obj.fields.values()[extra.field_index]; |
| 9394 | 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 | 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 | 9198 | self.builder.buildPtrToInt(non_int_val, small_int_ty, "") |
| 9399 | 9199 | else |
| 9400 | 9200 | self.builder.buildBitCast(non_int_val, small_int_ty, ""); |
| ... | ... | @@ -9402,26 +9202,21 @@ pub const FuncGen = struct { |
| 9402 | 9202 | } |
| 9403 | 9203 | |
| 9404 | 9204 | const tag_int = blk: { |
| 9405 | const tag_ty = union_ty.unionTagTypeHypothetical(); | |
| 9205 | const tag_ty = union_ty.unionTagTypeHypothetical(mod); | |
| 9406 | 9206 | const union_field_name = union_obj.fields.keys()[extra.field_index]; |
| 9407 | const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?; | |
| 9408 | var tag_val_payload: Value.Payload.U32 = .{ | |
| 9409 | .base = .{ .tag = .enum_field_index }, | |
| 9410 | .data = @intCast(u32, enum_field_index), | |
| 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); | |
| 9207 | const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?; | |
| 9208 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); | |
| 9209 | const tag_int_val = try tag_val.enumToInt(tag_ty, mod); | |
| 9210 | break :blk tag_int_val.toUnsignedInt(mod); | |
| 9416 | 9211 | }; |
| 9417 | 9212 | if (layout.payload_size == 0) { |
| 9418 | 9213 | if (layout.tag_size == 0) { |
| 9419 | 9214 | return null; |
| 9420 | 9215 | } |
| 9421 | assert(!isByRef(union_ty)); | |
| 9216 | assert(!isByRef(union_ty, mod)); | |
| 9422 | 9217 | return union_llvm_ty.constInt(tag_int, .False); |
| 9423 | 9218 | } |
| 9424 | assert(isByRef(union_ty)); | |
| 9219 | assert(isByRef(union_ty, mod)); | |
| 9425 | 9220 | // The llvm type of the alloca will be the named LLVM union type, and will not |
| 9426 | 9221 | // necessarily match the format that we need, depending on which tag is active. |
| 9427 | 9222 | // We must construct the correct unnamed struct type here, in order to then set |
| ... | ... | @@ -9431,12 +9226,12 @@ pub const FuncGen = struct { |
| 9431 | 9226 | assert(union_obj.haveFieldTypes()); |
| 9432 | 9227 | const field = union_obj.fields.values()[extra.field_index]; |
| 9433 | 9228 | const field_llvm_ty = try self.dg.lowerType(field.ty); |
| 9434 | const field_size = field.ty.abiSize(target); | |
| 9435 | const field_align = field.normalAlignment(target); | |
| 9229 | const field_size = field.ty.abiSize(mod); | |
| 9230 | const field_align = field.normalAlignment(mod); | |
| 9436 | 9231 | |
| 9437 | 9232 | const llvm_union_ty = t: { |
| 9438 | 9233 | const payload = p: { |
| 9439 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) { | |
| 9234 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 9440 | 9235 | const padding_len = @intCast(c_uint, layout.payload_size); |
| 9441 | 9236 | break :p self.context.intType(8).arrayType(padding_len); |
| 9442 | 9237 | } |
| ... | ... | @@ -9472,14 +9267,12 @@ pub const FuncGen = struct { |
| 9472 | 9267 | // tag and the payload. |
| 9473 | 9268 | const index_type = self.context.intType(32); |
| 9474 | 9269 | |
| 9475 | var field_ptr_payload: Type.Payload.Pointer = .{ | |
| 9476 | .data = .{ | |
| 9477 | .pointee_type = field.ty, | |
| 9478 | .@"align" = field_align, | |
| 9479 | .@"addrspace" = .generic, | |
| 9270 | const field_ptr_ty = try mod.ptrType(.{ | |
| 9271 | .child = field.ty.toIntern(), | |
| 9272 | .flags = .{ | |
| 9273 | .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align), | |
| 9480 | 9274 | }, |
| 9481 | }; | |
| 9482 | const field_ptr_ty = Type.initPayload(&field_ptr_payload.base); | |
| 9275 | }); | |
| 9483 | 9276 | if (layout.tag_size == 0) { |
| 9484 | 9277 | const indices: [3]*llvm.Value = .{ |
| 9485 | 9278 | index_type.constNull(), |
| ... | ... | @@ -9511,7 +9304,7 @@ pub const FuncGen = struct { |
| 9511 | 9304 | const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty); |
| 9512 | 9305 | const llvm_tag = tag_llvm_ty.constInt(tag_int, .False); |
| 9513 | 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 | 9310 | return result_ptr; |
| ... | ... | @@ -9535,7 +9328,8 @@ pub const FuncGen = struct { |
| 9535 | 9328 | // by the target. |
| 9536 | 9329 | // To work around this, don't emit llvm.prefetch in this case. |
| 9537 | 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 | 9333 | switch (prefetch.cache) { |
| 9540 | 9334 | .instruction => switch (target.cpu.arch) { |
| 9541 | 9335 | .x86_64, |
| ... | ... | @@ -9584,7 +9378,7 @@ pub const FuncGen = struct { |
| 9584 | 9378 | |
| 9585 | 9379 | fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 9586 | 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 | 9382 | const operand = try self.resolveInst(ty_op.operand); |
| 9589 | 9383 | |
| 9590 | 9384 | const llvm_dest_ty = try self.dg.lowerType(inst_ty); |
| ... | ... | @@ -9658,8 +9452,9 @@ pub const FuncGen = struct { |
| 9658 | 9452 | return table; |
| 9659 | 9453 | } |
| 9660 | 9454 | |
| 9661 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | |
| 9662 | const slice_alignment = slice_ty.abiAlignment(self.dg.module.getTarget()); | |
| 9455 | const mod = self.dg.module; | |
| 9456 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 9457 | const slice_alignment = slice_ty.abiAlignment(mod); | |
| 9663 | 9458 | const llvm_slice_ptr_ty = self.context.pointerType(0); // TODO: Address space |
| 9664 | 9459 | |
| 9665 | 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 | 9496 | opt_ty: Type, |
| 9702 | 9497 | can_elide_load: bool, |
| 9703 | 9498 | ) !*llvm.Value { |
| 9704 | var buf: Type.Payload.ElemType = undefined; | |
| 9705 | const payload_ty = opt_ty.optionalChild(&buf); | |
| 9499 | const mod = fg.dg.module; | |
| 9500 | const payload_ty = opt_ty.optionalChild(mod); | |
| 9706 | 9501 | |
| 9707 | if (isByRef(opt_ty)) { | |
| 9502 | if (isByRef(opt_ty, mod)) { | |
| 9708 | 9503 | // We have a pointer and we need to return a pointer to the first field. |
| 9709 | 9504 | const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, ""); |
| 9710 | 9505 | |
| 9711 | const target = fg.dg.module.getTarget(); | |
| 9712 | const payload_alignment = payload_ty.abiAlignment(target); | |
| 9713 | if (isByRef(payload_ty)) { | |
| 9506 | const payload_alignment = payload_ty.abiAlignment(mod); | |
| 9507 | if (isByRef(payload_ty, mod)) { | |
| 9714 | 9508 | if (can_elide_load) |
| 9715 | 9509 | return payload_ptr; |
| 9716 | 9510 | |
| ... | ... | @@ -9722,7 +9516,7 @@ pub const FuncGen = struct { |
| 9722 | 9516 | return load_inst; |
| 9723 | 9517 | } |
| 9724 | 9518 | |
| 9725 | assert(!isByRef(payload_ty)); | |
| 9519 | assert(!isByRef(payload_ty, mod)); | |
| 9726 | 9520 | return fg.builder.buildExtractValue(opt_handle, 0, ""); |
| 9727 | 9521 | } |
| 9728 | 9522 | |
| ... | ... | @@ -9734,10 +9528,10 @@ pub const FuncGen = struct { |
| 9734 | 9528 | ) !?*llvm.Value { |
| 9735 | 9529 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); |
| 9736 | 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)) { | |
| 9739 | const target = self.dg.module.getTarget(); | |
| 9740 | const payload_alignment = optional_ty.abiAlignment(target); | |
| 9533 | if (isByRef(optional_ty, mod)) { | |
| 9534 | const payload_alignment = optional_ty.abiAlignment(mod); | |
| 9741 | 9535 | const alloca_inst = self.buildAlloca(optional_llvm_ty, payload_alignment); |
| 9742 | 9536 | |
| 9743 | 9537 | { |
| ... | ... | @@ -9765,13 +9559,13 @@ pub const FuncGen = struct { |
| 9765 | 9559 | struct_ptr_ty: Type, |
| 9766 | 9560 | field_index: u32, |
| 9767 | 9561 | ) !?*llvm.Value { |
| 9768 | const target = self.dg.object.target; | |
| 9769 | const struct_ty = struct_ptr_ty.childType(); | |
| 9770 | switch (struct_ty.zigTypeTag()) { | |
| 9771 | .Struct => switch (struct_ty.containerLayout()) { | |
| 9562 | const mod = self.dg.module; | |
| 9563 | const struct_ty = struct_ptr_ty.childType(mod); | |
| 9564 | switch (struct_ty.zigTypeTag(mod)) { | |
| 9565 | .Struct => switch (struct_ty.containerLayout(mod)) { | |
| 9772 | 9566 | .Packed => { |
| 9773 | const result_ty = self.air.typeOfIndex(inst); | |
| 9774 | const result_ty_info = result_ty.ptrInfo().data; | |
| 9567 | const result_ty = self.typeOfIndex(inst); | |
| 9568 | const result_ty_info = result_ty.ptrInfo(mod); | |
| 9775 | 9569 | |
| 9776 | 9570 | if (result_ty_info.host_size != 0) { |
| 9777 | 9571 | // From LLVM's perspective, a pointer to a packed struct and a pointer |
| ... | ... | @@ -9783,7 +9577,7 @@ pub const FuncGen = struct { |
| 9783 | 9577 | |
| 9784 | 9578 | // We have a pointer to a packed struct field that happens to be byte-aligned. |
| 9785 | 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 | 9581 | if (byte_offset == 0) return struct_ptr; |
| 9788 | 9582 | const byte_llvm_ty = self.context.intType(8); |
| 9789 | 9583 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| ... | ... | @@ -9794,24 +9588,23 @@ pub const FuncGen = struct { |
| 9794 | 9588 | else => { |
| 9795 | 9589 | const struct_llvm_ty = try self.dg.lowerPtrElemTy(struct_ty); |
| 9796 | 9590 | |
| 9797 | var ty_buf: Type.Payload.Pointer = undefined; | |
| 9798 | if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| { | |
| 9799 | return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field_index, ""); | |
| 9591 | if (llvmField(struct_ty, field_index, mod)) |llvm_field| { | |
| 9592 | return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field.index, ""); | |
| 9800 | 9593 | } else { |
| 9801 | 9594 | // If we found no index then this means this is a zero sized field at the |
| 9802 | 9595 | // end of the struct. Treat our struct pointer as an array of two and get |
| 9803 | 9596 | // the index to the element at index `1` to get a pointer to the end of |
| 9804 | 9597 | // the struct. |
| 9805 | 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 | 9600 | const indices: [1]*llvm.Value = .{llvm_index}; |
| 9808 | 9601 | return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, ""); |
| 9809 | 9602 | } |
| 9810 | 9603 | }, |
| 9811 | 9604 | }, |
| 9812 | 9605 | .Union => { |
| 9813 | const layout = struct_ty.unionGetLayout(target); | |
| 9814 | if (layout.payload_size == 0 or struct_ty.containerLayout() == .Packed) return struct_ptr; | |
| 9606 | const layout = struct_ty.unionGetLayout(mod); | |
| 9607 | if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr; | |
| 9815 | 9608 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); |
| 9816 | 9609 | const union_llvm_ty = try self.dg.lowerType(struct_ty); |
| 9817 | 9610 | const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_ptr, payload_index, ""); |
| ... | ... | @@ -9835,12 +9628,12 @@ pub const FuncGen = struct { |
| 9835 | 9628 | ptr_alignment: u32, |
| 9836 | 9629 | is_volatile: bool, |
| 9837 | 9630 | ) !*llvm.Value { |
| 9631 | const mod = fg.dg.module; | |
| 9838 | 9632 | const pointee_llvm_ty = try fg.dg.lowerType(pointee_type); |
| 9839 | const target = fg.dg.module.getTarget(); | |
| 9840 | const result_align = @max(ptr_alignment, pointee_type.abiAlignment(target)); | |
| 9633 | const result_align = @max(ptr_alignment, pointee_type.abiAlignment(mod)); | |
| 9841 | 9634 | const result_ptr = fg.buildAlloca(pointee_llvm_ty, result_align); |
| 9842 | const llvm_usize = fg.context.intType(Type.usize.intInfo(target).bits); | |
| 9843 | const size_bytes = pointee_type.abiSize(target); | |
| 9635 | const llvm_usize = fg.context.intType(Type.usize.intInfo(mod).bits); | |
| 9636 | const size_bytes = pointee_type.abiSize(mod); | |
| 9844 | 9637 | _ = fg.builder.buildMemCpy( |
| 9845 | 9638 | result_ptr, |
| 9846 | 9639 | result_align, |
| ... | ... | @@ -9856,12 +9649,12 @@ pub const FuncGen = struct { |
| 9856 | 9649 | /// alloca and copies the value into it, then returns the alloca instruction. |
| 9857 | 9650 | /// For isByRef=false types, it creates a load instruction and returns it. |
| 9858 | 9651 | fn load(self: *FuncGen, ptr: *llvm.Value, ptr_ty: Type) !?*llvm.Value { |
| 9859 | const info = ptr_ty.ptrInfo().data; | |
| 9860 | if (!info.pointee_type.hasRuntimeBitsIgnoreComptime()) return null; | |
| 9652 | const mod = self.dg.module; | |
| 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(); | |
| 9863 | const ptr_alignment = info.alignment(target); | |
| 9864 | const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr()); | |
| 9656 | const ptr_alignment = info.alignment(mod); | |
| 9657 | const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr(mod)); | |
| 9865 | 9658 | |
| 9866 | 9659 | assert(info.vector_index != .runtime); |
| 9867 | 9660 | if (info.vector_index != .none) { |
| ... | ... | @@ -9877,7 +9670,7 @@ pub const FuncGen = struct { |
| 9877 | 9670 | } |
| 9878 | 9671 | |
| 9879 | 9672 | if (info.host_size == 0) { |
| 9880 | if (isByRef(info.pointee_type)) { | |
| 9673 | if (isByRef(info.pointee_type, mod)) { | |
| 9881 | 9674 | return self.loadByRef(ptr, info.pointee_type, ptr_alignment, info.@"volatile"); |
| 9882 | 9675 | } |
| 9883 | 9676 | const elem_llvm_ty = try self.dg.lowerType(info.pointee_type); |
| ... | ... | @@ -9892,13 +9685,13 @@ pub const FuncGen = struct { |
| 9892 | 9685 | containing_int.setAlignment(ptr_alignment); |
| 9893 | 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 | 9689 | const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False); |
| 9897 | 9690 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); |
| 9898 | 9691 | const elem_llvm_ty = try self.dg.lowerType(info.pointee_type); |
| 9899 | 9692 | |
| 9900 | if (isByRef(info.pointee_type)) { | |
| 9901 | const result_align = info.pointee_type.abiAlignment(target); | |
| 9693 | if (isByRef(info.pointee_type, mod)) { | |
| 9694 | const result_align = info.pointee_type.abiAlignment(mod); | |
| 9902 | 9695 | const result_ptr = self.buildAlloca(elem_llvm_ty, result_align); |
| 9903 | 9696 | |
| 9904 | 9697 | const same_size_int = self.context.intType(elem_bits); |
| ... | ... | @@ -9908,13 +9701,13 @@ pub const FuncGen = struct { |
| 9908 | 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 | 9705 | const same_size_int = self.context.intType(elem_bits); |
| 9913 | 9706 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| 9914 | 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 | 9711 | const same_size_int = self.context.intType(elem_bits); |
| 9919 | 9712 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| 9920 | 9713 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); |
| ... | ... | @@ -9930,13 +9723,13 @@ pub const FuncGen = struct { |
| 9930 | 9723 | elem: *llvm.Value, |
| 9931 | 9724 | ordering: llvm.AtomicOrdering, |
| 9932 | 9725 | ) !void { |
| 9933 | const info = ptr_ty.ptrInfo().data; | |
| 9726 | const mod = self.dg.module; | |
| 9727 | const info = ptr_ty.ptrInfo(mod); | |
| 9934 | 9728 | const elem_ty = info.pointee_type; |
| 9935 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { | |
| 9729 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { | |
| 9936 | 9730 | return; |
| 9937 | 9731 | } |
| 9938 | const target = self.dg.module.getTarget(); | |
| 9939 | const ptr_alignment = ptr_ty.ptrAlignment(target); | |
| 9732 | const ptr_alignment = ptr_ty.ptrAlignment(mod); | |
| 9940 | 9733 | const ptr_volatile = llvm.Bool.fromBool(info.@"volatile"); |
| 9941 | 9734 | |
| 9942 | 9735 | assert(info.vector_index != .runtime); |
| ... | ... | @@ -9964,13 +9757,13 @@ pub const FuncGen = struct { |
| 9964 | 9757 | assert(ordering == .NotAtomic); |
| 9965 | 9758 | containing_int.setAlignment(ptr_alignment); |
| 9966 | 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 | 9761 | const containing_int_ty = containing_int.typeOf(); |
| 9969 | 9762 | const shift_amt = containing_int_ty.constInt(info.bit_offset, .False); |
| 9970 | 9763 | // Convert to equally-sized integer type in order to perform the bit |
| 9971 | 9764 | // operations on the value to store |
| 9972 | 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 | 9767 | self.builder.buildPtrToInt(elem, value_bits_type, "") |
| 9975 | 9768 | else |
| 9976 | 9769 | self.builder.buildBitCast(elem, value_bits_type, ""); |
| ... | ... | @@ -9991,7 +9784,7 @@ pub const FuncGen = struct { |
| 9991 | 9784 | store_inst.setVolatile(ptr_volatile); |
| 9992 | 9785 | return; |
| 9993 | 9786 | } |
| 9994 | if (!isByRef(elem_ty)) { | |
| 9787 | if (!isByRef(elem_ty, mod)) { | |
| 9995 | 9788 | const store_inst = self.builder.buildStore(elem, ptr); |
| 9996 | 9789 | store_inst.setOrdering(ordering); |
| 9997 | 9790 | store_inst.setAlignment(ptr_alignment); |
| ... | ... | @@ -9999,13 +9792,13 @@ pub const FuncGen = struct { |
| 9999 | 9792 | return; |
| 10000 | 9793 | } |
| 10001 | 9794 | assert(ordering == .NotAtomic); |
| 10002 | const size_bytes = elem_ty.abiSize(target); | |
| 9795 | const size_bytes = elem_ty.abiSize(mod); | |
| 10003 | 9796 | _ = self.builder.buildMemCpy( |
| 10004 | 9797 | ptr, |
| 10005 | 9798 | ptr_alignment, |
| 10006 | 9799 | elem, |
| 10007 | elem_ty.abiAlignment(target), | |
| 10008 | self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False), | |
| 9800 | elem_ty.abiAlignment(mod), | |
| 9801 | self.context.intType(Type.usize.intInfo(mod).bits).constInt(size_bytes, .False), | |
| 10009 | 9802 | info.@"volatile", |
| 10010 | 9803 | ); |
| 10011 | 9804 | } |
| ... | ... | @@ -10030,11 +9823,12 @@ pub const FuncGen = struct { |
| 10030 | 9823 | a4: *llvm.Value, |
| 10031 | 9824 | a5: *llvm.Value, |
| 10032 | 9825 | ) *llvm.Value { |
| 10033 | const target = fg.dg.module.getTarget(); | |
| 9826 | const mod = fg.dg.module; | |
| 9827 | const target = mod.getTarget(); | |
| 10034 | 9828 | if (!target_util.hasValgrindSupport(target)) return default_value; |
| 10035 | 9829 | |
| 10036 | 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 | 9833 | const array_llvm_ty = usize_llvm_ty.arrayType(6); |
| 10040 | 9834 | const array_ptr = fg.valgrind_client_request_array orelse a: { |
| ... | ... | @@ -10111,6 +9905,16 @@ pub const FuncGen = struct { |
| 10111 | 9905 | ); |
| 10112 | 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 | 9920 | fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void { |
| ... | ... | @@ -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 | 10257 | /// Take into account 0 bit fields and padding. Returns null if an llvm |
| 10448 | 10258 | /// field could not be found. |
| 10449 | 10259 | /// This only happens if you want the field index of a zero sized field at |
| 10450 | 10260 | /// the end of the struct. |
| 10451 | fn llvmFieldIndex( | |
| 10452 | ty: Type, | |
| 10453 | field_index: usize, | |
| 10454 | target: std.Target, | |
| 10455 | ptr_pl_buf: *Type.Payload.Pointer, | |
| 10456 | ) ?c_uint { | |
| 10261 | fn llvmField(ty: Type, field_index: usize, mod: *Module) ?LlvmField { | |
| 10457 | 10262 | // Detects where we inserted extra padding fields so that we can skip |
| 10458 | 10263 | // over them in this function. |
| 10459 | 10264 | comptime assert(struct_layout_version == 2); |
| 10460 | 10265 | var offset: u64 = 0; |
| 10461 | 10266 | var big_align: u32 = 0; |
| 10462 | 10267 | |
| 10463 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 10464 | const tuple = ty.tupleFields(); | |
| 10465 | var llvm_field_index: c_uint = 0; | |
| 10466 | for (tuple.types, 0..) |field_ty, i| { | |
| 10467 | if (tuple.values[i].tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; | |
| 10268 | const struct_type = switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 10269 | .anon_struct_type => |tuple| { | |
| 10270 | var llvm_field_index: c_uint = 0; | |
| 10271 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 10272 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 10468 | 10273 | |
| 10469 | const field_align = field_ty.abiAlignment(target); | |
| 10470 | big_align = @max(big_align, field_align); | |
| 10471 | const prev_offset = offset; | |
| 10472 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 10274 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 10275 | big_align = @max(big_align, field_align); | |
| 10276 | const prev_offset = offset; | |
| 10277 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 10473 | 10278 | |
| 10474 | const padding_len = offset - prev_offset; | |
| 10475 | if (padding_len > 0) { | |
| 10476 | llvm_field_index += 1; | |
| 10477 | } | |
| 10279 | const padding_len = offset - prev_offset; | |
| 10280 | if (padding_len > 0) { | |
| 10281 | llvm_field_index += 1; | |
| 10282 | } | |
| 10478 | 10283 | |
| 10479 | if (field_index <= i) { | |
| 10480 | ptr_pl_buf.* = .{ | |
| 10481 | .data = .{ | |
| 10482 | .pointee_type = field_ty, | |
| 10483 | .@"align" = field_align, | |
| 10484 | .@"addrspace" = .generic, | |
| 10485 | }, | |
| 10486 | }; | |
| 10487 | return llvm_field_index; | |
| 10488 | } | |
| 10284 | if (field_index <= i) { | |
| 10285 | return .{ | |
| 10286 | .index = llvm_field_index, | |
| 10287 | .ty = field_ty.toType(), | |
| 10288 | .alignment = field_align, | |
| 10289 | }; | |
| 10290 | } | |
| 10489 | 10291 | |
| 10490 | llvm_field_index += 1; | |
| 10491 | offset += field_ty.abiSize(target); | |
| 10492 | } | |
| 10493 | return null; | |
| 10494 | } | |
| 10495 | const layout = ty.containerLayout(); | |
| 10292 | llvm_field_index += 1; | |
| 10293 | offset += field_ty.toType().abiSize(mod); | |
| 10294 | } | |
| 10295 | return null; | |
| 10296 | }, | |
| 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 | 10302 | assert(layout != .Packed); |
| 10497 | 10303 | |
| 10498 | 10304 | var llvm_field_index: c_uint = 0; |
| 10499 | var it = ty.castTag(.@"struct").?.data.runtimeFieldIterator(); | |
| 10305 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 10500 | 10306 | while (it.next()) |field_and_index| { |
| 10501 | 10307 | const field = field_and_index.field; |
| 10502 | const field_align = field.alignment(target, layout); | |
| 10308 | const field_align = field.alignment(mod, layout); | |
| 10503 | 10309 | big_align = @max(big_align, field_align); |
| 10504 | 10310 | const prev_offset = offset; |
| 10505 | 10311 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| ... | ... | @@ -10510,54 +10316,52 @@ fn llvmFieldIndex( |
| 10510 | 10316 | } |
| 10511 | 10317 | |
| 10512 | 10318 | if (field_index == field_and_index.index) { |
| 10513 | ptr_pl_buf.* = .{ | |
| 10514 | .data = .{ | |
| 10515 | .pointee_type = field.ty, | |
| 10516 | .@"align" = field_align, | |
| 10517 | .@"addrspace" = .generic, | |
| 10518 | }, | |
| 10319 | return .{ | |
| 10320 | .index = llvm_field_index, | |
| 10321 | .ty = field.ty, | |
| 10322 | .alignment = field_align, | |
| 10519 | 10323 | }; |
| 10520 | return llvm_field_index; | |
| 10521 | 10324 | } |
| 10522 | 10325 | |
| 10523 | 10326 | llvm_field_index += 1; |
| 10524 | offset += field.ty.abiSize(target); | |
| 10327 | offset += field.ty.abiSize(mod); | |
| 10525 | 10328 | } else { |
| 10526 | 10329 | // We did not find an llvm field that corresponds to this zig field. |
| 10527 | 10330 | return null; |
| 10528 | 10331 | } |
| 10529 | 10332 | } |
| 10530 | 10333 | |
| 10531 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { | |
| 10532 | if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) return false; | |
| 10334 | fn firstParamSRet(fn_info: InternPool.Key.FuncType, mod: *Module) bool { | |
| 10335 | if (!fn_info.return_type.toType().hasRuntimeBitsIgnoreComptime(mod)) return false; | |
| 10533 | 10336 | |
| 10337 | const target = mod.getTarget(); | |
| 10534 | 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 | 10340 | .C => switch (target.cpu.arch) { |
| 10537 | 10341 | .mips, .mipsel => return false, |
| 10538 | 10342 | .x86_64 => switch (target.os.tag) { |
| 10539 | .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory, | |
| 10540 | else => return firstParamSRetSystemV(fn_info.return_type, target), | |
| 10343 | .windows => return x86_64_abi.classifyWindows(fn_info.return_type.toType(), mod) == .memory, | |
| 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, | |
| 10543 | .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory, | |
| 10544 | .arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type, target, .ret)) { | |
| 10346 | .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type.toType(), mod)[0] == .indirect, | |
| 10347 | .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type.toType(), mod) == .memory, | |
| 10348 | .arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type.toType(), mod, .ret)) { | |
| 10545 | 10349 | .memory, .i64_array => return true, |
| 10546 | 10350 | .i32_array => |size| return size != 1, |
| 10547 | 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 | 10354 | else => return false, // TODO investigate C ABI for other architectures |
| 10551 | 10355 | }, |
| 10552 | .SysV => return firstParamSRetSystemV(fn_info.return_type, target), | |
| 10553 | .Win64 => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory, | |
| 10554 | .Stdcall => return !isScalar(fn_info.return_type), | |
| 10356 | .SysV => return firstParamSRetSystemV(fn_info.return_type.toType(), mod), | |
| 10357 | .Win64 => return x86_64_abi.classifyWindows(fn_info.return_type.toType(), mod) == .memory, | |
| 10358 | .Stdcall => return !isScalar(mod, fn_info.return_type.toType()), | |
| 10555 | 10359 | else => return false, |
| 10556 | 10360 | } |
| 10557 | 10361 | } |
| 10558 | 10362 | |
| 10559 | fn firstParamSRetSystemV(ty: Type, target: std.Target) bool { | |
| 10560 | const class = x86_64_abi.classifySystemV(ty, target, .ret); | |
| 10363 | fn firstParamSRetSystemV(ty: Type, mod: *Module) bool { | |
| 10364 | const class = x86_64_abi.classifySystemV(ty, mod, .ret); | |
| 10561 | 10365 | if (class[0] == .memory) return true; |
| 10562 | 10366 | if (class[0] == .x87 and class[2] != .none) return true; |
| 10563 | 10367 | return false; |
| ... | ... | @@ -10566,75 +10370,77 @@ fn firstParamSRetSystemV(ty: Type, target: std.Target) bool { |
| 10566 | 10370 | /// In order to support the C calling convention, some return types need to be lowered |
| 10567 | 10371 | /// completely differently in the function prototype to honor the C ABI, and then |
| 10568 | 10372 | /// be effectively bitcasted to the actual return type. |
| 10569 | fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { | |
| 10570 | if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { | |
| 10373 | fn lowerFnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type { | |
| 10374 | const mod = dg.module; | |
| 10375 | const return_type = fn_info.return_type.toType(); | |
| 10376 | if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 10571 | 10377 | // If the return type is an error set or an error union, then we make this |
| 10572 | 10378 | // anyerror return type instead, so that it can be coerced into a function |
| 10573 | 10379 | // pointer type which has anyerror as the return type. |
| 10574 | if (fn_info.return_type.isError()) { | |
| 10380 | if (return_type.isError(mod)) { | |
| 10575 | 10381 | return dg.lowerType(Type.anyerror); |
| 10576 | 10382 | } else { |
| 10577 | 10383 | return dg.context.voidType(); |
| 10578 | 10384 | } |
| 10579 | 10385 | } |
| 10580 | const target = dg.module.getTarget(); | |
| 10386 | const target = mod.getTarget(); | |
| 10581 | 10387 | switch (fn_info.cc) { |
| 10582 | 10388 | .Unspecified, .Inline => { |
| 10583 | if (isByRef(fn_info.return_type)) { | |
| 10389 | if (isByRef(return_type, mod)) { | |
| 10584 | 10390 | return dg.context.voidType(); |
| 10585 | 10391 | } else { |
| 10586 | return dg.lowerType(fn_info.return_type); | |
| 10392 | return dg.lowerType(return_type); | |
| 10587 | 10393 | } |
| 10588 | 10394 | }, |
| 10589 | 10395 | .C => { |
| 10590 | 10396 | switch (target.cpu.arch) { |
| 10591 | .mips, .mipsel => return dg.lowerType(fn_info.return_type), | |
| 10397 | .mips, .mipsel => return dg.lowerType(return_type), | |
| 10592 | 10398 | .x86_64 => switch (target.os.tag) { |
| 10593 | 10399 | .windows => return lowerWin64FnRetTy(dg, fn_info), |
| 10594 | 10400 | else => return lowerSystemVFnRetTy(dg, fn_info), |
| 10595 | 10401 | }, |
| 10596 | 10402 | .wasm32 => { |
| 10597 | if (isScalar(fn_info.return_type)) { | |
| 10598 | return dg.lowerType(fn_info.return_type); | |
| 10403 | if (isScalar(mod, 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 | 10407 | if (classes[0] == .indirect or classes[0] == .none) { |
| 10602 | 10408 | return dg.context.voidType(); |
| 10603 | 10409 | } |
| 10604 | 10410 | |
| 10605 | 10411 | assert(classes[0] == .direct and classes[1] == .none); |
| 10606 | const scalar_type = wasm_c_abi.scalarType(fn_info.return_type, target); | |
| 10607 | const abi_size = scalar_type.abiSize(target); | |
| 10412 | const scalar_type = wasm_c_abi.scalarType(return_type, mod); | |
| 10413 | const abi_size = scalar_type.abiSize(mod); | |
| 10608 | 10414 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10609 | 10415 | }, |
| 10610 | 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 | 10418 | .memory => return dg.context.voidType(), |
| 10613 | .float_array => return dg.lowerType(fn_info.return_type), | |
| 10614 | .byval => return dg.lowerType(fn_info.return_type), | |
| 10419 | .float_array => return dg.lowerType(return_type), | |
| 10420 | .byval => return dg.lowerType(return_type), | |
| 10615 | 10421 | .integer => { |
| 10616 | const bit_size = fn_info.return_type.bitSize(target); | |
| 10422 | const bit_size = return_type.bitSize(mod); | |
| 10617 | 10423 | return dg.context.intType(@intCast(c_uint, bit_size)); |
| 10618 | 10424 | }, |
| 10619 | 10425 | .double_integer => return dg.context.intType(64).arrayType(2), |
| 10620 | 10426 | } |
| 10621 | 10427 | }, |
| 10622 | 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 | 10430 | .memory, .i64_array => return dg.context.voidType(), |
| 10625 | 10431 | .i32_array => |len| if (len == 1) { |
| 10626 | 10432 | return dg.context.intType(32); |
| 10627 | 10433 | } else { |
| 10628 | 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 | 10439 | .riscv32, .riscv64 => { |
| 10634 | switch (riscv_c_abi.classifyType(fn_info.return_type, target)) { | |
| 10440 | switch (riscv_c_abi.classifyType(return_type, mod)) { | |
| 10635 | 10441 | .memory => return dg.context.voidType(), |
| 10636 | 10442 | .integer => { |
| 10637 | const bit_size = fn_info.return_type.bitSize(target); | |
| 10443 | const bit_size = return_type.bitSize(mod); | |
| 10638 | 10444 | return dg.context.intType(@intCast(c_uint, bit_size)); |
| 10639 | 10445 | }, |
| 10640 | 10446 | .double_integer => { |
| ... | ... | @@ -10644,50 +10450,52 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10644 | 10450 | }; |
| 10645 | 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 | 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 | 10460 | .Win64 => return lowerWin64FnRetTy(dg, fn_info), |
| 10655 | 10461 | .SysV => return lowerSystemVFnRetTy(dg, fn_info), |
| 10656 | 10462 | .Stdcall => { |
| 10657 | if (isScalar(fn_info.return_type)) { | |
| 10658 | return dg.lowerType(fn_info.return_type); | |
| 10463 | if (isScalar(mod, return_type)) { | |
| 10464 | return dg.lowerType(return_type); | |
| 10659 | 10465 | } else { |
| 10660 | 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 { | |
| 10668 | const target = dg.module.getTarget(); | |
| 10669 | switch (x86_64_abi.classifyWindows(fn_info.return_type, target)) { | |
| 10473 | fn lowerWin64FnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type { | |
| 10474 | const mod = dg.module; | |
| 10475 | const return_type = fn_info.return_type.toType(); | |
| 10476 | switch (x86_64_abi.classifyWindows(return_type, mod)) { | |
| 10670 | 10477 | .integer => { |
| 10671 | if (isScalar(fn_info.return_type)) { | |
| 10672 | return dg.lowerType(fn_info.return_type); | |
| 10478 | if (isScalar(mod, return_type)) { | |
| 10479 | return dg.lowerType(return_type); | |
| 10673 | 10480 | } else { |
| 10674 | const abi_size = fn_info.return_type.abiSize(target); | |
| 10481 | const abi_size = return_type.abiSize(mod); | |
| 10675 | 10482 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10676 | 10483 | } |
| 10677 | 10484 | }, |
| 10678 | 10485 | .win_i128 => return dg.context.intType(64).vectorType(2), |
| 10679 | 10486 | .memory => return dg.context.voidType(), |
| 10680 | .sse => return dg.lowerType(fn_info.return_type), | |
| 10487 | .sse => return dg.lowerType(return_type), | |
| 10681 | 10488 | else => unreachable, |
| 10682 | 10489 | } |
| 10683 | 10490 | } |
| 10684 | 10491 | |
| 10685 | fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { | |
| 10686 | if (isScalar(fn_info.return_type)) { | |
| 10687 | return dg.lowerType(fn_info.return_type); | |
| 10492 | fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type { | |
| 10493 | const mod = dg.module; | |
| 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(); | |
| 10690 | const classes = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret); | |
| 10498 | const classes = x86_64_abi.classifySystemV(return_type, mod, .ret); | |
| 10691 | 10499 | if (classes[0] == .memory) { |
| 10692 | 10500 | return dg.context.voidType(); |
| 10693 | 10501 | } |
| ... | ... | @@ -10728,7 +10536,7 @@ fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm |
| 10728 | 10536 | } |
| 10729 | 10537 | } |
| 10730 | 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 | 10540 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10733 | 10541 | } |
| 10734 | 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 | 10544 | |
| 10737 | 10545 | const ParamTypeIterator = struct { |
| 10738 | 10546 | dg: *DeclGen, |
| 10739 | fn_info: Type.Payload.Function.Data, | |
| 10547 | fn_info: InternPool.Key.FuncType, | |
| 10740 | 10548 | zig_index: u32, |
| 10741 | 10549 | llvm_index: u32, |
| 10742 | target: std.Target, | |
| 10743 | 10550 | llvm_types_len: u32, |
| 10744 | 10551 | llvm_types_buffer: [8]*llvm.Type, |
| 10745 | 10552 | byval_attr: bool, |
| ... | ... | @@ -10762,7 +10569,7 @@ const ParamTypeIterator = struct { |
| 10762 | 10569 | if (it.zig_index >= it.fn_info.param_types.len) return null; |
| 10763 | 10570 | const ty = it.fn_info.param_types[it.zig_index]; |
| 10764 | 10571 | it.byval_attr = false; |
| 10765 | return nextInner(it, ty); | |
| 10572 | return nextInner(it, ty.toType()); | |
| 10766 | 10573 | } |
| 10767 | 10574 | |
| 10768 | 10575 | /// `airCall` uses this instead of `next` so that it can take into account variadic functions. |
| ... | ... | @@ -10771,15 +10578,18 @@ const ParamTypeIterator = struct { |
| 10771 | 10578 | if (it.zig_index >= args.len) { |
| 10772 | 10579 | return null; |
| 10773 | 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 | 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 | 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 | 10593 | it.zig_index += 1; |
| 10784 | 10594 | return .no_bits; |
| 10785 | 10595 | } |
| ... | ... | @@ -10787,11 +10597,10 @@ const ParamTypeIterator = struct { |
| 10787 | 10597 | .Unspecified, .Inline => { |
| 10788 | 10598 | it.zig_index += 1; |
| 10789 | 10599 | it.llvm_index += 1; |
| 10790 | var buf: Type.Payload.ElemType = undefined; | |
| 10791 | if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) { | |
| 10600 | if (ty.isSlice(mod) or (ty.zigTypeTag(mod) == .Optional and ty.optionalChild(mod).isSlice(mod))) { | |
| 10792 | 10601 | it.llvm_index += 1; |
| 10793 | 10602 | return .slice; |
| 10794 | } else if (isByRef(ty)) { | |
| 10603 | } else if (isByRef(ty, mod)) { | |
| 10795 | 10604 | return .byref; |
| 10796 | 10605 | } else { |
| 10797 | 10606 | return .byval; |
| ... | ... | @@ -10801,23 +10610,23 @@ const ParamTypeIterator = struct { |
| 10801 | 10610 | @panic("TODO implement async function lowering in the LLVM backend"); |
| 10802 | 10611 | }, |
| 10803 | 10612 | .C => { |
| 10804 | switch (it.target.cpu.arch) { | |
| 10613 | switch (target.cpu.arch) { | |
| 10805 | 10614 | .mips, .mipsel => { |
| 10806 | 10615 | it.zig_index += 1; |
| 10807 | 10616 | it.llvm_index += 1; |
| 10808 | 10617 | return .byval; |
| 10809 | 10618 | }, |
| 10810 | .x86_64 => switch (it.target.os.tag) { | |
| 10619 | .x86_64 => switch (target.os.tag) { | |
| 10811 | 10620 | .windows => return it.nextWin64(ty), |
| 10812 | 10621 | else => return it.nextSystemV(ty), |
| 10813 | 10622 | }, |
| 10814 | 10623 | .wasm32 => { |
| 10815 | 10624 | it.zig_index += 1; |
| 10816 | 10625 | it.llvm_index += 1; |
| 10817 | if (isScalar(ty)) { | |
| 10626 | if (isScalar(mod, ty)) { | |
| 10818 | 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 | 10630 | if (classes[0] == .indirect) { |
| 10822 | 10631 | return .byref; |
| 10823 | 10632 | } |
| ... | ... | @@ -10826,7 +10635,7 @@ const ParamTypeIterator = struct { |
| 10826 | 10635 | .aarch64, .aarch64_be => { |
| 10827 | 10636 | it.zig_index += 1; |
| 10828 | 10637 | it.llvm_index += 1; |
| 10829 | switch (aarch64_c_abi.classifyType(ty, it.target)) { | |
| 10638 | switch (aarch64_c_abi.classifyType(ty, mod)) { | |
| 10830 | 10639 | .memory => return .byref_mut, |
| 10831 | 10640 | .float_array => |len| return Lowering{ .float_array = len }, |
| 10832 | 10641 | .byval => return .byval, |
| ... | ... | @@ -10841,7 +10650,7 @@ const ParamTypeIterator = struct { |
| 10841 | 10650 | .arm, .armeb => { |
| 10842 | 10651 | it.zig_index += 1; |
| 10843 | 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 | 10654 | .memory => { |
| 10846 | 10655 | it.byval_attr = true; |
| 10847 | 10656 | return .byref; |
| ... | ... | @@ -10854,10 +10663,10 @@ const ParamTypeIterator = struct { |
| 10854 | 10663 | .riscv32, .riscv64 => { |
| 10855 | 10664 | it.zig_index += 1; |
| 10856 | 10665 | it.llvm_index += 1; |
| 10857 | if (ty.tag() == .f16) { | |
| 10666 | if (ty.toIntern() == .f16_type) { | |
| 10858 | 10667 | return .as_u16; |
| 10859 | 10668 | } |
| 10860 | switch (riscv_c_abi.classifyType(ty, it.target)) { | |
| 10669 | switch (riscv_c_abi.classifyType(ty, mod)) { | |
| 10861 | 10670 | .memory => return .byref_mut, |
| 10862 | 10671 | .byval => return .byval, |
| 10863 | 10672 | .integer => return .abi_sized_int, |
| ... | ... | @@ -10878,7 +10687,7 @@ const ParamTypeIterator = struct { |
| 10878 | 10687 | it.zig_index += 1; |
| 10879 | 10688 | it.llvm_index += 1; |
| 10880 | 10689 | |
| 10881 | if (isScalar(ty)) { | |
| 10690 | if (isScalar(mod, ty)) { | |
| 10882 | 10691 | return .byval; |
| 10883 | 10692 | } else { |
| 10884 | 10693 | it.byval_attr = true; |
| ... | ... | @@ -10894,9 +10703,10 @@ const ParamTypeIterator = struct { |
| 10894 | 10703 | } |
| 10895 | 10704 | |
| 10896 | 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 | 10708 | .integer => { |
| 10899 | if (isScalar(ty)) { | |
| 10709 | if (isScalar(mod, ty)) { | |
| 10900 | 10710 | it.zig_index += 1; |
| 10901 | 10711 | it.llvm_index += 1; |
| 10902 | 10712 | return .byval; |
| ... | ... | @@ -10926,14 +10736,15 @@ const ParamTypeIterator = struct { |
| 10926 | 10736 | } |
| 10927 | 10737 | |
| 10928 | 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 | 10741 | if (classes[0] == .memory) { |
| 10931 | 10742 | it.zig_index += 1; |
| 10932 | 10743 | it.llvm_index += 1; |
| 10933 | 10744 | it.byval_attr = true; |
| 10934 | 10745 | return .byref; |
| 10935 | 10746 | } |
| 10936 | if (isScalar(ty)) { | |
| 10747 | if (isScalar(mod, ty)) { | |
| 10937 | 10748 | it.zig_index += 1; |
| 10938 | 10749 | it.llvm_index += 1; |
| 10939 | 10750 | return .byval; |
| ... | ... | @@ -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 | 10801 | return .{ |
| 10991 | 10802 | .dg = dg, |
| 10992 | 10803 | .fn_info = fn_info, |
| 10993 | 10804 | .zig_index = 0, |
| 10994 | 10805 | .llvm_index = 0, |
| 10995 | .target = dg.module.getTarget(), | |
| 10996 | 10806 | .llvm_types_buffer = undefined, |
| 10997 | 10807 | .llvm_types_len = 0, |
| 10998 | 10808 | .byval_attr = false, |
| ... | ... | @@ -11001,16 +10811,17 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp |
| 11001 | 10811 | |
| 11002 | 10812 | fn ccAbiPromoteInt( |
| 11003 | 10813 | cc: std.builtin.CallingConvention, |
| 11004 | target: std.Target, | |
| 10814 | mod: *Module, | |
| 11005 | 10815 | ty: Type, |
| 11006 | 10816 | ) ?std.builtin.Signedness { |
| 10817 | const target = mod.getTarget(); | |
| 11007 | 10818 | switch (cc) { |
| 11008 | 10819 | .Unspecified, .Inline, .Async => return null, |
| 11009 | 10820 | else => {}, |
| 11010 | 10821 | } |
| 11011 | const int_info = switch (ty.zigTypeTag()) { | |
| 11012 | .Bool => Type.u1.intInfo(target), | |
| 11013 | .Int, .Enum, .ErrorSet => ty.intInfo(target), | |
| 10822 | const int_info = switch (ty.zigTypeTag(mod)) { | |
| 10823 | .Bool => Type.u1.intInfo(mod), | |
| 10824 | .Int, .Enum, .ErrorSet => ty.intInfo(mod), | |
| 11014 | 10825 | else => return null, |
| 11015 | 10826 | }; |
| 11016 | 10827 | if (int_info.bits <= 16) return int_info.signedness; |
| ... | ... | @@ -11039,12 +10850,12 @@ fn ccAbiPromoteInt( |
| 11039 | 10850 | |
| 11040 | 10851 | /// This is the one source of truth for whether a type is passed around as an LLVM pointer, |
| 11041 | 10852 | /// or as an LLVM value. |
| 11042 | fn isByRef(ty: Type) bool { | |
| 10853 | fn isByRef(ty: Type, mod: *Module) bool { | |
| 11043 | 10854 | // For tuples and structs, if there are more than this many non-void |
| 11044 | 10855 | // fields, then we make it byref, otherwise byval. |
| 11045 | 10856 | const max_fields_byval = 0; |
| 11046 | 10857 | |
| 11047 | switch (ty.zigTypeTag()) { | |
| 10858 | switch (ty.zigTypeTag(mod)) { | |
| 11048 | 10859 | .Type, |
| 11049 | 10860 | .ComptimeInt, |
| 11050 | 10861 | .ComptimeFloat, |
| ... | ... | @@ -11067,51 +10878,53 @@ fn isByRef(ty: Type) bool { |
| 11067 | 10878 | .AnyFrame, |
| 11068 | 10879 | => return false, |
| 11069 | 10880 | |
| 11070 | .Array, .Frame => return ty.hasRuntimeBits(), | |
| 10881 | .Array, .Frame => return ty.hasRuntimeBits(mod), | |
| 11071 | 10882 | .Struct => { |
| 11072 | 10883 | // Packed structs are represented to LLVM as integers. |
| 11073 | if (ty.containerLayout() == .Packed) return false; | |
| 11074 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 11075 | const tuple = ty.tupleFields(); | |
| 11076 | var count: usize = 0; | |
| 11077 | for (tuple.values, 0..) |field_val, i| { | |
| 11078 | if (field_val.tag() != .unreachable_value or !tuple.types[i].hasRuntimeBits()) continue; | |
| 11079 | ||
| 11080 | count += 1; | |
| 11081 | if (count > max_fields_byval) return true; | |
| 11082 | if (isByRef(tuple.types[i])) return true; | |
| 11083 | } | |
| 11084 | return false; | |
| 11085 | } | |
| 10884 | if (ty.containerLayout(mod) == .Packed) return false; | |
| 10885 | const struct_type = switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 10886 | .anon_struct_type => |tuple| { | |
| 10887 | var count: usize = 0; | |
| 10888 | for (tuple.types, tuple.values) |field_ty, field_val| { | |
| 10889 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 10890 | ||
| 10891 | count += 1; | |
| 10892 | if (count > max_fields_byval) return true; | |
| 10893 | if (isByRef(field_ty.toType(), mod)) return true; | |
| 10894 | } | |
| 10895 | return false; | |
| 10896 | }, | |
| 10897 | .struct_type => |s| s, | |
| 10898 | else => unreachable, | |
| 10899 | }; | |
| 10900 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 11086 | 10901 | var count: usize = 0; |
| 11087 | const fields = ty.structFields(); | |
| 11088 | for (fields.values()) |field| { | |
| 11089 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | |
| 10902 | for (struct_obj.fields.values()) |field| { | |
| 10903 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | |
| 11090 | 10904 | |
| 11091 | 10905 | count += 1; |
| 11092 | 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 | 10909 | return false; |
| 11096 | 10910 | }, |
| 11097 | .Union => switch (ty.containerLayout()) { | |
| 10911 | .Union => switch (ty.containerLayout(mod)) { | |
| 11098 | 10912 | .Packed => return false, |
| 11099 | else => return ty.hasRuntimeBits(), | |
| 10913 | else => return ty.hasRuntimeBits(mod), | |
| 11100 | 10914 | }, |
| 11101 | 10915 | .ErrorUnion => { |
| 11102 | const payload_ty = ty.errorUnionPayload(); | |
| 11103 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 10916 | const payload_ty = ty.errorUnionPayload(mod); | |
| 10917 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 11104 | 10918 | return false; |
| 11105 | 10919 | } |
| 11106 | 10920 | return true; |
| 11107 | 10921 | }, |
| 11108 | 10922 | .Optional => { |
| 11109 | var buf: Type.Payload.ElemType = undefined; | |
| 11110 | const payload_ty = ty.optionalChild(&buf); | |
| 11111 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 10923 | const payload_ty = ty.optionalChild(mod); | |
| 10924 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 11112 | 10925 | return false; |
| 11113 | 10926 | } |
| 11114 | if (ty.optionalReprIsPayload()) { | |
| 10927 | if (ty.optionalReprIsPayload(mod)) { | |
| 11115 | 10928 | return false; |
| 11116 | 10929 | } |
| 11117 | 10930 | return true; |
| ... | ... | @@ -11119,8 +10932,8 @@ fn isByRef(ty: Type) bool { |
| 11119 | 10932 | } |
| 11120 | 10933 | } |
| 11121 | 10934 | |
| 11122 | fn isScalar(ty: Type) bool { | |
| 11123 | return switch (ty.zigTypeTag()) { | |
| 10935 | fn isScalar(mod: *Module, ty: Type) bool { | |
| 10936 | return switch (ty.zigTypeTag(mod)) { | |
| 11124 | 10937 | .Void, |
| 11125 | 10938 | .Bool, |
| 11126 | 10939 | .NoReturn, |
| ... | ... | @@ -11134,8 +10947,8 @@ fn isScalar(ty: Type) bool { |
| 11134 | 10947 | .Vector, |
| 11135 | 10948 | => true, |
| 11136 | 10949 | |
| 11137 | .Struct => ty.containerLayout() == .Packed, | |
| 11138 | .Union => ty.containerLayout() == .Packed, | |
| 10950 | .Struct => ty.containerLayout(mod) == .Packed, | |
| 10951 | .Union => ty.containerLayout(mod) == .Packed, | |
| 11139 | 10952 | else => false, |
| 11140 | 10953 | }; |
| 11141 | 10954 | } |
| ... | ... | @@ -11184,10 +10997,10 @@ fn backendSupportsF128(target: std.Target) bool { |
| 11184 | 10997 | /// LLVM does not support all relevant intrinsics for all targets, so we |
| 11185 | 10998 | /// may need to manually generate a libc call |
| 11186 | 10999 | fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { |
| 11187 | return switch (scalar_ty.tag()) { | |
| 11188 | .f16 => backendSupportsF16(target), | |
| 11189 | .f80 => (target.c_type_bit_size(.longdouble) == 80) and backendSupportsF80(target), | |
| 11190 | .f128 => (target.c_type_bit_size(.longdouble) == 128) and backendSupportsF128(target), | |
| 11000 | return switch (scalar_ty.toIntern()) { | |
| 11001 | .f16_type => backendSupportsF16(target), | |
| 11002 | .f80_type => (target.c_type_bit_size(.longdouble) == 80) and backendSupportsF80(target), | |
| 11003 | .f128_type => (target.c_type_bit_size(.longdouble) == 128) and backendSupportsF128(target), | |
| 11191 | 11004 | else => true, |
| 11192 | 11005 | }; |
| 11193 | 11006 | } |
| ... | ... | @@ -11304,12 +11117,12 @@ fn buildAllocaInner( |
| 11304 | 11117 | return alloca; |
| 11305 | 11118 | } |
| 11306 | 11119 | |
| 11307 | fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 { | |
| 11308 | return @boolToInt(Type.anyerror.abiAlignment(target) > payload_ty.abiAlignment(target)); | |
| 11120 | fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 { | |
| 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 { | |
| 11312 | return @boolToInt(Type.anyerror.abiAlignment(target) <= payload_ty.abiAlignment(target)); | |
| 11124 | fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 { | |
| 11125 | return @boolToInt(Type.anyerror.abiAlignment(mod) <= payload_ty.abiAlignment(mod)); | |
| 11313 | 11126 | } |
| 11314 | 11127 | |
| 11315 | 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 | 218 | |
| 219 | 219 | pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error { |
| 220 | 220 | @setCold(true); |
| 221 | const mod = self.module; | |
| 221 | 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 | 224 | assert(self.error_msg == null); |
| 224 | 225 | self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args); |
| 225 | 226 | return error.CodegenFail; |
| ... | ... | @@ -231,12 +232,13 @@ pub const DeclGen = struct { |
| 231 | 232 | |
| 232 | 233 | /// Fetch the result-id for a previously generated instruction or constant. |
| 233 | 234 | fn resolve(self: *DeclGen, inst: Air.Inst.Ref) !IdRef { |
| 234 | if (self.air.value(inst)) |val| { | |
| 235 | const ty = self.air.typeOf(inst); | |
| 236 | if (ty.zigTypeTag() == .Fn) { | |
| 237 | const fn_decl_index = switch (val.tag()) { | |
| 238 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, | |
| 239 | .function => val.castTag(.function).?.data.owner_decl, | |
| 235 | const mod = self.module; | |
| 236 | if (try self.air.value(inst, mod)) |val| { | |
| 237 | const ty = self.typeOf(inst); | |
| 238 | if (ty.zigTypeTag(mod) == .Fn) { | |
| 239 | const fn_decl_index = switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 240 | .extern_func => |extern_func| extern_func.decl, | |
| 241 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 240 | 242 | else => unreachable, |
| 241 | 243 | }; |
| 242 | 244 | const spv_decl_index = try self.resolveDecl(fn_decl_index); |
| ... | ... | @@ -254,12 +256,12 @@ pub const DeclGen = struct { |
| 254 | 256 | /// Note: Function does not actually generate the decl. |
| 255 | 257 | fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !SpvModule.Decl.Index { |
| 256 | 258 | const decl = self.module.declPtr(decl_index); |
| 257 | self.module.markDeclAlive(decl); | |
| 259 | try self.module.markDeclAlive(decl); | |
| 258 | 260 | |
| 259 | 261 | const entry = try self.decl_link.getOrPut(decl_index); |
| 260 | 262 | if (!entry.found_existing) { |
| 261 | 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 | 265 | .func |
| 264 | 266 | else |
| 265 | 267 | .global; |
| ... | ... | @@ -340,8 +342,9 @@ pub const DeclGen = struct { |
| 340 | 342 | } |
| 341 | 343 | |
| 342 | 344 | fn arithmeticTypeInfo(self: *DeclGen, ty: Type) !ArithmeticTypeInfo { |
| 345 | const mod = self.module; | |
| 343 | 346 | const target = self.getTarget(); |
| 344 | return switch (ty.zigTypeTag()) { | |
| 347 | return switch (ty.zigTypeTag(mod)) { | |
| 345 | 348 | .Bool => ArithmeticTypeInfo{ |
| 346 | 349 | .bits = 1, // Doesn't matter for this class. |
| 347 | 350 | .is_vector = false, |
| ... | ... | @@ -355,7 +358,7 @@ pub const DeclGen = struct { |
| 355 | 358 | .class = .float, |
| 356 | 359 | }, |
| 357 | 360 | .Int => blk: { |
| 358 | const int_info = ty.intInfo(target); | |
| 361 | const int_info = ty.intInfo(mod); | |
| 359 | 362 | // TODO: Maybe it's useful to also return this value. |
| 360 | 363 | const maybe_backing_bits = self.backingIntBits(int_info.bits); |
| 361 | 364 | break :blk ArithmeticTypeInfo{ |
| ... | ... | @@ -533,34 +536,35 @@ pub const DeclGen = struct { |
| 533 | 536 | } |
| 534 | 537 | |
| 535 | 538 | fn addInt(self: *@This(), ty: Type, val: Value) !void { |
| 536 | const target = self.dg.getTarget(); | |
| 537 | const int_info = ty.intInfo(target); | |
| 539 | const mod = self.dg.module; | |
| 540 | const int_info = ty.intInfo(mod); | |
| 538 | 541 | const int_bits = switch (int_info.signedness) { |
| 539 | .signed => @bitCast(u64, val.toSignedInt(target)), | |
| 540 | .unsigned => val.toUnsignedInt(target), | |
| 542 | .signed => @bitCast(u64, val.toSignedInt(mod)), | |
| 543 | .unsigned => val.toUnsignedInt(mod), | |
| 541 | 544 | }; |
| 542 | 545 | |
| 543 | 546 | // TODO: Swap endianess if the compiler is big endian. |
| 544 | const len = ty.abiSize(target); | |
| 547 | const len = ty.abiSize(mod); | |
| 545 | 548 | try self.addBytes(std.mem.asBytes(&int_bits)[0..@intCast(usize, len)]); |
| 546 | 549 | } |
| 547 | 550 | |
| 548 | 551 | fn addFloat(self: *@This(), ty: Type, val: Value) !void { |
| 552 | const mod = self.dg.module; | |
| 549 | 553 | const target = self.dg.getTarget(); |
| 550 | const len = ty.abiSize(target); | |
| 554 | const len = ty.abiSize(mod); | |
| 551 | 555 | |
| 552 | 556 | // TODO: Swap endianess if the compiler is big endian. |
| 553 | 557 | switch (ty.floatBits(target)) { |
| 554 | 558 | 16 => { |
| 555 | const float_bits = val.toFloat(f16); | |
| 559 | const float_bits = val.toFloat(f16, mod); | |
| 556 | 560 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); |
| 557 | 561 | }, |
| 558 | 562 | 32 => { |
| 559 | const float_bits = val.toFloat(f32); | |
| 563 | const float_bits = val.toFloat(f32, mod); | |
| 560 | 564 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); |
| 561 | 565 | }, |
| 562 | 566 | 64 => { |
| 563 | const float_bits = val.toFloat(f64); | |
| 567 | const float_bits = val.toFloat(f64, mod); | |
| 564 | 568 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); |
| 565 | 569 | }, |
| 566 | 570 | else => unreachable, |
| ... | ... | @@ -569,6 +573,7 @@ pub const DeclGen = struct { |
| 569 | 573 | |
| 570 | 574 | fn addDeclRef(self: *@This(), ty: Type, decl_index: Decl.Index) !void { |
| 571 | 575 | const dg = self.dg; |
| 576 | const mod = dg.module; | |
| 572 | 577 | |
| 573 | 578 | const ty_ref = try self.dg.resolveType(ty, .indirect); |
| 574 | 579 | const ty_id = dg.typeId(ty_ref); |
| ... | ... | @@ -576,19 +581,18 @@ pub const DeclGen = struct { |
| 576 | 581 | const decl = dg.module.declPtr(decl_index); |
| 577 | 582 | const spv_decl_index = try dg.resolveDecl(decl_index); |
| 578 | 583 | |
| 579 | switch (decl.val.tag()) { | |
| 580 | .function => { | |
| 584 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { | |
| 585 | .func => { | |
| 581 | 586 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| 582 | 587 | // just generate an empty pointer. Function pointers are represented by usize for now, |
| 583 | 588 | // though. |
| 584 | try self.addInt(Type.usize, Value.initTag(.zero)); | |
| 589 | try self.addInt(Type.usize, Value.zero_usize); | |
| 585 | 590 | // TODO: Add dependency |
| 586 | 591 | return; |
| 587 | 592 | }, |
| 588 | .extern_fn => unreachable, // TODO | |
| 593 | .extern_func => unreachable, // TODO | |
| 589 | 594 | else => { |
| 590 | 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 | 597 | try self.decl_deps.put(spv_decl_index, {}); |
| 594 | 598 | |
| ... | ... | @@ -606,117 +610,122 @@ pub const DeclGen = struct { |
| 606 | 610 | } |
| 607 | 611 | } |
| 608 | 612 | |
| 609 | fn lower(self: *@This(), ty: Type, val: Value) !void { | |
| 610 | const target = self.dg.getTarget(); | |
| 613 | fn lower(self: *@This(), ty: Type, arg_val: Value) !void { | |
| 611 | 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()) { | |
| 614 | const size = ty.abiSize(target); | |
| 623 | if (val.isUndefDeep(mod)) { | |
| 624 | const size = ty.abiSize(mod); | |
| 615 | 625 | return try self.addUndef(size); |
| 616 | 626 | } |
| 617 | 627 | |
| 618 | switch (ty.zigTypeTag()) { | |
| 619 | .Int => try self.addInt(ty, val), | |
| 620 | .Float => try self.addFloat(ty, val), | |
| 621 | .Bool => try self.addConstBool(val.toBool()), | |
| 622 | .Array => switch (val.tag()) { | |
| 623 | .aggregate => { | |
| 624 | const elem_vals = val.castTag(.aggregate).?.data; | |
| 625 | const elem_ty = ty.elemType(); | |
| 626 | const len = @intCast(u32, ty.arrayLenIncludingSentinel()); // TODO: limit spir-v to 32 bit arrays in a more elegant way. | |
| 627 | for (elem_vals[0..len]) |elem_val| { | |
| 628 | try self.lower(elem_ty, elem_val); | |
| 629 | } | |
| 630 | }, | |
| 631 | .repeated => { | |
| 632 | const elem_val = val.castTag(.repeated).?.data; | |
| 633 | const elem_ty = ty.elemType(); | |
| 634 | const len = @intCast(u32, ty.arrayLen()); | |
| 635 | for (0..len) |_| { | |
| 636 | try self.lower(elem_ty, elem_val); | |
| 637 | } | |
| 638 | if (ty.sentinel()) |sentinel| { | |
| 639 | try self.lower(elem_ty, sentinel); | |
| 640 | } | |
| 641 | }, | |
| 642 | .str_lit => { | |
| 643 | const str_lit = val.castTag(.str_lit).?.data; | |
| 644 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 645 | try self.addBytes(bytes); | |
| 646 | if (ty.sentinel()) |sentinel| { | |
| 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)}), | |
| 628 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 629 | .int_type, | |
| 630 | .ptr_type, | |
| 631 | .array_type, | |
| 632 | .vector_type, | |
| 633 | .opt_type, | |
| 634 | .anyframe_type, | |
| 635 | .error_union_type, | |
| 636 | .simple_type, | |
| 637 | .struct_type, | |
| 638 | .anon_struct_type, | |
| 639 | .union_type, | |
| 640 | .opaque_type, | |
| 641 | .enum_type, | |
| 642 | .func_type, | |
| 643 | .error_set_type, | |
| 644 | .inferred_error_set_type, | |
| 645 | => unreachable, // types, not values | |
| 646 | ||
| 647 | .undef, .runtime_value => unreachable, // handled above | |
| 648 | .simple_value => |simple_value| switch (simple_value) { | |
| 649 | .undefined, | |
| 650 | .void, | |
| 651 | .null, | |
| 652 | .empty_struct, | |
| 653 | .@"unreachable", | |
| 654 | .generic_poison, | |
| 655 | => unreachable, // non-runtime values | |
| 656 | .false, .true => try self.addConstBool(val.toBool()), | |
| 655 | 657 | }, |
| 656 | .Pointer => switch (val.tag()) { | |
| 657 | .decl_ref_mut => { | |
| 658 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 659 | try self.addDeclRef(ty, decl_index); | |
| 660 | }, | |
| 661 | .decl_ref => { | |
| 662 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 663 | try self.addDeclRef(ty, decl_index); | |
| 664 | }, | |
| 665 | .slice => { | |
| 666 | const slice = val.castTag(.slice).?.data; | |
| 658 | .variable, | |
| 659 | .extern_func, | |
| 660 | .func, | |
| 661 | .enum_literal, | |
| 662 | .empty_enum_value, | |
| 663 | => unreachable, // non-runtime values | |
| 664 | .int => try self.addInt(ty, val), | |
| 665 | .err => |err| { | |
| 666 | const int = try mod.getErrorValue(err.name); | |
| 667 | try self.addConstInt(u16, @intCast(u16, int)); | |
| 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; | |
| 669 | const ptr_ty = ty.slicePtrFieldType(&buf); | |
| 674 | const eu_layout = dg.errorUnionLayout(payload_ty); | |
| 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); | |
| 672 | try self.addInt(Type.usize, slice.len); | |
| 673 | }, | |
| 674 | .null_value, .zero => try self.addNullPtr(try dg.resolveType(ty, .indirect)), | |
| 675 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | |
| 676 | try self.addInt(Type.usize, val); | |
| 677 | }, | |
| 678 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), | |
| 679 | }, | |
| 680 | .Struct => { | |
| 681 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 682 | unreachable; // TODO | |
| 679 | const payload_size = payload_ty.abiSize(mod); | |
| 680 | const error_size = Type.anyerror.abiAlignment(mod); | |
| 681 | const ty_size = ty.abiSize(mod); | |
| 682 | const padding = ty_size - payload_size - error_size; | |
| 683 | ||
| 684 | const payload_val = switch (error_union.val) { | |
| 685 | .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }), | |
| 686 | .payload => |payload| payload, | |
| 687 | }.toValue(); | |
| 688 | ||
| 689 | if (eu_layout.error_first) { | |
| 690 | try self.lower(Type.anyerror, error_val); | |
| 691 | try self.lower(payload_ty, payload_val); | |
| 683 | 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) { | |
| 687 | return dg.todo("packed struct constants", .{}); | |
| 688 | } | |
| 697 | try self.addUndef(padding); | |
| 698 | }, | |
| 699 | .enum_tag => { | |
| 700 | const int_val = try val.enumToInt(ty, mod); | |
| 689 | 701 | |
| 690 | const struct_begin = self.size; | |
| 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]); | |
| 702 | const int_ty = ty.intTagType(mod); | |
| 695 | 703 | |
| 696 | // Add padding if required. | |
| 697 | // TODO: Add to type generation as well? | |
| 698 | const unpadded_field_end = self.size - struct_begin; | |
| 699 | const padded_field_end = ty.structFieldOffset(i + 1, target); | |
| 700 | const padding = padded_field_end - unpadded_field_end; | |
| 701 | try self.addUndef(padding); | |
| 702 | } | |
| 704 | try self.lower(int_ty, int_val); | |
| 705 | }, | |
| 706 | .float => try self.addFloat(ty, val), | |
| 707 | .ptr => |ptr| { | |
| 708 | switch (ptr.addr) { | |
| 709 | .decl => |decl| try self.addDeclRef(ty, decl), | |
| 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 => { | |
| 706 | var opt_buf: Type.Payload.ElemType = undefined; | |
| 707 | const payload_ty = ty.optionalChild(&opt_buf); | |
| 708 | const has_payload = !val.isNull(); | |
| 709 | const abi_size = ty.abiSize(target); | |
| 710 | ||
| 711 | if (!payload_ty.hasRuntimeBits()) { | |
| 712 | try self.addConstBool(has_payload); | |
| 717 | .opt => { | |
| 718 | const payload_ty = ty.optionalChild(mod); | |
| 719 | const payload_val = val.optionalValue(mod); | |
| 720 | const abi_size = ty.abiSize(mod); | |
| 721 | ||
| 722 | if (!payload_ty.hasRuntimeBits(mod)) { | |
| 723 | try self.addConstBool(payload_val != null); | |
| 713 | 724 | return; |
| 714 | } else if (ty.optionalReprIsPayload()) { | |
| 725 | } else if (ty.optionalReprIsPayload(mod)) { | |
| 715 | 726 | // Optional representation is a nullable pointer or slice. |
| 716 | if (val.castTag(.opt_payload)) |payload| { | |
| 717 | try self.lower(payload_ty, payload.data); | |
| 718 | } else if (has_payload) { | |
| 719 | try self.lower(payload_ty, val); | |
| 727 | if (payload_val) |pl_val| { | |
| 728 | try self.lower(payload_ty, pl_val); | |
| 720 | 729 | } else { |
| 721 | 730 | const ptr_ty_ref = try dg.resolveType(ty, .indirect); |
| 722 | 731 | try self.addNullPtr(ptr_ty_ref); |
| ... | ... | @@ -729,102 +738,98 @@ pub const DeclGen = struct { |
| 729 | 738 | |
| 730 | 739 | // Subtract 1 for @sizeOf(bool). |
| 731 | 740 | // TODO: Make this not hardcoded. |
| 732 | const payload_size = payload_ty.abiSize(target); | |
| 741 | const payload_size = payload_ty.abiSize(mod); | |
| 733 | 742 | const padding = abi_size - payload_size - 1; |
| 734 | 743 | |
| 735 | if (val.castTag(.opt_payload)) |payload| { | |
| 736 | try self.lower(payload_ty, payload.data); | |
| 744 | if (payload_val) |pl_val| { | |
| 745 | try self.lower(payload_ty, pl_val); | |
| 737 | 746 | } else { |
| 738 | 747 | try self.addUndef(payload_size); |
| 739 | 748 | } |
| 740 | try self.addConstBool(has_payload); | |
| 749 | try self.addConstBool(payload_val != null); | |
| 741 | 750 | try self.addUndef(padding); |
| 742 | 751 | }, |
| 743 | .Enum => { | |
| 744 | var int_val_buffer: Value.Payload.U64 = undefined; | |
| 745 | const int_val = val.enumToInt(ty, &int_val_buffer); | |
| 752 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 753 | .array_type => |array_type| { | |
| 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; | |
| 748 | const int_ty = ty.intTagType(&int_ty_buffer); | |
| 775 | if (struct_ty.layout == .Packed) { | |
| 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 => { | |
| 753 | const tag_and_val = val.castTag(.@"union").?.data; | |
| 754 | const layout = ty.unionGetLayout(target); | |
| 796 | .un => |un| { | |
| 797 | const layout = ty.unionGetLayout(mod); | |
| 755 | 798 | |
| 756 | 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 | 804 | if (union_ty.layout == .Packed) { |
| 762 | 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 | 809 | const active_field_ty = union_ty.fields.values()[active_field].ty; |
| 767 | 810 | |
| 768 | 811 | const has_tag = layout.tag_size != 0; |
| 769 | 812 | const tag_first = layout.tag_align >= layout.payload_align; |
| 770 | 813 | |
| 771 | 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: { | |
| 776 | try self.lower(active_field_ty, tag_and_val.val); | |
| 777 | break :blk active_field_ty.abiSize(target); | |
| 818 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: { | |
| 819 | try self.lower(active_field_ty, un.val.toValue()); | |
| 820 | break :blk active_field_ty.abiSize(mod); | |
| 778 | 821 | } else 0; |
| 779 | 822 | |
| 780 | 823 | const payload_padding_len = layout.payload_size - active_field_size; |
| 781 | 824 | try self.addUndef(payload_padding_len); |
| 782 | 825 | |
| 783 | 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 | 830 | try self.addUndef(layout.padding); |
| 788 | 831 | }, |
| 789 | .ErrorSet => switch (val.tag()) { | |
| 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)}), | |
| 832 | .memoized_call => unreachable, | |
| 828 | 833 | } |
| 829 | 834 | } |
| 830 | 835 | }; |
| ... | ... | @@ -878,7 +883,7 @@ pub const DeclGen = struct { |
| 878 | 883 | // const target = self.getTarget(); |
| 879 | 884 | |
| 880 | 885 | // TODO: Fix the resulting global linking for these paths. |
| 881 | // if (val.isUndef()) { | |
| 886 | // if (val.isUndef(mod)) { | |
| 882 | 887 | // // Special case: the entire value is undefined. In this case, we can just |
| 883 | 888 | // // generate an OpVariable with no initializer. |
| 884 | 889 | // return try section.emit(self.spv.gpa, .OpVariable, .{ |
| ... | ... | @@ -886,7 +891,7 @@ pub const DeclGen = struct { |
| 886 | 891 | // .id_result = result_id, |
| 887 | 892 | // .storage_class = storage_class, |
| 888 | 893 | // }); |
| 889 | // } else if (ty.abiSize(target) == 0) { | |
| 894 | // } else if (ty.abiSize(mod) == 0) { | |
| 890 | 895 | // // Special case: if the type has no size, then return an undefined pointer. |
| 891 | 896 | // return try section.emit(self.spv.gpa, .OpUndef, .{ |
| 892 | 897 | // .id_result_type = self.typeId(ptr_ty_ref), |
| ... | ... | @@ -968,68 +973,25 @@ pub const DeclGen = struct { |
| 968 | 973 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. |
| 969 | 974 | /// This function should only be called during function code generation. |
| 970 | 975 | fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef { |
| 971 | const target = self.getTarget(); | |
| 976 | const mod = self.module; | |
| 972 | 977 | const result_ty_ref = try self.resolveType(ty, repr); |
| 973 | 978 | |
| 974 | 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 | 982 | return self.spv.constUndef(result_ty_ref); |
| 978 | 983 | } |
| 979 | 984 | |
| 980 | switch (ty.zigTypeTag()) { | |
| 985 | switch (ty.zigTypeTag(mod)) { | |
| 981 | 986 | .Int => { |
| 982 | if (ty.isSignedInt()) { | |
| 983 | return try self.spv.constInt(result_ty_ref, val.toSignedInt(target)); | |
| 987 | if (ty.isSignedInt(mod)) { | |
| 988 | return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod)); | |
| 984 | 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) { | |
| 989 | .direct => return try self.spv.constBool(result_ty_ref, val.toBool()), | |
| 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); | |
| 993 | .Bool => { | |
| 994 | @compileError("TODO merge conflict failure"); | |
| 1033 | 995 | }, |
| 1034 | 996 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra |
| 1035 | 997 | // OpVariable that is not really required. |
| ... | ... | @@ -1037,7 +999,7 @@ pub const DeclGen = struct { |
| 1037 | 999 | // The value cannot be generated directly, so generate it as an indirect constant, |
| 1038 | 1000 | // and then perform an OpLoad. |
| 1039 | 1001 | const result_id = self.spv.allocId(); |
| 1040 | const alignment = ty.abiAlignment(target); | |
| 1002 | const alignment = ty.abiAlignment(mod); | |
| 1041 | 1003 | const spv_decl_index = try self.spv.allocDecl(.global); |
| 1042 | 1004 | |
| 1043 | 1005 | try self.lowerIndirectConstant( |
| ... | ... | @@ -1114,9 +1076,9 @@ pub const DeclGen = struct { |
| 1114 | 1076 | /// NOTE: When the active field is set to something other than the most aligned field, the |
| 1115 | 1077 | /// resulting struct will be *underaligned*. |
| 1116 | 1078 | fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef { |
| 1117 | const target = self.getTarget(); | |
| 1118 | const layout = ty.unionGetLayout(target); | |
| 1119 | const union_ty = ty.cast(Type.Payload.Union).?.data; | |
| 1079 | const mod = self.module; | |
| 1080 | const layout = ty.unionGetLayout(mod); | |
| 1081 | const union_ty = mod.typeToUnion(ty).?; | |
| 1120 | 1082 | |
| 1121 | 1083 | if (union_ty.layout == .Packed) { |
| 1122 | 1084 | return self.todo("packed union types", .{}); |
| ... | ... | @@ -1143,11 +1105,11 @@ pub const DeclGen = struct { |
| 1143 | 1105 | const active_field = maybe_active_field orelse layout.most_aligned_field; |
| 1144 | 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 | 1109 | const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect); |
| 1148 | 1110 | member_types.appendAssumeCapacity(active_payload_ty_ref); |
| 1149 | 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 | 1113 | } else 0; |
| 1152 | 1114 | |
| 1153 | 1115 | const payload_padding_len = layout.payload_size - active_field_size; |
| ... | ... | @@ -1177,21 +1139,21 @@ pub const DeclGen = struct { |
| 1177 | 1139 | |
| 1178 | 1140 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. |
| 1179 | 1141 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef { |
| 1142 | const mod = self.module; | |
| 1180 | 1143 | log.debug("resolveType: ty = {}", .{ty.fmt(self.module)}); |
| 1181 | 1144 | const target = self.getTarget(); |
| 1182 | switch (ty.zigTypeTag()) { | |
| 1145 | switch (ty.zigTypeTag(mod)) { | |
| 1183 | 1146 | .Void, .NoReturn => return try self.spv.resolve(.void_type), |
| 1184 | 1147 | .Bool => switch (repr) { |
| 1185 | 1148 | .direct => return try self.spv.resolve(.bool_type), |
| 1186 | 1149 | .indirect => return try self.intType(.unsigned, 1), |
| 1187 | 1150 | }, |
| 1188 | 1151 | .Int => { |
| 1189 | const int_info = ty.intInfo(target); | |
| 1152 | const int_info = ty.intInfo(mod); | |
| 1190 | 1153 | return try self.intType(int_info.signedness, int_info.bits); |
| 1191 | 1154 | }, |
| 1192 | 1155 | .Enum => { |
| 1193 | var buffer: Type.Payload.Bits = undefined; | |
| 1194 | const tag_ty = ty.intTagType(&buffer); | |
| 1156 | const tag_ty = ty.intTagType(mod); | |
| 1195 | 1157 | return self.resolveType(tag_ty, repr); |
| 1196 | 1158 | }, |
| 1197 | 1159 | .Float => { |
| ... | ... | @@ -1213,17 +1175,18 @@ pub const DeclGen = struct { |
| 1213 | 1175 | return try self.spv.resolve(.{ .float_type = .{ .bits = bits } }); |
| 1214 | 1176 | }, |
| 1215 | 1177 | .Array => { |
| 1216 | const elem_ty = ty.childType(); | |
| 1178 | const elem_ty = ty.childType(mod); | |
| 1217 | 1179 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); |
| 1218 | const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse { | |
| 1219 | return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()}); | |
| 1180 | const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse { | |
| 1181 | return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)}); | |
| 1220 | 1182 | }; |
| 1221 | 1183 | return self.spv.arrayType(total_len, elem_ty_ref); |
| 1222 | 1184 | }, |
| 1223 | 1185 | .Fn => switch (repr) { |
| 1224 | 1186 | .direct => { |
| 1187 | const fn_info = mod.typeToFunc(ty).?; | |
| 1225 | 1188 | // TODO: Put this somewhere in Sema.zig |
| 1226 | if (ty.fnIsVarArgs()) | |
| 1189 | if (fn_info.is_var_args) | |
| 1227 | 1190 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); |
| 1228 | 1191 | |
| 1229 | 1192 | const param_ty_refs = try self.gpa.alloc(CacheRef, ty.fnParamLen()); |
| ... | ... | @@ -1245,7 +1208,7 @@ pub const DeclGen = struct { |
| 1245 | 1208 | }, |
| 1246 | 1209 | }, |
| 1247 | 1210 | .Pointer => { |
| 1248 | const ptr_info = ty.ptrInfo().data; | |
| 1211 | const ptr_info = ty.ptrInfo(mod); | |
| 1249 | 1212 | |
| 1250 | 1213 | const storage_class = spvStorageClass(ptr_info.@"addrspace"); |
| 1251 | 1214 | const child_ty_ref = try self.resolveType(ptr_info.pointee_type, .indirect); |
| ... | ... | @@ -1277,8 +1240,8 @@ pub const DeclGen = struct { |
| 1277 | 1240 | // TODO: Properly verify sizes and child type. |
| 1278 | 1241 | |
| 1279 | 1242 | return try self.spv.resolve(.{ .vector_type = .{ |
| 1280 | .component_type = try self.resolveType(ty.elemType(), repr), | |
| 1281 | .component_count = @intCast(u32, ty.vectorLen()), | |
| 1243 | .component_type = try self.resolveType(ty.childType(mod), repr), | |
| 1244 | .component_count = @intCast(u32, ty.vectorLen(mod)), | |
| 1282 | 1245 | } }); |
| 1283 | 1246 | }, |
| 1284 | 1247 | .Struct => { |
| ... | ... | @@ -1290,7 +1253,7 @@ pub const DeclGen = struct { |
| 1290 | 1253 | var member_index: usize = 0; |
| 1291 | 1254 | for (tuple.types, 0..) |field_ty, i| { |
| 1292 | 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 | 1258 | member_types[member_index] = try self.resolveType(field_ty, .indirect); |
| 1296 | 1259 | member_index += 1; |
| ... | ... | @@ -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 | 1269 | if (struct_ty.layout == .Packed) { |
| 1307 | 1270 | return try self.resolveType(struct_ty.backing_int_ty, .direct); |
| ... | ... | @@ -1314,16 +1277,16 @@ pub const DeclGen = struct { |
| 1314 | 1277 | defer self.gpa.free(member_names); |
| 1315 | 1278 | |
| 1316 | 1279 | var member_index: usize = 0; |
| 1317 | for (struct_ty.fields.values(), 0..) |field, i| { | |
| 1318 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | |
| 1280 | const struct_obj = void; // TODO | |
| 1281 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 1282 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | |
| 1319 | 1283 | |
| 1320 | 1284 | member_types[member_index] = try self.resolveType(field.ty, .indirect); |
| 1321 | 1285 | member_names[member_index] = try self.spv.resolveString(struct_ty.fields.keys()[i]); |
| 1322 | 1286 | member_index += 1; |
| 1323 | 1287 | } |
| 1324 | 1288 | |
| 1325 | const name = try struct_ty.getFullyQualifiedName(self.module); | |
| 1326 | defer self.module.gpa.free(name); | |
| 1289 | const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module)); | |
| 1327 | 1290 | |
| 1328 | 1291 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1329 | 1292 | .name = try self.spv.resolveString(name), |
| ... | ... | @@ -1332,9 +1295,8 @@ pub const DeclGen = struct { |
| 1332 | 1295 | } }); |
| 1333 | 1296 | }, |
| 1334 | 1297 | .Optional => { |
| 1335 | var buf: Type.Payload.ElemType = undefined; | |
| 1336 | const payload_ty = ty.optionalChild(&buf); | |
| 1337 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 1298 | const payload_ty = ty.optionalChild(mod); | |
| 1299 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1338 | 1300 | // Just use a bool. |
| 1339 | 1301 | // Note: Always generate the bool with indirect format, to save on some sanity |
| 1340 | 1302 | // Perform the conversion to a direct bool when the field is extracted. |
| ... | ... | @@ -1342,7 +1304,7 @@ pub const DeclGen = struct { |
| 1342 | 1304 | } |
| 1343 | 1305 | |
| 1344 | 1306 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); |
| 1345 | if (ty.optionalReprIsPayload()) { | |
| 1307 | if (ty.optionalReprIsPayload(mod)) { | |
| 1346 | 1308 | // Optional is actually a pointer or a slice. |
| 1347 | 1309 | return payload_ty_ref; |
| 1348 | 1310 | } |
| ... | ... | @@ -1360,7 +1322,7 @@ pub const DeclGen = struct { |
| 1360 | 1322 | .Union => return try self.resolveUnionType(ty, null), |
| 1361 | 1323 | .ErrorSet => return try self.intType(.unsigned, 16), |
| 1362 | 1324 | .ErrorUnion => { |
| 1363 | const payload_ty = ty.errorUnionPayload(); | |
| 1325 | const payload_ty = ty.errorUnionPayload(mod); | |
| 1364 | 1326 | const error_ty_ref = try self.resolveType(Type.anyerror, .indirect); |
| 1365 | 1327 | |
| 1366 | 1328 | const eu_layout = self.errorUnionLayout(payload_ty); |
| ... | ... | @@ -1445,14 +1407,14 @@ pub const DeclGen = struct { |
| 1445 | 1407 | }; |
| 1446 | 1408 | |
| 1447 | 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); | |
| 1451 | const payload_align = payload_ty.abiAlignment(target); | |
| 1412 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 1413 | const payload_align = payload_ty.abiAlignment(mod); | |
| 1452 | 1414 | |
| 1453 | 1415 | const error_first = error_align > payload_align; |
| 1454 | 1416 | return .{ |
| 1455 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(), | |
| 1417 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod), | |
| 1456 | 1418 | .error_first = error_first, |
| 1457 | 1419 | }; |
| 1458 | 1420 | } |
| ... | ... | @@ -1529,28 +1491,28 @@ pub const DeclGen = struct { |
| 1529 | 1491 | } |
| 1530 | 1492 | |
| 1531 | 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 | 1497 | const spv_decl_index = try self.resolveDecl(self.decl_index); |
| 1534 | 1498 | |
| 1535 | 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)) |_| { | |
| 1539 | assert(decl.ty.zigTypeTag() == .Fn); | |
| 1501 | if (decl.val.getFunction(mod)) |_| { | |
| 1502 | assert(decl.ty.zigTypeTag(mod) == .Fn); | |
| 1540 | 1503 | const prototype_id = try self.resolveTypeId(decl.ty); |
| 1541 | 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 | 1506 | .id_result = decl_id, |
| 1544 | 1507 | .function_control = .{}, // TODO: We can set inline here if the type requires it. |
| 1545 | 1508 | .function_type = prototype_id, |
| 1546 | 1509 | }); |
| 1547 | 1510 | |
| 1548 | const params = decl.ty.fnParamLen(); | |
| 1549 | var i: usize = 0; | |
| 1511 | const fn_info = mod.typeToFunc(decl.ty).?; | |
| 1550 | 1512 | |
| 1551 | try self.args.ensureUnusedCapacity(self.gpa, params); | |
| 1552 | while (i < params) : (i += 1) { | |
| 1553 | const param_type_id = try self.resolveTypeId(decl.ty.fnParamType(i)); | |
| 1513 | try self.args.ensureUnusedCapacity(self.gpa, fn_info.param_types.len); | |
| 1514 | for (fn_info.param_types) |param_type| { | |
| 1515 | const param_type_id = try self.resolveTypeId(param_type.toType()); | |
| 1554 | 1516 | const arg_result_id = self.spv.allocId(); |
| 1555 | 1517 | try self.func.prologue.emit(self.spv.gpa, .OpFunctionParameter, .{ |
| 1556 | 1518 | .id_result_type = param_type_id, |
| ... | ... | @@ -1576,8 +1538,7 @@ pub const DeclGen = struct { |
| 1576 | 1538 | try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); |
| 1577 | 1539 | try self.spv.addFunction(spv_decl_index, self.func); |
| 1578 | 1540 | |
| 1579 | const fqn = try decl.getFullyQualifiedName(self.module); | |
| 1580 | defer self.module.gpa.free(fqn); | |
| 1541 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(self.module)); | |
| 1581 | 1542 | |
| 1582 | 1543 | try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ |
| 1583 | 1544 | .target = decl_id, |
| ... | ... | @@ -1589,12 +1550,12 @@ pub const DeclGen = struct { |
| 1589 | 1550 | try self.generateTestEntryPoint(fqn, spv_decl_index); |
| 1590 | 1551 | } |
| 1591 | 1552 | } else { |
| 1592 | const init_val = if (decl.val.castTag(.variable)) |payload| | |
| 1593 | payload.data.init | |
| 1553 | const init_val = if (decl.val.getVariable(mod)) |payload| | |
| 1554 | payload.init.toValue() | |
| 1594 | 1555 | else |
| 1595 | 1556 | decl.val; |
| 1596 | 1557 | |
| 1597 | if (init_val.tag() == .unreachable_value) { | |
| 1558 | if (init_val.ip_index == .unreachable_value) { | |
| 1598 | 1559 | return self.todo("importing extern variables", .{}); |
| 1599 | 1560 | } |
| 1600 | 1561 | |
| ... | ... | @@ -1634,7 +1595,8 @@ pub const DeclGen = struct { |
| 1634 | 1595 | /// Convert representation from indirect (in memory) to direct (in 'register') |
| 1635 | 1596 | /// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct). |
| 1636 | 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 | 1600 | .Bool => blk: { |
| 1639 | 1601 | const direct_bool_ty_ref = try self.resolveType(ty, .direct); |
| 1640 | 1602 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); |
| ... | ... | @@ -1655,7 +1617,8 @@ pub const DeclGen = struct { |
| 1655 | 1617 | /// Convert representation from direct (in 'register) to direct (in memory) |
| 1656 | 1618 | /// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect). |
| 1657 | 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 | 1622 | .Bool => blk: { |
| 1660 | 1623 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); |
| 1661 | 1624 | break :blk self.boolToInt(indirect_bool_ty_ref, operand_id); |
| ... | ... | @@ -1679,11 +1642,12 @@ pub const DeclGen = struct { |
| 1679 | 1642 | } |
| 1680 | 1643 | |
| 1681 | 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 | 1647 | const indirect_value_ty_ref = try self.resolveType(value_ty, .indirect); |
| 1684 | 1648 | const result_id = self.spv.allocId(); |
| 1685 | 1649 | const access = spec.MemoryAccess.Extended{ |
| 1686 | .Volatile = ptr_ty.isVolatilePtr(), | |
| 1650 | .Volatile = ptr_ty.isVolatilePtr(mod), | |
| 1687 | 1651 | }; |
| 1688 | 1652 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 1689 | 1653 | .id_result_type = self.typeId(indirect_value_ty_ref), |
| ... | ... | @@ -1695,10 +1659,11 @@ pub const DeclGen = struct { |
| 1695 | 1659 | } |
| 1696 | 1660 | |
| 1697 | 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 | 1664 | const indirect_value_id = try self.convertToIndirect(value_ty, value_id); |
| 1700 | 1665 | const access = spec.MemoryAccess.Extended{ |
| 1701 | .Volatile = ptr_ty.isVolatilePtr(), | |
| 1666 | .Volatile = ptr_ty.isVolatilePtr(mod), | |
| 1702 | 1667 | }; |
| 1703 | 1668 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 1704 | 1669 | .pointer = ptr_id, |
| ... | ... | @@ -1714,10 +1679,11 @@ pub const DeclGen = struct { |
| 1714 | 1679 | } |
| 1715 | 1680 | |
| 1716 | 1681 | fn genInst(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 1682 | const mod = self.module; | |
| 1683 | const ip = &mod.intern_pool; | |
| 1717 | 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 | 1686 | return; |
| 1720 | } | |
| 1721 | 1687 | |
| 1722 | 1688 | const air_tags = self.air.instructions.items(.tag); |
| 1723 | 1689 | const maybe_result_id: ?IdRef = switch (air_tags[inst]) { |
| ... | ... | @@ -1794,8 +1760,6 @@ pub const DeclGen = struct { |
| 1794 | 1760 | .br => return self.airBr(inst), |
| 1795 | 1761 | .breakpoint => return, |
| 1796 | 1762 | .cond_br => return self.airCondBr(inst), |
| 1797 | .constant => unreachable, | |
| 1798 | .const_ty => unreachable, | |
| 1799 | 1763 | .dbg_stmt => return self.airDbgStmt(inst), |
| 1800 | 1764 | .loop => return self.airLoop(inst), |
| 1801 | 1765 | .ret => return self.airRet(inst), |
| ... | ... | @@ -1841,7 +1805,7 @@ pub const DeclGen = struct { |
| 1841 | 1805 | const lhs_id = try self.resolve(bin_op.lhs); |
| 1842 | 1806 | const rhs_id = try self.resolve(bin_op.rhs); |
| 1843 | 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 | 1809 | try self.func.body.emit(self.spv.gpa, opcode, .{ |
| 1846 | 1810 | .id_result_type = result_type_id, |
| 1847 | 1811 | .id_result = result_id, |
| ... | ... | @@ -1856,7 +1820,7 @@ pub const DeclGen = struct { |
| 1856 | 1820 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1857 | 1821 | const lhs_id = try self.resolve(bin_op.lhs); |
| 1858 | 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 | 1825 | // the shift and the base must be the same type in SPIR-V, but in Zig the shift is a smaller int. |
| 1862 | 1826 | const shift_id = self.spv.allocId(); |
| ... | ... | @@ -1901,15 +1865,15 @@ pub const DeclGen = struct { |
| 1901 | 1865 | if (self.liveness.isUnused(inst)) return null; |
| 1902 | 1866 | // LHS and RHS are guaranteed to have the same type, and AIR guarantees |
| 1903 | 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 | 1869 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1906 | 1870 | var lhs_id = try self.resolve(bin_op.lhs); |
| 1907 | 1871 | var rhs_id = try self.resolve(bin_op.rhs); |
| 1908 | 1872 | |
| 1909 | 1873 | const result_ty_ref = try self.resolveType(ty, .direct); |
| 1910 | 1874 | |
| 1911 | assert(self.air.typeOf(bin_op.lhs).eql(ty, self.module)); | |
| 1912 | assert(self.air.typeOf(bin_op.rhs).eql(ty, self.module)); | |
| 1875 | assert(self.typeOf(bin_op.lhs).eql(ty, self.module)); | |
| 1876 | assert(self.typeOf(bin_op.rhs).eql(ty, self.module)); | |
| 1913 | 1877 | |
| 1914 | 1878 | // Binary operations are generally applicable to both scalar and vector operations |
| 1915 | 1879 | // in SPIR-V, but int and float versions of operations require different opcodes. |
| ... | ... | @@ -1965,8 +1929,8 @@ pub const DeclGen = struct { |
| 1965 | 1929 | const lhs = try self.resolve(extra.lhs); |
| 1966 | 1930 | const rhs = try self.resolve(extra.rhs); |
| 1967 | 1931 | |
| 1968 | const operand_ty = self.air.typeOf(extra.lhs); | |
| 1969 | const result_ty = self.air.typeOfIndex(inst); | |
| 1932 | const operand_ty = self.typeOf(extra.lhs); | |
| 1933 | const result_ty = self.typeOfIndex(inst); | |
| 1970 | 1934 | |
| 1971 | 1935 | const info = try self.arithmeticTypeInfo(operand_ty); |
| 1972 | 1936 | switch (info.class) { |
| ... | ... | @@ -2056,15 +2020,16 @@ pub const DeclGen = struct { |
| 2056 | 2020 | } |
| 2057 | 2021 | |
| 2058 | 2022 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2023 | const mod = self.module; | |
| 2059 | 2024 | if (self.liveness.isUnused(inst)) return null; |
| 2060 | const ty = self.air.typeOfIndex(inst); | |
| 2025 | const ty = self.typeOfIndex(inst); | |
| 2061 | 2026 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2062 | 2027 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 2063 | 2028 | const a = try self.resolve(extra.a); |
| 2064 | 2029 | const b = try self.resolve(extra.b); |
| 2065 | const mask = self.air.values[extra.mask]; | |
| 2030 | const mask = extra.mask.toValue(); | |
| 2066 | 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 | 2034 | const result_id = self.spv.allocId(); |
| 2070 | 2035 | const result_type_id = try self.resolveTypeId(ty); |
| ... | ... | @@ -2078,12 +2043,11 @@ pub const DeclGen = struct { |
| 2078 | 2043 | |
| 2079 | 2044 | var i: usize = 0; |
| 2080 | 2045 | while (i < mask_len) : (i += 1) { |
| 2081 | var buf: Value.ElemValueBuffer = undefined; | |
| 2082 | const elem = mask.elemValueBuffer(self.module, i, &buf); | |
| 2083 | if (elem.isUndef()) { | |
| 2046 | const elem = try mask.elemValue(mod, i); | |
| 2047 | if (elem.isUndef(mod)) { | |
| 2084 | 2048 | self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); |
| 2085 | 2049 | } else { |
| 2086 | const int = elem.toSignedInt(self.getTarget()); | |
| 2050 | const int = elem.toSignedInt(mod); | |
| 2087 | 2051 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); |
| 2088 | 2052 | self.func.body.writeOperand(spec.LiteralInteger, unsigned); |
| 2089 | 2053 | } |
| ... | ... | @@ -2130,9 +2094,10 @@ pub const DeclGen = struct { |
| 2130 | 2094 | } |
| 2131 | 2095 | |
| 2132 | 2096 | fn ptrAdd(self: *DeclGen, result_ty: Type, ptr_ty: Type, ptr_id: IdRef, offset_id: IdRef) !IdRef { |
| 2097 | const mod = self.module; | |
| 2133 | 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 | 2101 | .One => { |
| 2137 | 2102 | // Pointer to array |
| 2138 | 2103 | // TODO: Is this correct? |
| ... | ... | @@ -2155,8 +2120,8 @@ pub const DeclGen = struct { |
| 2155 | 2120 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2156 | 2121 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2157 | 2122 | const offset_id = try self.resolve(bin_op.rhs); |
| 2158 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 2159 | const result_ty = self.air.typeOfIndex(inst); | |
| 2123 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 2124 | const result_ty = self.typeOfIndex(inst); | |
| 2160 | 2125 | |
| 2161 | 2126 | return try self.ptrAdd(result_ty, ptr_ty, ptr_id, offset_id); |
| 2162 | 2127 | } |
| ... | ... | @@ -2166,11 +2131,11 @@ pub const DeclGen = struct { |
| 2166 | 2131 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2167 | 2132 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2168 | 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 | 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 | 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 | 2140 | const negative_offset_id = self.spv.allocId(); |
| 2176 | 2141 | try self.func.body.emit(self.spv.gpa, .OpSNegate, .{ |
| ... | ... | @@ -2189,13 +2154,13 @@ pub const DeclGen = struct { |
| 2189 | 2154 | lhs_id: IdRef, |
| 2190 | 2155 | rhs_id: IdRef, |
| 2191 | 2156 | ) !IdRef { |
| 2157 | const mod = self.module; | |
| 2192 | 2158 | var cmp_lhs_id = lhs_id; |
| 2193 | 2159 | var cmp_rhs_id = rhs_id; |
| 2194 | 2160 | const opcode: Opcode = opcode: { |
| 2195 | var int_buffer: Type.Payload.Bits = undefined; | |
| 2196 | const op_ty = switch (ty.zigTypeTag()) { | |
| 2161 | const op_ty = switch (ty.zigTypeTag(mod)) { | |
| 2197 | 2162 | .Int, .Bool, .Float => ty, |
| 2198 | .Enum => ty.intTagType(&int_buffer), | |
| 2163 | .Enum => ty.intTagType(), | |
| 2199 | 2164 | .ErrorSet => Type.u16, |
| 2200 | 2165 | .Pointer => blk: { |
| 2201 | 2166 | // Note that while SPIR-V offers OpPtrEqual and OpPtrNotEqual, they are |
| ... | ... | @@ -2291,8 +2256,8 @@ pub const DeclGen = struct { |
| 2291 | 2256 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2292 | 2257 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2293 | 2258 | const bool_ty_id = try self.resolveTypeId(Type.bool); |
| 2294 | const ty = self.air.typeOf(bin_op.lhs); | |
| 2295 | assert(ty.eql(self.air.typeOf(bin_op.rhs), self.module)); | |
| 2259 | const ty = self.typeOf(bin_op.lhs); | |
| 2260 | assert(ty.eql(self.typeOf(bin_op.rhs), self.module)); | |
| 2296 | 2261 | |
| 2297 | 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 | 2268 | src_ty: Type, |
| 2304 | 2269 | src_id: IdRef, |
| 2305 | 2270 | ) !IdRef { |
| 2271 | const mod = self.module; | |
| 2306 | 2272 | const dst_ty_ref = try self.resolveType(dst_ty, .direct); |
| 2307 | 2273 | const result_id = self.spv.allocId(); |
| 2308 | 2274 | |
| 2309 | 2275 | // TODO: Some more cases are missing here |
| 2310 | 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 | 2279 | try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{ |
| 2314 | 2280 | .id_result_type = self.typeId(dst_ty_ref), |
| 2315 | 2281 | .id_result = result_id, |
| ... | ... | @@ -2329,8 +2295,8 @@ pub const DeclGen = struct { |
| 2329 | 2295 | if (self.liveness.isUnused(inst)) return null; |
| 2330 | 2296 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2331 | 2297 | const operand_id = try self.resolve(ty_op.operand); |
| 2332 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 2333 | const result_ty = self.air.typeOfIndex(inst); | |
| 2298 | const operand_ty = self.typeOf(ty_op.operand); | |
| 2299 | const result_ty = self.typeOfIndex(inst); | |
| 2334 | 2300 | return try self.bitCast(result_ty, operand_ty, operand_id); |
| 2335 | 2301 | } |
| 2336 | 2302 | |
| ... | ... | @@ -2339,11 +2305,11 @@ pub const DeclGen = struct { |
| 2339 | 2305 | |
| 2340 | 2306 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2341 | 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 | 2309 | const dest_ty_id = try self.resolveTypeId(dest_ty); |
| 2344 | 2310 | |
| 2345 | const target = self.getTarget(); | |
| 2346 | const dest_info = dest_ty.intInfo(target); | |
| 2311 | const mod = self.module; | |
| 2312 | const dest_info = dest_ty.intInfo(mod); | |
| 2347 | 2313 | |
| 2348 | 2314 | // TODO: Masking? |
| 2349 | 2315 | |
| ... | ... | @@ -2383,10 +2349,10 @@ pub const DeclGen = struct { |
| 2383 | 2349 | if (self.liveness.isUnused(inst)) return null; |
| 2384 | 2350 | |
| 2385 | 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 | 2353 | const operand_id = try self.resolve(ty_op.operand); |
| 2388 | 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 | 2356 | const dest_ty_id = try self.resolveTypeId(dest_ty); |
| 2391 | 2357 | |
| 2392 | 2358 | const result_id = self.spv.allocId(); |
| ... | ... | @@ -2410,7 +2376,7 @@ pub const DeclGen = struct { |
| 2410 | 2376 | |
| 2411 | 2377 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2412 | 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 | 2380 | const dest_info = try self.arithmeticTypeInfo(dest_ty); |
| 2415 | 2381 | const dest_ty_id = try self.resolveTypeId(dest_ty); |
| 2416 | 2382 | |
| ... | ... | @@ -2447,20 +2413,21 @@ pub const DeclGen = struct { |
| 2447 | 2413 | fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef { |
| 2448 | 2414 | if (self.liveness.isUnused(inst)) return null; |
| 2449 | 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 | 2417 | const operand_id = try self.resolve(ty_op.operand); |
| 2452 | 2418 | return try self.extractField(field_ty, operand_id, field); |
| 2453 | 2419 | } |
| 2454 | 2420 | |
| 2455 | 2421 | fn airSliceElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2422 | const mod = self.module; | |
| 2456 | 2423 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2457 | const slice_ty = self.air.typeOf(bin_op.lhs); | |
| 2458 | if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null; | |
| 2424 | const slice_ty = self.typeOf(bin_op.lhs); | |
| 2425 | if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) return null; | |
| 2459 | 2426 | |
| 2460 | 2427 | const slice_id = try self.resolve(bin_op.lhs); |
| 2461 | 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 | 2431 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 2465 | 2432 | |
| 2466 | 2433 | const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); |
| ... | ... | @@ -2468,15 +2435,16 @@ pub const DeclGen = struct { |
| 2468 | 2435 | } |
| 2469 | 2436 | |
| 2470 | 2437 | fn airSliceElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2438 | const mod = self.module; | |
| 2471 | 2439 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2472 | const slice_ty = self.air.typeOf(bin_op.lhs); | |
| 2473 | if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null; | |
| 2440 | const slice_ty = self.typeOf(bin_op.lhs); | |
| 2441 | if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) return null; | |
| 2474 | 2442 | |
| 2475 | 2443 | const slice_id = try self.resolve(bin_op.lhs); |
| 2476 | 2444 | const index_id = try self.resolve(bin_op.rhs); |
| 2477 | 2445 | |
| 2478 | 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 | 2448 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 2481 | 2449 | |
| 2482 | 2450 | const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); |
| ... | ... | @@ -2485,11 +2453,12 @@ pub const DeclGen = struct { |
| 2485 | 2453 | } |
| 2486 | 2454 | |
| 2487 | 2455 | fn ptrElemPtr(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, index_id: IdRef) !IdRef { |
| 2456 | const mod = self.module; | |
| 2488 | 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 | 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())); | |
| 2492 | if (ptr_ty.isSinglePointer()) { | |
| 2460 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(ptr_ty.ptrAddressSpace(mod))); | |
| 2461 | if (ptr_ty.isSinglePointer(mod)) { | |
| 2493 | 2462 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 2494 | 2463 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. |
| 2495 | 2464 | return try self.accessChain(elem_ptr_ty_ref, ptr_id, &.{index_id}); |
| ... | ... | @@ -2502,12 +2471,13 @@ pub const DeclGen = struct { |
| 2502 | 2471 | fn airPtrElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2503 | 2472 | if (self.liveness.isUnused(inst)) return null; |
| 2504 | 2473 | |
| 2474 | const mod = self.module; | |
| 2505 | 2475 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2506 | 2476 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2507 | const ptr_ty = self.air.typeOf(bin_op.lhs); | |
| 2508 | const elem_ty = ptr_ty.childType(); | |
| 2477 | const ptr_ty = self.typeOf(bin_op.lhs); | |
| 2478 | const elem_ty = ptr_ty.childType(mod); | |
| 2509 | 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 | 2482 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2513 | 2483 | const index_id = try self.resolve(bin_op.rhs); |
| ... | ... | @@ -2515,8 +2485,9 @@ pub const DeclGen = struct { |
| 2515 | 2485 | } |
| 2516 | 2486 | |
| 2517 | 2487 | fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2488 | const mod = self.module; | |
| 2518 | 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 | 2491 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2521 | 2492 | const index_id = try self.resolve(bin_op.rhs); |
| 2522 | 2493 | |
| ... | ... | @@ -2525,19 +2496,19 @@ pub const DeclGen = struct { |
| 2525 | 2496 | // If we have a pointer-to-array, construct an element pointer to use with load() |
| 2526 | 2497 | // If we pass ptr_ty directly, it will attempt to load the entire array rather than |
| 2527 | 2498 | // just an element. |
| 2528 | var elem_ptr_info = ptr_ty.ptrInfo(); | |
| 2529 | elem_ptr_info.data.size = .One; | |
| 2530 | const elem_ptr_ty = Type.initPayload(&elem_ptr_info.base); | |
| 2499 | var elem_ptr_info = ptr_ty.ptrInfo(mod); | |
| 2500 | elem_ptr_info.size = .One; | |
| 2501 | const elem_ptr_ty = try Type.ptr(undefined, mod, elem_ptr_info); | |
| 2531 | 2502 | |
| 2532 | 2503 | return try self.load(elem_ptr_ty, elem_ptr_id); |
| 2533 | 2504 | } |
| 2534 | 2505 | |
| 2535 | 2506 | fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2536 | 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(); | |
| 2540 | const layout = un_ty.unionGetLayout(target); | |
| 2510 | const mod = self.module; | |
| 2511 | const layout = un_ty.unionGetLayout(mod); | |
| 2541 | 2512 | if (layout.tag_size == 0) return null; |
| 2542 | 2513 | |
| 2543 | 2514 | const union_handle = try self.resolve(ty_op.operand); |
| ... | ... | @@ -2551,17 +2522,18 @@ pub const DeclGen = struct { |
| 2551 | 2522 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2552 | 2523 | if (self.liveness.isUnused(inst)) return null; |
| 2553 | 2524 | |
| 2525 | const mod = self.module; | |
| 2554 | 2526 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2555 | 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 | 2530 | const object_id = try self.resolve(struct_field.struct_operand); |
| 2559 | 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 | 2538 | return try self.extractField(field_ty, object_id, field_index); |
| 2567 | 2539 | } |
| ... | ... | @@ -2573,9 +2545,10 @@ pub const DeclGen = struct { |
| 2573 | 2545 | object_ptr: IdRef, |
| 2574 | 2546 | field_index: u32, |
| 2575 | 2547 | ) !?IdRef { |
| 2576 | const object_ty = object_ptr_ty.childType(); | |
| 2577 | switch (object_ty.zigTypeTag()) { | |
| 2578 | .Struct => switch (object_ty.containerLayout()) { | |
| 2548 | const mod = self.module; | |
| 2549 | const object_ty = object_ptr_ty.childType(mod); | |
| 2550 | switch (object_ty.zigTypeTag(mod)) { | |
| 2551 | .Struct => switch (object_ty.containerLayout(mod)) { | |
| 2579 | 2552 | .Packed => unreachable, // TODO |
| 2580 | 2553 | else => { |
| 2581 | 2554 | const field_index_ty_ref = try self.intType(.unsigned, 32); |
| ... | ... | @@ -2592,8 +2565,8 @@ pub const DeclGen = struct { |
| 2592 | 2565 | if (self.liveness.isUnused(inst)) return null; |
| 2593 | 2566 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2594 | 2567 | const struct_ptr = try self.resolve(ty_op.operand); |
| 2595 | const struct_ptr_ty = self.air.typeOf(ty_op.operand); | |
| 2596 | const result_ptr_ty = self.air.typeOfIndex(inst); | |
| 2568 | const struct_ptr_ty = self.typeOf(ty_op.operand); | |
| 2569 | const result_ptr_ty = self.typeOfIndex(inst); | |
| 2597 | 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 | 2622 | |
| 2650 | 2623 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2651 | 2624 | if (self.liveness.isUnused(inst)) return null; |
| 2652 | const ptr_ty = self.air.typeOfIndex(inst); | |
| 2653 | assert(ptr_ty.ptrAddressSpace() == .generic); | |
| 2654 | const child_ty = ptr_ty.childType(); | |
| 2625 | const mod = self.module; | |
| 2626 | const ptr_ty = self.typeOfIndex(inst); | |
| 2627 | assert(ptr_ty.ptrAddressSpace(mod) == .generic); | |
| 2628 | const child_ty = ptr_ty.childType(mod); | |
| 2655 | 2629 | const child_ty_ref = try self.resolveType(child_ty, .indirect); |
| 2656 | 2630 | return try self.alloc(child_ty_ref, null); |
| 2657 | 2631 | } |
| ... | ... | @@ -2667,6 +2641,7 @@ pub const DeclGen = struct { |
| 2667 | 2641 | // the current block by first generating the code of the block, then a label, and then generate the rest of the current |
| 2668 | 2642 | // ir.Block in a different SPIR-V block. |
| 2669 | 2643 | |
| 2644 | const mod = self.module; | |
| 2670 | 2645 | const label_id = self.spv.allocId(); |
| 2671 | 2646 | |
| 2672 | 2647 | // 4 chosen as arbitrary initial capacity. |
| ... | ... | @@ -2681,7 +2656,7 @@ pub const DeclGen = struct { |
| 2681 | 2656 | incoming_blocks.deinit(self.gpa); |
| 2682 | 2657 | } |
| 2683 | 2658 | |
| 2684 | const ty = self.air.typeOfIndex(inst); | |
| 2659 | const ty = self.typeOfIndex(inst); | |
| 2685 | 2660 | const inst_datas = self.air.instructions.items(.data); |
| 2686 | 2661 | const extra = self.air.extraData(Air.Block, inst_datas[inst].ty_pl.payload); |
| 2687 | 2662 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| ... | ... | @@ -2690,7 +2665,7 @@ pub const DeclGen = struct { |
| 2690 | 2665 | try self.beginSpvBlock(label_id); |
| 2691 | 2666 | |
| 2692 | 2667 | // If this block didn't produce a value, simply return here. |
| 2693 | if (!ty.hasRuntimeBitsIgnoreComptime()) | |
| 2668 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 2694 | 2669 | return null; |
| 2695 | 2670 | |
| 2696 | 2671 | // Combine the result from the blocks using the Phi instruction. |
| ... | ... | @@ -2714,9 +2689,10 @@ pub const DeclGen = struct { |
| 2714 | 2689 | fn airBr(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2715 | 2690 | const br = self.air.instructions.items(.data)[inst].br; |
| 2716 | 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 | 2696 | const operand_id = try self.resolve(br.operand); |
| 2721 | 2697 | // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body. |
| 2722 | 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 | 2729 | |
| 2754 | 2730 | fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2755 | 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 | 2736 | try self.func.body.emit(self.spv.gpa, .OpLine, .{ |
| 2758 | 2737 | .file = src_fname_id, |
| 2759 | 2738 | .line = dbg_stmt.line, |
| ... | ... | @@ -2762,22 +2741,24 @@ pub const DeclGen = struct { |
| 2762 | 2741 | } |
| 2763 | 2742 | |
| 2764 | 2743 | fn airLoad(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2744 | const mod = self.module; | |
| 2765 | 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 | 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 | 2750 | return try self.load(ptr_ty, operand); |
| 2771 | 2751 | } |
| 2772 | 2752 | |
| 2773 | 2753 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2754 | const mod = self.module; | |
| 2774 | 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 | 2757 | const ptr = try self.resolve(bin_op.lhs); |
| 2777 | 2758 | const value = try self.resolve(bin_op.rhs); |
| 2778 | 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 | 2762 | if (val_is_undef) { |
| 2782 | 2763 | const undef = try self.spv.constUndef(ptr_ty_ref); |
| 2783 | 2764 | try self.store(ptr_ty, ptr, undef); |
| ... | ... | @@ -2804,8 +2785,9 @@ pub const DeclGen = struct { |
| 2804 | 2785 | |
| 2805 | 2786 | fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2806 | 2787 | const operand = self.air.instructions.items(.data)[inst].un_op; |
| 2807 | const operand_ty = self.air.typeOf(operand); | |
| 2808 | if (operand_ty.hasRuntimeBits()) { | |
| 2788 | const operand_ty = self.typeOf(operand); | |
| 2789 | const mod = self.module; | |
| 2790 | if (operand_ty.hasRuntimeBits(mod)) { | |
| 2809 | 2791 | const operand_id = try self.resolve(operand); |
| 2810 | 2792 | try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = operand_id }); |
| 2811 | 2793 | } else { |
| ... | ... | @@ -2814,11 +2796,12 @@ pub const DeclGen = struct { |
| 2814 | 2796 | } |
| 2815 | 2797 | |
| 2816 | 2798 | fn airRetLoad(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2799 | const mod = self.module; | |
| 2817 | 2800 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2818 | const ptr_ty = self.air.typeOf(un_op); | |
| 2819 | const ret_ty = ptr_ty.childType(); | |
| 2801 | const ptr_ty = self.typeOf(un_op); | |
| 2802 | const ret_ty = ptr_ty.childType(mod); | |
| 2820 | 2803 | |
| 2821 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | |
| 2804 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 2822 | 2805 | try self.func.body.emit(self.spv.gpa, .OpReturn, {}); |
| 2823 | 2806 | return; |
| 2824 | 2807 | } |
| ... | ... | @@ -2831,20 +2814,21 @@ pub const DeclGen = struct { |
| 2831 | 2814 | } |
| 2832 | 2815 | |
| 2833 | 2816 | fn airTry(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2817 | const mod = self.module; | |
| 2834 | 2818 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2835 | 2819 | const err_union_id = try self.resolve(pl_op.operand); |
| 2836 | 2820 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 2837 | 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); | |
| 2840 | const payload_ty = self.air.typeOfIndex(inst); | |
| 2823 | const err_union_ty = self.typeOf(pl_op.operand); | |
| 2824 | const payload_ty = self.typeOfIndex(inst); | |
| 2841 | 2825 | |
| 2842 | 2826 | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 2843 | 2827 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 2844 | 2828 | |
| 2845 | 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 | 2832 | const err_id = if (eu_layout.payload_has_bits) |
| 2849 | 2833 | try self.extractField(Type.anyerror, err_union_id, eu_layout.errorFieldIndex()) |
| 2850 | 2834 | else |
| ... | ... | @@ -2892,17 +2876,18 @@ pub const DeclGen = struct { |
| 2892 | 2876 | fn airErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2893 | 2877 | if (self.liveness.isUnused(inst)) return null; |
| 2894 | 2878 | |
| 2879 | const mod = self.module; | |
| 2895 | 2880 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2896 | 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 | 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 | 2886 | // No error possible, so just return undefined. |
| 2902 | 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 | 2891 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 2907 | 2892 | |
| 2908 | 2893 | if (!eu_layout.payload_has_bits) { |
| ... | ... | @@ -2916,9 +2901,10 @@ pub const DeclGen = struct { |
| 2916 | 2901 | fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2917 | 2902 | if (self.liveness.isUnused(inst)) return null; |
| 2918 | 2903 | |
| 2904 | const mod = self.module; | |
| 2919 | 2905 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2920 | const err_union_ty = self.air.typeOfIndex(inst); | |
| 2921 | const payload_ty = err_union_ty.errorUnionPayload(); | |
| 2906 | const err_union_ty = self.typeOfIndex(inst); | |
| 2907 | const payload_ty = err_union_ty.errorUnionPayload(mod); | |
| 2922 | 2908 | const operand_id = try self.resolve(ty_op.operand); |
| 2923 | 2909 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 2924 | 2910 | |
| ... | ... | @@ -2946,25 +2932,24 @@ pub const DeclGen = struct { |
| 2946 | 2932 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { |
| 2947 | 2933 | if (self.liveness.isUnused(inst)) return null; |
| 2948 | 2934 | |
| 2935 | const mod = self.module; | |
| 2949 | 2936 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2950 | 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; | |
| 2954 | const payload_ty = optional_ty.optionalChild(&buf); | |
| 2940 | const payload_ty = optional_ty.optionalChild(mod); | |
| 2955 | 2941 | |
| 2956 | 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 | 2945 | // Pointer payload represents nullability: pointer or slice. |
| 2960 | 2946 | |
| 2961 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 2962 | const ptr_ty = if (payload_ty.isSlice()) | |
| 2963 | payload_ty.slicePtrFieldType(&ptr_buf) | |
| 2947 | const ptr_ty = if (payload_ty.isSlice(mod)) | |
| 2948 | payload_ty.slicePtrFieldType(mod) | |
| 2964 | 2949 | else |
| 2965 | 2950 | payload_ty; |
| 2966 | 2951 | |
| 2967 | const ptr_id = if (payload_ty.isSlice()) | |
| 2952 | const ptr_id = if (payload_ty.isSlice(mod)) | |
| 2968 | 2953 | try self.extractField(Type.bool, operand_id, 0) |
| 2969 | 2954 | else |
| 2970 | 2955 | operand_id; |
| ... | ... | @@ -2985,7 +2970,7 @@ pub const DeclGen = struct { |
| 2985 | 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 | 2974 | try self.extractField(Type.bool, operand_id, 1) |
| 2990 | 2975 | else |
| 2991 | 2976 | // Optional representation is bool indicating whether the optional is set |
| ... | ... | @@ -3009,14 +2994,15 @@ pub const DeclGen = struct { |
| 3009 | 2994 | fn airUnwrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3010 | 2995 | if (self.liveness.isUnused(inst)) return null; |
| 3011 | 2996 | |
| 2997 | const mod = self.module; | |
| 3012 | 2998 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3013 | 2999 | const operand_id = try self.resolve(ty_op.operand); |
| 3014 | const optional_ty = self.air.typeOf(ty_op.operand); | |
| 3015 | const payload_ty = self.air.typeOfIndex(inst); | |
| 3000 | const optional_ty = self.typeOf(ty_op.operand); | |
| 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 | 3006 | return operand_id; |
| 3021 | 3007 | } |
| 3022 | 3008 | |
| ... | ... | @@ -3026,16 +3012,17 @@ pub const DeclGen = struct { |
| 3026 | 3012 | fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3027 | 3013 | if (self.liveness.isUnused(inst)) return null; |
| 3028 | 3014 | |
| 3015 | const mod = self.module; | |
| 3029 | 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 | 3020 | return try self.constBool(true, .direct); |
| 3034 | 3021 | } |
| 3035 | 3022 | |
| 3036 | 3023 | const operand_id = try self.resolve(ty_op.operand); |
| 3037 | const optional_ty = self.air.typeOfIndex(inst); | |
| 3038 | if (optional_ty.optionalReprIsPayload()) { | |
| 3024 | const optional_ty = self.typeOfIndex(inst); | |
| 3025 | if (optional_ty.optionalReprIsPayload(mod)) { | |
| 3039 | 3026 | return operand_id; |
| 3040 | 3027 | } |
| 3041 | 3028 | |
| ... | ... | @@ -3045,30 +3032,29 @@ pub const DeclGen = struct { |
| 3045 | 3032 | } |
| 3046 | 3033 | |
| 3047 | 3034 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 3048 | const target = self.getTarget(); | |
| 3035 | const mod = self.module; | |
| 3049 | 3036 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3050 | 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 | 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 | 3042 | .Int => blk: { |
| 3056 | const bits = cond_ty.intInfo(target).bits; | |
| 3043 | const bits = cond_ty.intInfo(mod).bits; | |
| 3057 | 3044 | const backing_bits = self.backingIntBits(bits) orelse { |
| 3058 | 3045 | return self.todo("implement composite int switch", .{}); |
| 3059 | 3046 | }; |
| 3060 | 3047 | break :blk if (backing_bits <= 32) @as(u32, 1) else 2; |
| 3061 | 3048 | }, |
| 3062 | 3049 | .Enum => blk: { |
| 3063 | var buffer: Type.Payload.Bits = undefined; | |
| 3064 | const int_ty = cond_ty.intTagType(&buffer); | |
| 3065 | const int_info = int_ty.intInfo(target); | |
| 3050 | const int_ty = cond_ty.intTagType(mod); | |
| 3051 | const int_info = int_ty.intInfo(mod); | |
| 3066 | 3052 | const backing_bits = self.backingIntBits(int_info.bits) orelse { |
| 3067 | 3053 | return self.todo("implement composite int switch", .{}); |
| 3068 | 3054 | }; |
| 3069 | 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 | 3060 | const num_cases = switch_br.data.cases_len; |
| ... | ... | @@ -3112,15 +3098,14 @@ pub const DeclGen = struct { |
| 3112 | 3098 | const label = IdRef{ .id = first_case_label.id + case_i }; |
| 3113 | 3099 | |
| 3114 | 3100 | for (items) |item| { |
| 3115 | const value = self.air.value(item) orelse { | |
| 3101 | const value = (try self.air.value(item, mod)) orelse { | |
| 3116 | 3102 | return self.todo("switch on runtime value???", .{}); |
| 3117 | 3103 | }; |
| 3118 | const int_val = switch (cond_ty.zigTypeTag()) { | |
| 3119 | .Int => if (cond_ty.isSignedInt()) @bitCast(u64, value.toSignedInt(target)) else value.toUnsignedInt(target), | |
| 3104 | const int_val = switch (cond_ty.zigTypeTag(mod)) { | |
| 3105 | .Int => if (cond_ty.isSignedInt(mod)) @bitCast(u64, value.toSignedInt(mod)) else value.toUnsignedInt(mod), | |
| 3120 | 3106 | .Enum => blk: { |
| 3121 | var int_buffer: Value.Payload.U64 = undefined; | |
| 3122 | 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 | 3110 | else => unreachable, |
| 3126 | 3111 | }; |
| ... | ... | @@ -3164,6 +3149,7 @@ pub const DeclGen = struct { |
| 3164 | 3149 | } |
| 3165 | 3150 | |
| 3166 | 3151 | fn airAssembly(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3152 | const mod = self.module; | |
| 3167 | 3153 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3168 | 3154 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); |
| 3169 | 3155 | |
| ... | ... | @@ -3246,7 +3232,7 @@ pub const DeclGen = struct { |
| 3246 | 3232 | assert(as.errors.items.len != 0); |
| 3247 | 3233 | assert(self.error_msg == null); |
| 3248 | 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 | 3236 | self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{}); |
| 3251 | 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 | 3280 | fn airCall(self: *DeclGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !?IdRef { |
| 3295 | 3281 | _ = modifier; |
| 3296 | 3282 | |
| 3283 | const mod = self.module; | |
| 3297 | 3284 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3298 | 3285 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 3299 | 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); | |
| 3301 | const zig_fn_ty = switch (callee_ty.zigTypeTag()) { | |
| 3287 | const callee_ty = self.typeOf(pl_op.operand); | |
| 3288 | const zig_fn_ty = switch (callee_ty.zigTypeTag(mod)) { | |
| 3302 | 3289 | .Fn => callee_ty, |
| 3303 | 3290 | .Pointer => return self.fail("cannot call function pointers", .{}), |
| 3304 | 3291 | else => unreachable, |
| 3305 | 3292 | }; |
| 3306 | const fn_info = zig_fn_ty.fnInfo(); | |
| 3293 | const fn_info = mod.typeToFunc(zig_fn_ty).?; | |
| 3307 | 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 | 3297 | const result_id = self.spv.allocId(); |
| 3311 | 3298 | const callee_id = try self.resolve(pl_op.operand); |
| 3312 | 3299 | |
| ... | ... | @@ -3319,8 +3306,8 @@ pub const DeclGen = struct { |
| 3319 | 3306 | // before starting to emit OpFunctionCall instructions. Hence the |
| 3320 | 3307 | // temporary params buffer. |
| 3321 | 3308 | const arg_id = try self.resolve(arg); |
| 3322 | const arg_ty = self.air.typeOf(arg); | |
| 3323 | if (!arg_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 3309 | const arg_ty = self.typeOf(arg); | |
| 3310 | if (!arg_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3324 | 3311 | |
| 3325 | 3312 | params[n_params] = arg_id; |
| 3326 | 3313 | n_params += 1; |
| ... | ... | @@ -3333,14 +3320,24 @@ pub const DeclGen = struct { |
| 3333 | 3320 | .id_ref_3 = params[0..n_params], |
| 3334 | 3321 | }); |
| 3335 | 3322 | |
| 3336 | if (return_type.isNoReturn()) { | |
| 3323 | if (return_type == .noreturn_type) { | |
| 3337 | 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 | 3328 | return null; |
| 3342 | 3329 | } |
| 3343 | 3330 | |
| 3344 | 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 | 11 | const Allocator = std.mem.Allocator; |
| 12 | 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 | 17 | const spec = @import("spec.zig"); |
| 17 | 18 | const Word = spec.Word; |
| ... | ... | @@ -389,8 +390,8 @@ pub fn addFunction(self: *Module, decl_index: Decl.Index, func: Fn) !void { |
| 389 | 390 | /// Fetch the result-id of an OpString instruction that encodes the path of the source |
| 390 | 391 | /// file of the decl. This function may also emit an OpSource with source-level information regarding |
| 391 | 392 | /// the decl. |
| 392 | pub fn resolveSourceFileName(self: *Module, decl: *ZigDecl) !IdRef { | |
| 393 | const path = decl.getFileScope().sub_file_path; | |
| 393 | pub fn resolveSourceFileName(self: *Module, zig_module: *ZigModule, zig_decl: *ZigDecl) !IdRef { | |
| 394 | const path = zig_decl.getFileScope(zig_module).sub_file_path; | |
| 394 | 395 | const result = try self.source_file_names.getOrPut(self.gpa, path); |
| 395 | 396 | if (!result.found_existing) { |
| 396 | 397 | const file_result_id = self.allocId(); |
src/crash_report.zig+4-4| ... | ... | @@ -99,7 +99,7 @@ fn dumpStatusReport() !void { |
| 99 | 99 | allocator, |
| 100 | 100 | anal.body, |
| 101 | 101 | anal.body_index, |
| 102 | block.namespace.file_scope, | |
| 102 | mod.namespacePtr(block.namespace).file_scope, | |
| 103 | 103 | block_src_decl.src_node, |
| 104 | 104 | 6, // indent |
| 105 | 105 | stderr, |
| ... | ... | @@ -108,7 +108,7 @@ fn dumpStatusReport() !void { |
| 108 | 108 | else => |e| return e, |
| 109 | 109 | }; |
| 110 | 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 | 112 | try stderr.writeAll("\n\n"); |
| 113 | 113 | |
| 114 | 114 | var parent = anal.parent; |
| ... | ... | @@ -121,7 +121,7 @@ fn dumpStatusReport() !void { |
| 121 | 121 | print_zir.renderSingleInstruction( |
| 122 | 122 | allocator, |
| 123 | 123 | curr.body[curr.body_index], |
| 124 | curr.block.namespace.file_scope, | |
| 124 | mod.namespacePtr(curr.block.namespace).file_scope, | |
| 125 | 125 | curr_block_src_decl.src_node, |
| 126 | 126 | 6, // indent |
| 127 | 127 | stderr, |
| ... | ... | @@ -148,7 +148,7 @@ fn writeFilePath(file: *Module.File, stream: anytype) !void { |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | fn writeFullyQualifiedDeclWithFile(mod: *Module, decl: *Decl, stream: anytype) !void { |
| 151 | try writeFilePath(decl.getFileScope(), stream); | |
| 151 | try writeFilePath(decl.getFileScope(mod), stream); | |
| 152 | 152 | try stream.writeAll(": "); |
| 153 | 153 | try decl.renderFullyQualifiedDebugName(mod, stream); |
| 154 | 154 | } |
src/link.zig+13-24| ... | ... | @@ -502,8 +502,6 @@ pub const File = struct { |
| 502 | 502 | /// of the final binary. |
| 503 | 503 | pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: Module.Decl.Index) UpdateDeclError!u32 { |
| 504 | 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 | 505 | switch (base.tag) { |
| 508 | 506 | // zig fmt: off |
| 509 | 507 | .coff => return @fieldParentPtr(Coff, "base", base).lowerUnnamedConst(tv, decl_index), |
| ... | ... | @@ -543,7 +541,6 @@ pub const File = struct { |
| 543 | 541 | /// May be called before or after updateDeclExports for any given Decl. |
| 544 | 542 | pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { |
| 545 | 543 | const decl = module.declPtr(decl_index); |
| 546 | log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmt(module) }); | |
| 547 | 544 | assert(decl.has_tv); |
| 548 | 545 | if (build_options.only_c) { |
| 549 | 546 | assert(base.tag == .c); |
| ... | ... | @@ -564,34 +561,27 @@ pub const File = struct { |
| 564 | 561 | } |
| 565 | 562 | |
| 566 | 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 { | |
| 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 | }); | |
| 564 | pub fn updateFunc(base: *File, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) UpdateDeclError!void { | |
| 572 | 565 | if (build_options.only_c) { |
| 573 | 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 | 569 | switch (base.tag) { |
| 577 | 570 | // zig fmt: off |
| 578 | .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func, air, liveness), | |
| 579 | .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func, air, liveness), | |
| 580 | .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func, air, liveness), | |
| 581 | .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness), | |
| 582 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness), | |
| 583 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness), | |
| 584 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness), | |
| 585 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func, air, liveness), | |
| 571 | .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func_index, air, liveness), | |
| 572 | .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func_index, air, liveness), | |
| 573 | .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func_index, air, liveness), | |
| 574 | .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness), | |
| 575 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func_index, air, liveness), | |
| 576 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func_index, air, liveness), | |
| 577 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func_index, air, liveness), | |
| 578 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func_index, air, liveness), | |
| 586 | 579 | // zig fmt: on |
| 587 | 580 | } |
| 588 | 581 | } |
| 589 | 582 | |
| 590 | 583 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { |
| 591 | 584 | const decl = module.declPtr(decl_index); |
| 592 | log.debug("updateDeclLineNumber {*} ({s}), line={}", .{ | |
| 593 | decl, decl.name, decl.src_line + 1, | |
| 594 | }); | |
| 595 | 585 | assert(decl.has_tv); |
| 596 | 586 | if (build_options.only_c) { |
| 597 | 587 | assert(base.tag == .c); |
| ... | ... | @@ -867,7 +857,6 @@ pub const File = struct { |
| 867 | 857 | exports: []const *Module.Export, |
| 868 | 858 | ) UpdateDeclExportsError!void { |
| 869 | 859 | const decl = module.declPtr(decl_index); |
| 870 | log.debug("updateDeclExports {*} ({s})", .{ decl, decl.name }); | |
| 871 | 860 | assert(decl.has_tv); |
| 872 | 861 | if (build_options.only_c) { |
| 873 | 862 | assert(base.tag == .c); |
| ... | ... | @@ -1124,13 +1113,13 @@ pub const File = struct { |
| 1124 | 1113 | |
| 1125 | 1114 | pub fn initDecl(kind: Kind, decl: ?Module.Decl.Index, mod: *Module) LazySymbol { |
| 1126 | 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 | 1117 | else |
| 1129 | 1118 | Type.anyerror }; |
| 1130 | 1119 | } |
| 1131 | 1120 | |
| 1132 | pub fn getDecl(self: LazySymbol) Module.Decl.OptionalIndex { | |
| 1133 | return Module.Decl.OptionalIndex.init(self.ty.getOwnerDeclOrNull()); | |
| 1121 | pub fn getDecl(self: LazySymbol, mod: *Module) Module.Decl.OptionalIndex { | |
| 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 | |
| 7 | 7 | const C = @This(); |
| 8 | 8 | const Module = @import("../Module.zig"); |
| 9 | const InternPool = @import("../InternPool.zig"); | |
| 9 | 10 | const Compilation = @import("../Compilation.zig"); |
| 10 | 11 | const codegen = @import("../codegen/c.zig"); |
| 11 | 12 | const link = @import("../link.zig"); |
| ... | ... | @@ -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 | 92 | const tracy = trace(@src()); |
| 92 | 93 | defer tracy.end(); |
| 93 | 94 | |
| 94 | 95 | const gpa = self.base.allocator; |
| 95 | 96 | |
| 97 | const func = module.funcPtr(func_index); | |
| 96 | 98 | const decl_index = func.owner_decl; |
| 97 | 99 | const gop = try self.decl_table.getOrPut(gpa, decl_index); |
| 98 | 100 | if (!gop.found_existing) { |
| ... | ... | @@ -111,7 +113,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes |
| 111 | 113 | .value_map = codegen.CValueMap.init(gpa), |
| 112 | 114 | .air = air, |
| 113 | 115 | .liveness = liveness, |
| 114 | .func = func, | |
| 116 | .func_index = func_index, | |
| 115 | 117 | .object = .{ |
| 116 | 118 | .dg = .{ |
| 117 | 119 | .gpa = gpa, |
| ... | ... | @@ -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 | 294 | defer export_names.deinit(gpa); |
| 293 | 295 | try export_names.ensureTotalCapacity(gpa, @intCast(u32, module.decl_exports.entries.len)); |
| 294 | 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 | 299 | while (f.remaining_decls.popOrNull()) |kv| { |
| 298 | 300 | const decl_index = kv.key; |
| ... | ... | @@ -552,10 +554,11 @@ fn flushDecl( |
| 552 | 554 | self: *C, |
| 553 | 555 | f: *Flush, |
| 554 | 556 | decl_index: Module.Decl.Index, |
| 555 | export_names: std.StringHashMapUnmanaged(void), | |
| 557 | export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void), | |
| 556 | 558 | ) FlushDeclError!void { |
| 557 | 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 | 562 | // Before flushing any particular Decl we must ensure its |
| 560 | 563 | // dependencies are already flushed, so that the order in the .c |
| 561 | 564 | // file comes out correctly. |
| ... | ... | @@ -569,7 +572,7 @@ fn flushDecl( |
| 569 | 572 | |
| 570 | 573 | try self.flushLazyFns(f, decl_block.lazy_fns); |
| 571 | 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 | 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 | 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 | 1036 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1037 | 1037 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1038 | 1038 | } |
| 1039 | 1039 | if (build_options.have_llvm) { |
| 1040 | 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 | 1044 | const tracy = trace(@src()); |
| 1045 | 1045 | defer tracy.end(); |
| 1046 | 1046 | |
| 1047 | const func = mod.funcPtr(func_index); | |
| 1047 | 1048 | const decl_index = func.owner_decl; |
| 1048 | const decl = module.declPtr(decl_index); | |
| 1049 | const decl = mod.declPtr(decl_index); | |
| 1049 | 1050 | |
| 1050 | 1051 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 1051 | 1052 | self.freeUnnamedConsts(decl_index); |
| ... | ... | @@ -1056,8 +1057,8 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 1056 | 1057 | |
| 1057 | 1058 | const res = try codegen.generateFunction( |
| 1058 | 1059 | &self.base, |
| 1059 | decl.srcLoc(), | |
| 1060 | func, | |
| 1060 | decl.srcLoc(mod), | |
| 1061 | func_index, | |
| 1061 | 1062 | air, |
| 1062 | 1063 | liveness, |
| 1063 | 1064 | &code_buffer, |
| ... | ... | @@ -1067,7 +1068,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 1067 | 1068 | .ok => code_buffer.items, |
| 1068 | 1069 | .fail => |em| { |
| 1069 | 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 | 1072 | return; |
| 1072 | 1073 | }, |
| 1073 | 1074 | }; |
| ... | ... | @@ -1076,7 +1077,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 1076 | 1077 | |
| 1077 | 1078 | // Since we updated the vaddr and the size, each corresponding export |
| 1078 | 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 | 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 | 1097 | const atom_index = try self.createAtom(); |
| 1097 | 1098 | |
| 1098 | 1099 | const sym_name = blk: { |
| 1099 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 1100 | defer gpa.free(decl_name); | |
| 1100 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 1101 | 1101 | |
| 1102 | 1102 | const index = unnamed_consts.items.len; |
| 1103 | 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 | 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 | 1114 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| 1115 | 1115 | }); |
| 1116 | 1116 | var code = switch (res) { |
| ... | ... | @@ -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 | 1127 | const atom = self.getAtomPtr(atom_index); |
| 1128 | 1128 | atom.size = @intCast(u32, code.len); |
| 1129 | 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 | 1141 | |
| 1142 | 1142 | pub fn updateDecl( |
| 1143 | 1143 | self: *Coff, |
| 1144 | module: *Module, | |
| 1144 | mod: *Module, | |
| 1145 | 1145 | decl_index: Module.Decl.Index, |
| 1146 | 1146 | ) link.File.UpdateDeclError!void { |
| 1147 | 1147 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1148 | 1148 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1149 | 1149 | } |
| 1150 | 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 | 1153 | const tracy = trace(@src()); |
| 1154 | 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 | 1159 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1160 | 1160 | } |
| 1161 | if (decl.val.castTag(.variable)) |payload| { | |
| 1162 | const variable = payload.data; | |
| 1161 | if (decl.val.getVariable(mod)) |variable| { | |
| 1163 | 1162 | if (variable.is_extern) { |
| 1164 | 1163 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1165 | 1164 | } |
| ... | ... | @@ -1172,8 +1171,8 @@ pub fn updateDecl( |
| 1172 | 1171 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 1173 | 1172 | defer code_buffer.deinit(); |
| 1174 | 1173 | |
| 1175 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | |
| 1176 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | |
| 1174 | const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val; | |
| 1175 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ | |
| 1177 | 1176 | .ty = decl.ty, |
| 1178 | 1177 | .val = decl_val, |
| 1179 | 1178 | }, &code_buffer, .none, .{ |
| ... | ... | @@ -1183,7 +1182,7 @@ pub fn updateDecl( |
| 1183 | 1182 | .ok => code_buffer.items, |
| 1184 | 1183 | .fail => |em| { |
| 1185 | 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 | 1186 | return; |
| 1188 | 1187 | }, |
| 1189 | 1188 | }; |
| ... | ... | @@ -1192,7 +1191,7 @@ pub fn updateDecl( |
| 1192 | 1191 | |
| 1193 | 1192 | // Since we updated the vaddr and the size, each corresponding export |
| 1194 | 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 | 1197 | fn updateLazySymbolAtom( |
| ... | ... | @@ -1217,8 +1216,8 @@ fn updateLazySymbolAtom( |
| 1217 | 1216 | const atom = self.getAtomPtr(atom_index); |
| 1218 | 1217 | const local_sym_index = atom.getSymbolIndex().?; |
| 1219 | 1218 | |
| 1220 | const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl| | |
| 1221 | mod.declPtr(owner_decl).srcLoc() | |
| 1219 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| | |
| 1220 | mod.declPtr(owner_decl).srcLoc(mod) | |
| 1222 | 1221 | else |
| 1223 | 1222 | Module.SrcLoc{ |
| 1224 | 1223 | .file_scope = undefined, |
| ... | ... | @@ -1262,7 +1261,8 @@ fn updateLazySymbolAtom( |
| 1262 | 1261 | } |
| 1263 | 1262 | |
| 1264 | 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 | 1266 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 1267 | 1267 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 1268 | 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 | 1277 | metadata.state.* = .pending_flush; |
| 1278 | 1278 | const atom = metadata.atom.*; |
| 1279 | 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 | 1281 | .code => self.text_section_index.?, |
| 1282 | 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 | 1299 | fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { |
| 1300 | 1300 | const decl = self.base.options.module.?.declPtr(decl_index); |
| 1301 | 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 | 1304 | const val = decl.val; |
| 1304 | 1305 | const index: u16 = blk: { |
| 1305 | if (val.isUndefDeep()) { | |
| 1306 | if (val.isUndefDeep(mod)) { | |
| 1306 | 1307 | // TODO in release-fast and release-small, we should put undef in .bss |
| 1307 | 1308 | break :blk self.data_section_index.?; |
| 1308 | 1309 | } |
| ... | ... | @@ -1311,7 +1312,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { |
| 1311 | 1312 | // TODO: what if this is a function pointer? |
| 1312 | 1313 | .Fn => break :blk self.text_section_index.?, |
| 1313 | 1314 | else => { |
| 1314 | if (val.castTag(.variable)) |_| { | |
| 1315 | if (val.getVariable(mod)) |_| { | |
| 1315 | 1316 | break :blk self.data_section_index.?; |
| 1316 | 1317 | } |
| 1317 | 1318 | break :blk self.rdata_section_index.?; |
| ... | ... | @@ -1322,15 +1323,13 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { |
| 1322 | 1323 | } |
| 1323 | 1324 | |
| 1324 | 1325 | fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, complex_type: coff.ComplexType) !void { |
| 1325 | const gpa = self.base.allocator; | |
| 1326 | 1326 | const mod = self.base.options.module.?; |
| 1327 | 1327 | const decl = mod.declPtr(decl_index); |
| 1328 | 1328 | |
| 1329 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 1330 | defer gpa.free(decl_name); | |
| 1329 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 1331 | 1330 | |
| 1332 | 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 | 1334 | const decl_metadata = self.decls.get(decl_index).?; |
| 1336 | 1335 | const atom_index = decl_metadata.atom; |
| ... | ... | @@ -1410,7 +1409,7 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { |
| 1410 | 1409 | |
| 1411 | 1410 | pub fn updateDeclExports( |
| 1412 | 1411 | self: *Coff, |
| 1413 | module: *Module, | |
| 1412 | mod: *Module, | |
| 1414 | 1413 | decl_index: Module.Decl.Index, |
| 1415 | 1414 | exports: []const *Module.Export, |
| 1416 | 1415 | ) link.File.UpdateDeclExportsError!void { |
| ... | ... | @@ -1418,61 +1417,60 @@ pub fn updateDeclExports( |
| 1418 | 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 | 1422 | if (build_options.have_llvm) { |
| 1422 | 1423 | // Even in the case of LLVM, we need to notice certain exported symbols in order to |
| 1423 | 1424 | // detect the default subsystem. |
| 1424 | 1425 | for (exports) |exp| { |
| 1425 | const exported_decl = module.declPtr(exp.exported_decl); | |
| 1426 | if (exported_decl.getFunction() == null) continue; | |
| 1426 | const exported_decl = mod.declPtr(exp.exported_decl); | |
| 1427 | if (exported_decl.getOwnedFunctionIndex(mod) == .none) continue; | |
| 1427 | 1428 | const winapi_cc = switch (self.base.options.target.cpu.arch) { |
| 1428 | 1429 | .x86 => std.builtin.CallingConvention.Stdcall, |
| 1429 | 1430 | else => std.builtin.CallingConvention.C, |
| 1430 | 1431 | }; |
| 1431 | const decl_cc = exported_decl.ty.fnCallingConvention(); | |
| 1432 | if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and | |
| 1432 | const decl_cc = exported_decl.ty.fnCallingConvention(mod); | |
| 1433 | if (decl_cc == .C and ip.stringEqlSlice(exp.opts.name, "main") and | |
| 1433 | 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 | 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 | module.stage1_flags.have_winmain = true; | |
| 1439 | } else if (mem.eql(u8, exp.options.name, "wWinMain")) { | |
| 1440 | module.stage1_flags.have_wwinmain = true; | |
| 1441 | } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) { | |
| 1442 | module.stage1_flags.have_winmain_crt_startup = true; | |
| 1443 | } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) { | |
| 1444 | module.stage1_flags.have_wwinmain_crt_startup = true; | |
| 1445 | } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) { | |
| 1446 | module.stage1_flags.have_dllmain_crt_startup = true; | |
| 1438 | if (ip.stringEqlSlice(exp.opts.name, "WinMain")) { | |
| 1439 | mod.stage1_flags.have_winmain = true; | |
| 1440 | } else if (ip.stringEqlSlice(exp.opts.name, "wWinMain")) { | |
| 1441 | mod.stage1_flags.have_wwinmain = true; | |
| 1442 | } else if (ip.stringEqlSlice(exp.opts.name, "WinMainCRTStartup")) { | |
| 1443 | mod.stage1_flags.have_winmain_crt_startup = true; | |
| 1444 | } else if (ip.stringEqlSlice(exp.opts.name, "wWinMainCRTStartup")) { | |
| 1445 | mod.stage1_flags.have_wwinmain_crt_startup = true; | |
| 1446 | } else if (ip.stringEqlSlice(exp.opts.name, "DllMainCRTStartup")) { | |
| 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 | 1455 | const gpa = self.base.allocator; |
| 1458 | 1456 | |
| 1459 | const decl = module.declPtr(decl_index); | |
| 1457 | const decl = mod.declPtr(decl_index); | |
| 1460 | 1458 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 1461 | 1459 | const atom = self.getAtom(atom_index); |
| 1462 | 1460 | const decl_sym = atom.getSymbol(self); |
| 1463 | 1461 | const decl_metadata = self.decls.getPtr(decl_index).?; |
| 1464 | 1462 | |
| 1465 | 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 | 1467 | if (!mem.eql(u8, section_name, ".text")) { |
| 1470 | try module.failed_exports.putNoClobber( | |
| 1471 | module.gpa, | |
| 1468 | try mod.failed_exports.putNoClobber( | |
| 1469 | gpa, | |
| 1472 | 1470 | exp, |
| 1473 | 1471 | try Module.ErrorMsg.create( |
| 1474 | 1472 | gpa, |
| 1475 | decl.srcLoc(), | |
| 1473 | decl.srcLoc(mod), | |
| 1476 | 1474 | "Unimplemented: ExportOptions.section", |
| 1477 | 1475 | .{}, |
| 1478 | 1476 | ), |
| ... | ... | @@ -1481,13 +1479,13 @@ pub fn updateDeclExports( |
| 1481 | 1479 | } |
| 1482 | 1480 | } |
| 1483 | 1481 | |
| 1484 | if (exp.options.linkage == .LinkOnce) { | |
| 1485 | try module.failed_exports.putNoClobber( | |
| 1486 | module.gpa, | |
| 1482 | if (exp.opts.linkage == .LinkOnce) { | |
| 1483 | try mod.failed_exports.putNoClobber( | |
| 1484 | gpa, | |
| 1487 | 1485 | exp, |
| 1488 | 1486 | try Module.ErrorMsg.create( |
| 1489 | 1487 | gpa, |
| 1490 | decl.srcLoc(), | |
| 1488 | decl.srcLoc(mod), | |
| 1491 | 1489 | "Unimplemented: GlobalLinkage.LinkOnce", |
| 1492 | 1490 | .{}, |
| 1493 | 1491 | ), |
| ... | ... | @@ -1495,19 +1493,19 @@ pub fn updateDeclExports( |
| 1495 | 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 | 1497 | const sym_index = try self.allocateSymbol(); |
| 1500 | 1498 | try decl_metadata.exports.append(gpa, sym_index); |
| 1501 | 1499 | break :blk sym_index; |
| 1502 | 1500 | }; |
| 1503 | 1501 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1504 | 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 | 1504 | sym.value = decl_sym.value; |
| 1507 | 1505 | sym.section_number = @intToEnum(coff.SectionNumber, self.text_section_index.? + 1); |
| 1508 | 1506 | sym.type = .{ .complex_type = .FUNCTION, .base_type = .NULL }; |
| 1509 | 1507 | |
| 1510 | switch (exp.options.linkage) { | |
| 1508 | switch (exp.opts.linkage) { | |
| 1511 | 1509 | .Strong => { |
| 1512 | 1510 | sym.storage_class = .EXTERNAL; |
| 1513 | 1511 | }, |
| ... | ... | @@ -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 | 1526 | if (self.llvm_object) |_| return; |
| 1525 | 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 | 1530 | const sym_index = metadata.getExportPtr(self, name) orelse return; |
| 1527 | 1531 | |
| 1528 | 1532 | const gpa = self.base.allocator; |
| ... | ... | @@ -2538,6 +2542,7 @@ const ImportTable = @import("Coff/ImportTable.zig"); |
| 2538 | 2542 | const Liveness = @import("../Liveness.zig"); |
| 2539 | 2543 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 2540 | 2544 | const Module = @import("../Module.zig"); |
| 2545 | const InternPool = @import("../InternPool.zig"); | |
| 2541 | 2546 | const Object = @import("Coff/Object.zig"); |
| 2542 | 2547 | const Relocation = @import("Coff/Relocation.zig"); |
| 2543 | 2548 | const TableSection = @import("table_section.zig").TableSection; |
src/link/Dwarf.zig+119-136| ... | ... | @@ -18,6 +18,7 @@ const LinkBlock = File.LinkBlock; |
| 18 | 18 | const LinkFn = File.LinkFn; |
| 19 | 19 | const LinkerLoad = @import("../codegen.zig").LinkerLoad; |
| 20 | 20 | const Module = @import("../Module.zig"); |
| 21 | const InternPool = @import("../InternPool.zig"); | |
| 21 | 22 | const StringTable = @import("strtab.zig").StringTable; |
| 22 | 23 | const Type = @import("../type.zig").Type; |
| 23 | 24 | const Value = @import("../value.zig").Value; |
| ... | ... | @@ -86,12 +87,7 @@ pub const DeclState = struct { |
| 86 | 87 | dbg_info: std.ArrayList(u8), |
| 87 | 88 | abbrev_type_arena: std.heap.ArenaAllocator, |
| 88 | 89 | abbrev_table: std.ArrayListUnmanaged(AbbrevEntry) = .{}, |
| 89 | abbrev_resolver: std.HashMapUnmanaged( | |
| 90 | Type, | |
| 91 | u32, | |
| 92 | Type.HashContext64, | |
| 93 | std.hash_map.default_max_load_percentage, | |
| 94 | ) = .{}, | |
| 90 | abbrev_resolver: std.AutoHashMapUnmanaged(InternPool.Index, u32) = .{}, | |
| 95 | 91 | abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, |
| 96 | 92 | exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{}, |
| 97 | 93 | |
| ... | ... | @@ -141,9 +137,7 @@ pub const DeclState = struct { |
| 141 | 137 | /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section |
| 142 | 138 | /// which we use as our target of the relocation. |
| 143 | 139 | fn addTypeRelocGlobal(self: *DeclState, atom_index: Atom.Index, ty: Type, offset: u32) !void { |
| 144 | const resolv = self.abbrev_resolver.getContext(ty, .{ | |
| 145 | .mod = self.mod, | |
| 146 | }) orelse blk: { | |
| 140 | const resolv = self.abbrev_resolver.get(ty.toIntern()) orelse blk: { | |
| 147 | 141 | const sym_index = @intCast(u32, self.abbrev_table.items.len); |
| 148 | 142 | try self.abbrev_table.append(self.gpa, .{ |
| 149 | 143 | .atom_index = atom_index, |
| ... | ... | @@ -151,12 +145,8 @@ pub const DeclState = struct { |
| 151 | 145 | .offset = undefined, |
| 152 | 146 | }); |
| 153 | 147 | log.debug("%{d}: {}", .{ sym_index, ty.fmt(self.mod) }); |
| 154 | try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{ | |
| 155 | .mod = self.mod, | |
| 156 | }); | |
| 157 | break :blk self.abbrev_resolver.getContext(ty, .{ | |
| 158 | .mod = self.mod, | |
| 159 | }).?; | |
| 148 | try self.abbrev_resolver.putNoClobber(self.gpa, ty.toIntern(), sym_index); | |
| 149 | break :blk sym_index; | |
| 160 | 150 | }; |
| 161 | 151 | log.debug("{x}: %{d} + 0", .{ offset, resolv }); |
| 162 | 152 | try self.abbrev_relocs.append(self.gpa, .{ |
| ... | ... | @@ -169,16 +159,16 @@ pub const DeclState = struct { |
| 169 | 159 | |
| 170 | 160 | fn addDbgInfoType( |
| 171 | 161 | self: *DeclState, |
| 172 | module: *Module, | |
| 162 | mod: *Module, | |
| 173 | 163 | atom_index: Atom.Index, |
| 174 | 164 | ty: Type, |
| 175 | 165 | ) error{OutOfMemory}!void { |
| 176 | 166 | const arena = self.abbrev_type_arena.allocator(); |
| 177 | 167 | const dbg_info_buffer = &self.dbg_info; |
| 178 | const target = module.getTarget(); | |
| 168 | const target = mod.getTarget(); | |
| 179 | 169 | const target_endian = target.cpu.arch.endian(); |
| 180 | 170 | |
| 181 | switch (ty.zigTypeTag()) { | |
| 171 | switch (ty.zigTypeTag(mod)) { | |
| 182 | 172 | .NoReturn => unreachable, |
| 183 | 173 | .Void => { |
| 184 | 174 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.pad1)); |
| ... | ... | @@ -189,12 +179,12 @@ pub const DeclState = struct { |
| 189 | 179 | // DW.AT.encoding, DW.FORM.data1 |
| 190 | 180 | dbg_info_buffer.appendAssumeCapacity(DW.ATE.boolean); |
| 191 | 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 | 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 | 186 | .Int => { |
| 197 | const info = ty.intInfo(target); | |
| 187 | const info = ty.intInfo(mod); | |
| 198 | 188 | try dbg_info_buffer.ensureUnusedCapacity(12); |
| 199 | 189 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.base_type)); |
| 200 | 190 | // DW.AT.encoding, DW.FORM.data1 |
| ... | ... | @@ -203,31 +193,30 @@ pub const DeclState = struct { |
| 203 | 193 | .unsigned => DW.ATE.unsigned, |
| 204 | 194 | }); |
| 205 | 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 | 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 | 200 | .Optional => { |
| 211 | if (ty.isPtrLikeOptional()) { | |
| 201 | if (ty.isPtrLikeOptional(mod)) { | |
| 212 | 202 | try dbg_info_buffer.ensureUnusedCapacity(12); |
| 213 | 203 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.base_type)); |
| 214 | 204 | // DW.AT.encoding, DW.FORM.data1 |
| 215 | 205 | dbg_info_buffer.appendAssumeCapacity(DW.ATE.address); |
| 216 | 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 | 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 | 210 | } else { |
| 221 | 211 | // Non-pointer optionals are structs: struct { .maybe = *, .val = * } |
| 222 | var buf = try arena.create(Type.Payload.ElemType); | |
| 223 | const payload_ty = ty.optionalChild(buf); | |
| 212 | const payload_ty = ty.optionalChild(mod); | |
| 224 | 213 | // DW.AT.structure_type |
| 225 | 214 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); |
| 226 | 215 | // DW.AT.byte_size, DW.FORM.udata |
| 227 | const abi_size = ty.abiSize(target); | |
| 216 | const abi_size = ty.abiSize(mod); | |
| 228 | 217 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); |
| 229 | 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 | 220 | // DW.AT.member |
| 232 | 221 | try dbg_info_buffer.ensureUnusedCapacity(7); |
| 233 | 222 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | ... | @@ -251,14 +240,14 @@ pub const DeclState = struct { |
| 251 | 240 | try dbg_info_buffer.resize(index + 4); |
| 252 | 241 | try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index)); |
| 253 | 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 | 244 | try leb128.writeULEB128(dbg_info_buffer.writer(), offset); |
| 256 | 245 | // DW.AT.structure_type delimit children |
| 257 | 246 | try dbg_info_buffer.append(0); |
| 258 | 247 | } |
| 259 | 248 | }, |
| 260 | 249 | .Pointer => { |
| 261 | if (ty.isSlice()) { | |
| 250 | if (ty.isSlice(mod)) { | |
| 262 | 251 | // Slices are structs: struct { .ptr = *, .len = N } |
| 263 | 252 | const ptr_bits = target.ptrBitWidth(); |
| 264 | 253 | const ptr_bytes = @intCast(u8, @divExact(ptr_bits, 8)); |
| ... | ... | @@ -266,9 +255,9 @@ pub const DeclState = struct { |
| 266 | 255 | try dbg_info_buffer.ensureUnusedCapacity(2); |
| 267 | 256 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_type)); |
| 268 | 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 | 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 | 261 | // DW.AT.member |
| 273 | 262 | try dbg_info_buffer.ensureUnusedCapacity(5); |
| 274 | 263 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | ... | @@ -278,8 +267,7 @@ pub const DeclState = struct { |
| 278 | 267 | // DW.AT.type, DW.FORM.ref4 |
| 279 | 268 | var index = dbg_info_buffer.items.len; |
| 280 | 269 | try dbg_info_buffer.resize(index + 4); |
| 281 | var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); | |
| 282 | const ptr_ty = ty.slicePtrFieldType(buf); | |
| 270 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 283 | 271 | try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(u32, index)); |
| 284 | 272 | // DW.AT.data_member_location, DW.FORM.udata |
| 285 | 273 | try dbg_info_buffer.ensureUnusedCapacity(6); |
| ... | ... | @@ -304,18 +292,18 @@ pub const DeclState = struct { |
| 304 | 292 | // DW.AT.type, DW.FORM.ref4 |
| 305 | 293 | const index = dbg_info_buffer.items.len; |
| 306 | 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 | 298 | .Array => { |
| 311 | 299 | // DW.AT.array_type |
| 312 | 300 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_type)); |
| 313 | 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 | 303 | // DW.AT.type, DW.FORM.ref4 |
| 316 | 304 | var index = dbg_info_buffer.items.len; |
| 317 | 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 | 307 | // DW.AT.subrange_type |
| 320 | 308 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim)); |
| 321 | 309 | // DW.AT.type, DW.FORM.ref4 |
| ... | ... | @@ -323,7 +311,7 @@ pub const DeclState = struct { |
| 323 | 311 | try dbg_info_buffer.resize(index + 4); |
| 324 | 312 | try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index)); |
| 325 | 313 | // DW.AT.count, DW.FORM.udata |
| 326 | const len = ty.arrayLenIncludingSentinel(); | |
| 314 | const len = ty.arrayLenIncludingSentinel(mod); | |
| 327 | 315 | try leb128.writeULEB128(dbg_info_buffer.writer(), len); |
| 328 | 316 | // DW.AT.array_type delimit children |
| 329 | 317 | try dbg_info_buffer.append(0); |
| ... | ... | @@ -332,15 +320,14 @@ pub const DeclState = struct { |
| 332 | 320 | // DW.AT.structure_type |
| 333 | 321 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); |
| 334 | 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()) { | |
| 338 | .tuple, .anon_struct => { | |
| 325 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 326 | .anon_struct_type => |fields| { | |
| 339 | 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(); | |
| 343 | for (fields.types, 0..) |field, field_index| { | |
| 330 | for (fields.types, 0..) |field_ty, field_index| { | |
| 344 | 331 | // DW.AT.member |
| 345 | 332 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); |
| 346 | 333 | // DW.AT.name, DW.FORM.string |
| ... | ... | @@ -348,29 +335,32 @@ pub const DeclState = struct { |
| 348 | 335 | // DW.AT.type, DW.FORM.ref4 |
| 349 | 336 | var index = dbg_info_buffer.items.len; |
| 350 | 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 | 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 | 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 | 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 | 348 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); |
| 361 | 349 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); |
| 362 | 350 | dbg_info_buffer.appendAssumeCapacity(0); |
| 363 | 351 | |
| 364 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 365 | 352 | if (struct_obj.layout == .Packed) { |
| 366 | 353 | log.debug("TODO implement .debug_info for packed structs", .{}); |
| 367 | 354 | break :blk; |
| 368 | 355 | } |
| 369 | 356 | |
| 370 | const fields = ty.structFields(); | |
| 371 | for (fields.keys(), 0..) |field_name, field_index| { | |
| 372 | const field = fields.get(field_name).?; | |
| 373 | if (!field.ty.hasRuntimeBits()) continue; | |
| 357 | for ( | |
| 358 | struct_obj.fields.keys(), | |
| 359 | struct_obj.fields.values(), | |
| 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 | 364 | // DW.AT.member |
| 375 | 365 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); |
| 376 | 366 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | ... | @@ -382,10 +372,11 @@ pub const DeclState = struct { |
| 382 | 372 | try dbg_info_buffer.resize(index + 4); |
| 383 | 373 | try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index)); |
| 384 | 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 | 376 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 387 | 377 | } |
| 388 | 378 | }, |
| 379 | else => unreachable, | |
| 389 | 380 | } |
| 390 | 381 | |
| 391 | 382 | // DW.AT.structure_type delimit children |
| ... | ... | @@ -395,21 +386,16 @@ pub const DeclState = struct { |
| 395 | 386 | // DW.AT.enumeration_type |
| 396 | 387 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type)); |
| 397 | 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 | 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 | 392 | try dbg_info_buffer.ensureUnusedCapacity(enum_name.len + 1); |
| 402 | 393 | dbg_info_buffer.appendSliceAssumeCapacity(enum_name); |
| 403 | 394 | dbg_info_buffer.appendAssumeCapacity(0); |
| 404 | 395 | |
| 405 | const fields = ty.enumFields(); | |
| 406 | const values: ?Module.EnumFull.ValueMap = switch (ty.tag()) { | |
| 407 | .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values, | |
| 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| { | |
| 396 | const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type; | |
| 397 | for (enum_type.names, 0..) |field_name_index, field_i| { | |
| 398 | const field_name = mod.intern_pool.stringToSlice(field_name_index); | |
| 413 | 399 | // DW.AT.enumerator |
| 414 | 400 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64)); |
| 415 | 401 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant)); |
| ... | ... | @@ -417,15 +403,14 @@ pub const DeclState = struct { |
| 417 | 403 | dbg_info_buffer.appendSliceAssumeCapacity(field_name); |
| 418 | 404 | dbg_info_buffer.appendAssumeCapacity(0); |
| 419 | 405 | // DW.AT.const_value, DW.FORM.data8 |
| 420 | const value: u64 = if (values) |vals| value: { | |
| 421 | if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered | |
| 422 | const value = vals.keys()[field_i]; | |
| 406 | const value: u64 = value: { | |
| 407 | if (enum_type.values.len == 0) break :value field_i; // auto-numbered | |
| 408 | const value = enum_type.values[field_i]; | |
| 423 | 409 | // TODO do not assume a 64bit enum value - could be bigger. |
| 424 | 410 | // See https://github.com/ziglang/zig/issues/645 |
| 425 | var int_buffer: Value.Payload.U64 = undefined; | |
| 426 | const field_int_val = value.enumToInt(ty, &int_buffer); | |
| 427 | break :value @bitCast(u64, field_int_val.toSignedInt(target)); | |
| 428 | } else @intCast(u64, field_i); | |
| 411 | const field_int_val = try value.toValue().enumToInt(ty, mod); | |
| 412 | break :value @bitCast(u64, field_int_val.toSignedInt(mod)); | |
| 413 | }; | |
| 429 | 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 | 418 | try dbg_info_buffer.append(0); |
| 434 | 419 | }, |
| 435 | 420 | .Union => { |
| 436 | const layout = ty.unionGetLayout(target); | |
| 437 | const union_obj = ty.cast(Type.Payload.Union).?.data; | |
| 421 | const layout = ty.unionGetLayout(mod); | |
| 422 | const union_obj = mod.typeToUnion(ty).?; | |
| 438 | 423 | const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0; |
| 439 | 424 | const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size; |
| 440 | 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 | 428 | // TODO this is temporary to match current state of unions in Zig - we don't yet have |
| 444 | 429 | // safety checks implemented meaning the implicit tag is not yet stored and generated |
| ... | ... | @@ -478,14 +463,15 @@ pub const DeclState = struct { |
| 478 | 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 | 467 | for (fields.keys()) |field_name| { |
| 483 | 468 | const field = fields.get(field_name).?; |
| 484 | if (!field.ty.hasRuntimeBits()) continue; | |
| 469 | if (!field.ty.hasRuntimeBits(mod)) continue; | |
| 485 | 470 | // DW.AT.member |
| 486 | 471 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); |
| 487 | 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 | 475 | // DW.AT.type, DW.FORM.ref4 |
| 490 | 476 | const index = dbg_info_buffer.items.len; |
| 491 | 477 | try dbg_info_buffer.resize(index + 4); |
| ... | ... | @@ -517,30 +503,30 @@ pub const DeclState = struct { |
| 517 | 503 | .ErrorSet => { |
| 518 | 504 | try addDbgInfoErrorSet( |
| 519 | 505 | self.abbrev_type_arena.allocator(), |
| 520 | module, | |
| 506 | mod, | |
| 521 | 507 | ty, |
| 522 | 508 | target, |
| 523 | 509 | &self.dbg_info, |
| 524 | 510 | ); |
| 525 | 511 | }, |
| 526 | 512 | .ErrorUnion => { |
| 527 | const error_ty = ty.errorUnionSet(); | |
| 528 | const payload_ty = ty.errorUnionPayload(); | |
| 529 | const payload_align = if (payload_ty.isNoReturn()) 0 else payload_ty.abiAlignment(target); | |
| 530 | const error_align = Type.anyerror.abiAlignment(target); | |
| 531 | const abi_size = ty.abiSize(target); | |
| 532 | const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(target) else 0; | |
| 533 | const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(target); | |
| 513 | const error_ty = ty.errorUnionSet(mod); | |
| 514 | const payload_ty = ty.errorUnionPayload(mod); | |
| 515 | const payload_align = if (payload_ty.isNoReturn(mod)) 0 else payload_ty.abiAlignment(mod); | |
| 516 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 517 | const abi_size = ty.abiSize(mod); | |
| 518 | const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(mod) else 0; | |
| 519 | const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(mod); | |
| 534 | 520 | |
| 535 | 521 | // DW.AT.structure_type |
| 536 | 522 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); |
| 537 | 523 | // DW.AT.byte_size, DW.FORM.udata |
| 538 | 524 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); |
| 539 | 525 | // DW.AT.name, DW.FORM.string |
| 540 | const name = try ty.nameAllocArena(arena, module); | |
| 526 | const name = try ty.nameAllocArena(arena, mod); | |
| 541 | 527 | try dbg_info_buffer.writer().print("{s}\x00", .{name}); |
| 542 | 528 | |
| 543 | if (!payload_ty.isNoReturn()) { | |
| 529 | if (!payload_ty.isNoReturn(mod)) { | |
| 544 | 530 | // DW.AT.member |
| 545 | 531 | try dbg_info_buffer.ensureUnusedCapacity(7); |
| 546 | 532 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | ... | @@ -685,9 +671,10 @@ pub const DeclState = struct { |
| 685 | 671 | const atom_index = self.di_atom_decls.get(owner_decl).?; |
| 686 | 672 | const name_with_null = name.ptr[0 .. name.len + 1]; |
| 687 | 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 | 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 | 679 | switch (loc) { |
| 693 | 680 | .register => |reg| { |
| ... | ... | @@ -790,9 +777,9 @@ pub const DeclState = struct { |
| 790 | 777 | const fixup = dbg_info.items.len; |
| 791 | 778 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 792 | 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 | 783 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); |
| 797 | 784 | } else { |
| 798 | 785 | try leb128.writeULEB128(dbg_info.writer(), x); |
| ... | ... | @@ -805,7 +792,7 @@ pub const DeclState = struct { |
| 805 | 792 | // DW.AT.location, DW.FORM.exprloc |
| 806 | 793 | // uleb128(exprloc_len) |
| 807 | 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 | 796 | var implicit_value_len = std.ArrayList(u8).init(self.gpa); |
| 810 | 797 | defer implicit_value_len.deinit(); |
| 811 | 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 | 951 | defer tracy.end(); |
| 965 | 952 | |
| 966 | 953 | const decl = mod.declPtr(decl_index); |
| 967 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 968 | defer self.allocator.free(decl_name); | |
| 954 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 969 | 955 | |
| 970 | 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 | 965 | |
| 980 | 966 | assert(decl.has_tv); |
| 981 | 967 | |
| 982 | switch (decl.ty.zigTypeTag()) { | |
| 968 | switch (decl.ty.zigTypeTag(mod)) { | |
| 983 | 969 | .Fn => { |
| 984 | 970 | _ = try self.getOrCreateAtomForDecl(.src_fn, decl_index); |
| 985 | 971 | |
| 986 | 972 | // For functions we need to add a prologue to the debug line program. |
| 987 | 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 | 976 | log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ |
| 991 | 977 | decl.src_line, |
| 992 | 978 | func.lbrace_line, |
| ... | ... | @@ -1026,8 +1012,8 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 1026 | 1012 | const decl_name_with_null = decl_name[0 .. decl_name.len + 1]; |
| 1027 | 1013 | try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len); |
| 1028 | 1014 | |
| 1029 | const fn_ret_type = decl.ty.fnReturnType(); | |
| 1030 | const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(); | |
| 1015 | const fn_ret_type = decl.ty.fnReturnType(mod); | |
| 1016 | const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(mod); | |
| 1031 | 1017 | if (fn_ret_has_bits) { |
| 1032 | 1018 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.subprogram)); |
| 1033 | 1019 | } else { |
| ... | ... | @@ -1059,7 +1045,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 1059 | 1045 | |
| 1060 | 1046 | pub fn commitDeclState( |
| 1061 | 1047 | self: *Dwarf, |
| 1062 | module: *Module, | |
| 1048 | mod: *Module, | |
| 1063 | 1049 | decl_index: Module.Decl.Index, |
| 1064 | 1050 | sym_addr: u64, |
| 1065 | 1051 | sym_size: u64, |
| ... | ... | @@ -1071,12 +1057,12 @@ pub fn commitDeclState( |
| 1071 | 1057 | const gpa = self.allocator; |
| 1072 | 1058 | var dbg_line_buffer = &decl_state.dbg_line; |
| 1073 | 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 | 1062 | const target_endian = self.target.cpu.arch.endian(); |
| 1077 | 1063 | |
| 1078 | 1064 | assert(decl.has_tv); |
| 1079 | switch (decl.ty.zigTypeTag()) { | |
| 1065 | switch (decl.ty.zigTypeTag(mod)) { | |
| 1080 | 1066 | .Fn => { |
| 1081 | 1067 | // Since the Decl is a function, we need to update the .debug_line program. |
| 1082 | 1068 | // Perform the relocations based on vaddr. |
| ... | ... | @@ -1271,10 +1257,11 @@ pub fn commitDeclState( |
| 1271 | 1257 | const symbol = &decl_state.abbrev_table.items[sym_index]; |
| 1272 | 1258 | const ty = symbol.type; |
| 1273 | 1259 | const deferred: bool = blk: { |
| 1274 | if (ty.isAnyError()) break :blk true; | |
| 1275 | switch (ty.tag()) { | |
| 1276 | .error_set_inferred => { | |
| 1277 | if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; | |
| 1260 | if (ty.isAnyError(mod)) break :blk true; | |
| 1261 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 1262 | .inferred_error_set_type => |ies_index| { | |
| 1263 | const ies = mod.inferredErrorSetPtr(ies_index); | |
| 1264 | if (!ies.is_resolved) break :blk true; | |
| 1278 | 1265 | }, |
| 1279 | 1266 | else => {}, |
| 1280 | 1267 | } |
| ... | ... | @@ -1283,11 +1270,10 @@ pub fn commitDeclState( |
| 1283 | 1270 | if (deferred) continue; |
| 1284 | 1271 | |
| 1285 | 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 | 1277 | try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len)); |
| 1292 | 1278 | |
| 1293 | 1279 | while (decl_state.abbrev_relocs.popOrNull()) |reloc| { |
| ... | ... | @@ -1295,10 +1281,11 @@ pub fn commitDeclState( |
| 1295 | 1281 | const symbol = decl_state.abbrev_table.items[target]; |
| 1296 | 1282 | const ty = symbol.type; |
| 1297 | 1283 | const deferred: bool = blk: { |
| 1298 | if (ty.isAnyError()) break :blk true; | |
| 1299 | switch (ty.tag()) { | |
| 1300 | .error_set_inferred => { | |
| 1301 | if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; | |
| 1284 | if (ty.isAnyError(mod)) break :blk true; | |
| 1285 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 1286 | .inferred_error_set_type => |ies_index| { | |
| 1287 | const ies = mod.inferredErrorSetPtr(ies_index); | |
| 1288 | if (!ies.is_resolved) break :blk true; | |
| 1302 | 1289 | }, |
| 1303 | 1290 | else => {}, |
| 1304 | 1291 | } |
| ... | ... | @@ -1319,7 +1306,7 @@ pub fn commitDeclState( |
| 1319 | 1306 | reloc.offset, |
| 1320 | 1307 | value, |
| 1321 | 1308 | target, |
| 1322 | ty.fmt(module), | |
| 1309 | ty.fmt(mod), | |
| 1323 | 1310 | }); |
| 1324 | 1311 | mem.writeInt( |
| 1325 | 1312 | u32, |
| ... | ... | @@ -1358,7 +1345,6 @@ pub fn commitDeclState( |
| 1358 | 1345 | } |
| 1359 | 1346 | } |
| 1360 | 1347 | |
| 1361 | log.debug("writeDeclDebugInfo for '{s}", .{decl.name}); | |
| 1362 | 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 | 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 | 1517 | const tracy = trace(@src()); |
| 1532 | 1518 | defer tracy.end(); |
| 1533 | 1519 | |
| ... | ... | @@ -1535,8 +1521,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.De |
| 1535 | 1521 | const atom = self.getAtom(.src_fn, atom_index); |
| 1536 | 1522 | if (atom.len == 0) return; |
| 1537 | 1523 | |
| 1538 | const decl = module.declPtr(decl_index); | |
| 1539 | const func = decl.val.castTag(.function).?.data; | |
| 1524 | const decl = mod.declPtr(decl_index); | |
| 1525 | const func = decl.val.getFunction(mod).?; | |
| 1540 | 1526 | log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ |
| 1541 | 1527 | decl.src_line, |
| 1542 | 1528 | func.lbrace_line, |
| ... | ... | @@ -2534,18 +2520,14 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2534 | 2520 | defer arena_alloc.deinit(); |
| 2535 | 2521 | const arena = arena_alloc.allocator(); |
| 2536 | 2522 | |
| 2537 | const error_set = try arena.create(Module.ErrorSet); | |
| 2538 | const error_ty = try Type.Tag.error_set.create(arena, error_set); | |
| 2539 | var names = Module.ErrorSet.NameMap{}; | |
| 2540 | try names.ensureUnusedCapacity(arena, module.global_error_set.count()); | |
| 2541 | var it = module.global_error_set.keyIterator(); | |
| 2542 | while (it.next()) |key| { | |
| 2543 | names.putAssumeCapacityNoClobber(key.*, {}); | |
| 2544 | } | |
| 2545 | error_set.names = names; | |
| 2523 | // TODO: don't create a zig type for this, just make the dwarf info | |
| 2524 | // without touching the zig type system. | |
| 2525 | const names = try arena.dupe(InternPool.NullTerminatedString, module.global_error_set.keys()); | |
| 2526 | std.mem.sort(InternPool.NullTerminatedString, names, {}, InternPool.NullTerminatedString.indexLessThan); | |
| 2546 | 2527 | |
| 2528 | const error_ty = try module.intern(.{ .error_set_type = .{ .names = names } }); | |
| 2547 | 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 | 2532 | const di_atom_index = try self.createAtom(.di_atom); |
| 2551 | 2533 | log.debug("updateDeclDebugInfoAllocation in flushModule", .{}); |
| ... | ... | @@ -2598,7 +2580,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2598 | 2580 | |
| 2599 | 2581 | fn addDIFile(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !u28 { |
| 2600 | 2582 | const decl = mod.declPtr(decl_index); |
| 2601 | const file_scope = decl.getFileScope(); | |
| 2583 | const file_scope = decl.getFileScope(mod); | |
| 2602 | 2584 | const gop = try self.di_files.getOrPut(self.allocator, file_scope); |
| 2603 | 2585 | if (!gop.found_existing) { |
| 2604 | 2586 | switch (self.bin_file.tag) { |
| ... | ... | @@ -2663,7 +2645,7 @@ fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct { |
| 2663 | 2645 | |
| 2664 | 2646 | fn addDbgInfoErrorSet( |
| 2665 | 2647 | arena: Allocator, |
| 2666 | module: *Module, | |
| 2648 | mod: *Module, | |
| 2667 | 2649 | ty: Type, |
| 2668 | 2650 | target: std.Target, |
| 2669 | 2651 | dbg_info_buffer: *std.ArrayList(u8), |
| ... | ... | @@ -2673,10 +2655,10 @@ fn addDbgInfoErrorSet( |
| 2673 | 2655 | // DW.AT.enumeration_type |
| 2674 | 2656 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type)); |
| 2675 | 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 | 2659 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); |
| 2678 | 2660 | // DW.AT.name, DW.FORM.string |
| 2679 | const name = try ty.nameAllocArena(arena, module); | |
| 2661 | const name = try ty.nameAllocArena(arena, mod); | |
| 2680 | 2662 | try dbg_info_buffer.writer().print("{s}\x00", .{name}); |
| 2681 | 2663 | |
| 2682 | 2664 | // DW.AT.enumerator |
| ... | ... | @@ -2689,9 +2671,10 @@ fn addDbgInfoErrorSet( |
| 2689 | 2671 | // DW.AT.const_value, DW.FORM.data8 |
| 2690 | 2672 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian); |
| 2691 | 2673 | |
| 2692 | const error_names = ty.errorSetNames(); | |
| 2693 | for (error_names) |error_name| { | |
| 2694 | const kv = module.getErrorValue(error_name) catch unreachable; | |
| 2674 | const error_names = ty.errorSetNames(mod); | |
| 2675 | for (error_names) |error_name_ip| { | |
| 2676 | const int = try mod.getErrorValue(error_name_ip); | |
| 2677 | const error_name = mod.intern_pool.stringToSlice(error_name_ip); | |
| 2695 | 2678 | // DW.AT.enumerator |
| 2696 | 2679 | try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64)); |
| 2697 | 2680 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant)); |
| ... | ... | @@ -2699,7 +2682,7 @@ fn addDbgInfoErrorSet( |
| 2699 | 2682 | dbg_info_buffer.appendSliceAssumeCapacity(error_name); |
| 2700 | 2683 | dbg_info_buffer.appendAssumeCapacity(0); |
| 2701 | 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 | 2688 | // DW.AT.enumeration_type delimit children |
src/link/Elf.zig+63-58| ... | ... | @@ -28,6 +28,7 @@ const File = link.File; |
| 28 | 28 | const Liveness = @import("../Liveness.zig"); |
| 29 | 29 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 30 | 30 | const Module = @import("../Module.zig"); |
| 31 | const InternPool = @import("../InternPool.zig"); | |
| 31 | 32 | const Package = @import("../Package.zig"); |
| 32 | 33 | const StringTable = @import("strtab.zig").StringTable; |
| 33 | 34 | const TableSection = @import("table_section.zig").TableSection; |
| ... | ... | @@ -2414,7 +2415,8 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { |
| 2414 | 2415 | } |
| 2415 | 2416 | |
| 2416 | 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 | 2420 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 2419 | 2421 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 2420 | 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 | 2431 | metadata.state.* = .pending_flush; |
| 2430 | 2432 | const atom = metadata.atom.*; |
| 2431 | 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 | 2435 | .code => self.text_section_index.?, |
| 2434 | 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 | 2451 | } |
| 2450 | 2452 | |
| 2451 | 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 | 2456 | const ty = decl.ty; |
| 2454 | const zig_ty = ty.zigTypeTag(); | |
| 2457 | const zig_ty = ty.zigTypeTag(mod); | |
| 2455 | 2458 | const val = decl.val; |
| 2456 | 2459 | const shdr_index: u16 = blk: { |
| 2457 | if (val.isUndefDeep()) { | |
| 2460 | if (val.isUndefDeep(mod)) { | |
| 2458 | 2461 | // TODO in release-fast and release-small, we should put undef in .bss |
| 2459 | 2462 | break :blk self.data_section_index.?; |
| 2460 | 2463 | } |
| ... | ... | @@ -2463,7 +2466,7 @@ fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 { |
| 2463 | 2466 | // TODO: what if this is a function pointer? |
| 2464 | 2467 | .Fn => break :blk self.text_section_index.?, |
| 2465 | 2468 | else => { |
| 2466 | if (val.castTag(.variable)) |_| { | |
| 2469 | if (val.getVariable(mod)) |_| { | |
| 2467 | 2470 | break :blk self.data_section_index.?; |
| 2468 | 2471 | } |
| 2469 | 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 | 2481 | const mod = self.base.options.module.?; |
| 2479 | 2482 | const decl = mod.declPtr(decl_index); |
| 2480 | 2483 | |
| 2481 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 2482 | defer self.base.allocator.free(decl_name); | |
| 2484 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 2483 | 2485 | |
| 2484 | 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 | 2489 | const decl_metadata = self.decls.get(decl_index).?; |
| 2488 | 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 | 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 | 2578 | if (build_options.skip_non_native and builtin.object_format != .elf) { |
| 2577 | 2579 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2578 | 2580 | } |
| 2579 | 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 | 2585 | const tracy = trace(@src()); |
| 2584 | 2586 | defer tracy.end(); |
| 2585 | 2587 | |
| 2588 | const func = mod.funcPtr(func_index); | |
| 2586 | 2589 | const decl_index = func.owner_decl; |
| 2587 | const decl = module.declPtr(decl_index); | |
| 2590 | const decl = mod.declPtr(decl_index); | |
| 2588 | 2591 | |
| 2589 | 2592 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2590 | 2593 | self.freeUnnamedConsts(decl_index); |
| ... | ... | @@ -2593,28 +2596,28 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven |
| 2593 | 2596 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2594 | 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 | 2600 | defer if (decl_state) |*ds| ds.deinit(); |
| 2598 | 2601 | |
| 2599 | 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 | 2604 | .dwarf = ds, |
| 2602 | 2605 | }) |
| 2603 | 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 | 2609 | const code = switch (res) { |
| 2607 | 2610 | .ok => code_buffer.items, |
| 2608 | 2611 | .fail => |em| { |
| 2609 | 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 | 2614 | return; |
| 2612 | 2615 | }, |
| 2613 | 2616 | }; |
| 2614 | 2617 | const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC); |
| 2615 | 2618 | if (decl_state) |*ds| { |
| 2616 | 2619 | try self.dwarf.?.commitDeclState( |
| 2617 | module, | |
| 2620 | mod, | |
| 2618 | 2621 | decl_index, |
| 2619 | 2622 | local_sym.st_value, |
| 2620 | 2623 | local_sym.st_size, |
| ... | ... | @@ -2624,31 +2627,30 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven |
| 2624 | 2627 | |
| 2625 | 2628 | // Since we updated the vaddr and the size, each corresponding export |
| 2626 | 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 | 2633 | pub fn updateDecl( |
| 2631 | 2634 | self: *Elf, |
| 2632 | module: *Module, | |
| 2635 | mod: *Module, | |
| 2633 | 2636 | decl_index: Module.Decl.Index, |
| 2634 | 2637 | ) File.UpdateDeclError!void { |
| 2635 | 2638 | if (build_options.skip_non_native and builtin.object_format != .elf) { |
| 2636 | 2639 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2637 | 2640 | } |
| 2638 | 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 | 2645 | const tracy = trace(@src()); |
| 2643 | 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 | 2651 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 2649 | 2652 | } |
| 2650 | if (decl.val.castTag(.variable)) |payload| { | |
| 2651 | const variable = payload.data; | |
| 2653 | if (decl.val.getVariable(mod)) |variable| { | |
| 2652 | 2654 | if (variable.is_extern) { |
| 2653 | 2655 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 2654 | 2656 | } |
| ... | ... | @@ -2661,13 +2663,13 @@ pub fn updateDecl( |
| 2661 | 2663 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2662 | 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 | 2667 | defer if (decl_state) |*ds| ds.deinit(); |
| 2666 | 2668 | |
| 2667 | 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 | 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 | 2673 | .ty = decl.ty, |
| 2672 | 2674 | .val = decl_val, |
| 2673 | 2675 | }, &code_buffer, .{ |
| ... | ... | @@ -2676,7 +2678,7 @@ pub fn updateDecl( |
| 2676 | 2678 | .parent_atom_index = atom.getSymbolIndex().?, |
| 2677 | 2679 | }) |
| 2678 | 2680 | else |
| 2679 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | |
| 2681 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ | |
| 2680 | 2682 | .ty = decl.ty, |
| 2681 | 2683 | .val = decl_val, |
| 2682 | 2684 | }, &code_buffer, .none, .{ |
| ... | ... | @@ -2687,7 +2689,7 @@ pub fn updateDecl( |
| 2687 | 2689 | .ok => code_buffer.items, |
| 2688 | 2690 | .fail => |em| { |
| 2689 | 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 | 2693 | return; |
| 2692 | 2694 | }, |
| 2693 | 2695 | }; |
| ... | ... | @@ -2695,7 +2697,7 @@ pub fn updateDecl( |
| 2695 | 2697 | const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT); |
| 2696 | 2698 | if (decl_state) |*ds| { |
| 2697 | 2699 | try self.dwarf.?.commitDeclState( |
| 2698 | module, | |
| 2700 | mod, | |
| 2699 | 2701 | decl_index, |
| 2700 | 2702 | local_sym.st_value, |
| 2701 | 2703 | local_sym.st_size, |
| ... | ... | @@ -2705,7 +2707,7 @@ pub fn updateDecl( |
| 2705 | 2707 | |
| 2706 | 2708 | // Since we updated the vaddr and the size, each corresponding export |
| 2707 | 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 | 2713 | fn updateLazySymbolAtom( |
| ... | ... | @@ -2734,8 +2736,8 @@ fn updateLazySymbolAtom( |
| 2734 | 2736 | const atom = self.getAtom(atom_index); |
| 2735 | 2737 | const local_sym_index = atom.getSymbolIndex().?; |
| 2736 | 2738 | |
| 2737 | const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl| | |
| 2738 | mod.declPtr(owner_decl).srcLoc() | |
| 2739 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| | |
| 2740 | mod.declPtr(owner_decl).srcLoc(mod) | |
| 2739 | 2741 | else |
| 2740 | 2742 | Module.SrcLoc{ |
| 2741 | 2743 | .file_scope = undefined, |
| ... | ... | @@ -2800,8 +2802,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2800 | 2802 | |
| 2801 | 2803 | const decl = mod.declPtr(decl_index); |
| 2802 | 2804 | const name_str_index = blk: { |
| 2803 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 2804 | defer gpa.free(decl_name); | |
| 2805 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 2805 | 2806 | const index = unnamed_consts.items.len; |
| 2806 | 2807 | const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); |
| 2807 | 2808 | defer gpa.free(name); |
| ... | ... | @@ -2811,7 +2812,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2811 | 2812 | |
| 2812 | 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 | 2816 | .none = {}, |
| 2816 | 2817 | }, .{ |
| 2817 | 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 | 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 | 2831 | const shdr_index = self.rodata_section_index.?; |
| 2831 | 2832 | const phdr_index = self.sections.items(.phdr_index)[shdr_index]; |
| 2832 | 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 | 2853 | |
| 2853 | 2854 | pub fn updateDeclExports( |
| 2854 | 2855 | self: *Elf, |
| 2855 | module: *Module, | |
| 2856 | mod: *Module, | |
| 2856 | 2857 | decl_index: Module.Decl.Index, |
| 2857 | 2858 | exports: []const *Module.Export, |
| 2858 | 2859 | ) File.UpdateDeclExportsError!void { |
| ... | ... | @@ -2860,7 +2861,7 @@ pub fn updateDeclExports( |
| 2860 | 2861 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2861 | 2862 | } |
| 2862 | 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 | 2867 | const tracy = trace(@src()); |
| ... | ... | @@ -2868,7 +2869,7 @@ pub fn updateDeclExports( |
| 2868 | 2869 | |
| 2869 | 2870 | const gpa = self.base.allocator; |
| 2870 | 2871 | |
| 2871 | const decl = module.declPtr(decl_index); | |
| 2872 | const decl = mod.declPtr(decl_index); | |
| 2872 | 2873 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2873 | 2874 | const atom = self.getAtom(atom_index); |
| 2874 | 2875 | const decl_sym = atom.getSymbol(self); |
| ... | ... | @@ -2878,40 +2879,41 @@ pub fn updateDeclExports( |
| 2878 | 2879 | try self.global_symbols.ensureUnusedCapacity(gpa, exports.len); |
| 2879 | 2880 | |
| 2880 | 2881 | for (exports) |exp| { |
| 2881 | if (exp.options.section) |section_name| { | |
| 2882 | if (!mem.eql(u8, section_name, ".text")) { | |
| 2883 | try module.failed_exports.ensureUnusedCapacity(module.gpa, 1); | |
| 2884 | module.failed_exports.putAssumeCapacityNoClobber( | |
| 2882 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | |
| 2883 | if (exp.opts.section.unwrap()) |section_name| { | |
| 2884 | if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) { | |
| 2885 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); | |
| 2886 | mod.failed_exports.putAssumeCapacityNoClobber( | |
| 2885 | 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 | 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 | 2894 | .Internal => elf.STB_LOCAL, |
| 2893 | 2895 | .Strong => blk: { |
| 2894 | 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 | 2898 | self.entry_addr = decl_sym.st_value; |
| 2897 | 2899 | } |
| 2898 | 2900 | break :blk elf.STB_GLOBAL; |
| 2899 | 2901 | }, |
| 2900 | 2902 | .Weak => elf.STB_WEAK, |
| 2901 | 2903 | .LinkOnce => { |
| 2902 | try module.failed_exports.ensureUnusedCapacity(module.gpa, 1); | |
| 2903 | module.failed_exports.putAssumeCapacityNoClobber( | |
| 2904 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); | |
| 2905 | mod.failed_exports.putAssumeCapacityNoClobber( | |
| 2904 | 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 | 2909 | continue; |
| 2908 | 2910 | }, |
| 2909 | 2911 | }; |
| 2910 | 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 | 2914 | const sym = &self.global_symbols.items[i]; |
| 2913 | 2915 | sym.* = .{ |
| 2914 | .st_name = try self.shstrtab.insert(gpa, exp.options.name), | |
| 2916 | .st_name = try self.shstrtab.insert(gpa, exp_name), | |
| 2915 | 2917 | .st_info = (stb_bits << 4) | stt_bits, |
| 2916 | 2918 | .st_other = 0, |
| 2917 | 2919 | .st_shndx = shdr_index, |
| ... | ... | @@ -2925,7 +2927,7 @@ pub fn updateDeclExports( |
| 2925 | 2927 | }; |
| 2926 | 2928 | try decl_metadata.exports.append(gpa, @intCast(u32, i)); |
| 2927 | 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 | 2931 | .st_info = (stb_bits << 4) | stt_bits, |
| 2930 | 2932 | .st_other = 0, |
| 2931 | 2933 | .st_shndx = shdr_index, |
| ... | ... | @@ -2942,8 +2944,7 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.In |
| 2942 | 2944 | defer tracy.end(); |
| 2943 | 2945 | |
| 2944 | 2946 | const decl = mod.declPtr(decl_index); |
| 2945 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 2946 | defer self.base.allocator.free(decl_name); | |
| 2947 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 2947 | 2948 | |
| 2948 | 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 | 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 | 2962 | if (self.llvm_object) |_| return; |
| 2958 | 2963 | const metadata = self.decls.getPtr(decl_index) orelse return; |
| 2959 | const sym_index = metadata.getExportPtr(self, name) orelse return; | |
| 2960 | log.debug("deleting export '{s}'", .{name}); | |
| 2964 | const mod = self.base.options.module.?; | |
| 2965 | const sym_index = metadata.getExportPtr(self, mod.intern_pool.stringToSlice(name)) orelse return; | |
| 2961 | 2966 | self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {}; |
| 2962 | 2967 | self.global_symbols.items[sym_index.*].st_info = 0; |
| 2963 | 2968 | sym_index.* = 0; |
src/link/MachO.zig+76-68| ... | ... | @@ -40,6 +40,7 @@ const Liveness = @import("../Liveness.zig"); |
| 40 | 40 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 41 | 41 | const Md5 = std.crypto.hash.Md5; |
| 42 | 42 | const Module = @import("../Module.zig"); |
| 43 | const InternPool = @import("../InternPool.zig"); | |
| 43 | 44 | const Relocation = @import("MachO/Relocation.zig"); |
| 44 | 45 | const StringTable = @import("strtab.zig").StringTable; |
| 45 | 46 | const TableSection = @import("table_section.zig").TableSection; |
| ... | ... | @@ -1847,18 +1848,19 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { |
| 1847 | 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 | 1852 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 1852 | 1853 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1853 | 1854 | } |
| 1854 | 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 | 1858 | const tracy = trace(@src()); |
| 1858 | 1859 | defer tracy.end(); |
| 1859 | 1860 | |
| 1861 | const func = mod.funcPtr(func_index); | |
| 1860 | 1862 | const decl_index = func.owner_decl; |
| 1861 | const decl = module.declPtr(decl_index); | |
| 1863 | const decl = mod.declPtr(decl_index); | |
| 1862 | 1864 | |
| 1863 | 1865 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 1864 | 1866 | self.freeUnnamedConsts(decl_index); |
| ... | ... | @@ -1868,23 +1870,23 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 1868 | 1870 | defer code_buffer.deinit(); |
| 1869 | 1871 | |
| 1870 | 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 | 1874 | else |
| 1873 | 1875 | null; |
| 1874 | 1876 | defer if (decl_state) |*ds| ds.deinit(); |
| 1875 | 1877 | |
| 1876 | 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 | 1880 | .dwarf = ds, |
| 1879 | 1881 | }) |
| 1880 | 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 | 1885 | var code = switch (res) { |
| 1884 | 1886 | .ok => code_buffer.items, |
| 1885 | 1887 | .fail => |em| { |
| 1886 | 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 | 1890 | return; |
| 1889 | 1891 | }, |
| 1890 | 1892 | }; |
| ... | ... | @@ -1893,7 +1895,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 1893 | 1895 | |
| 1894 | 1896 | if (decl_state) |*ds| { |
| 1895 | 1897 | try self.d_sym.?.dwarf.commitDeclState( |
| 1896 | module, | |
| 1898 | mod, | |
| 1897 | 1899 | decl_index, |
| 1898 | 1900 | addr, |
| 1899 | 1901 | self.getAtom(atom_index).size, |
| ... | ... | @@ -1903,7 +1905,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 1903 | 1905 | |
| 1904 | 1906 | // Since we updated the vaddr and the size, each corresponding export symbol also |
| 1905 | 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 | 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 | 1914 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1913 | 1915 | defer code_buffer.deinit(); |
| 1914 | 1916 | |
| 1915 | const module = self.base.options.module.?; | |
| 1917 | const mod = self.base.options.module.?; | |
| 1916 | 1918 | const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index); |
| 1917 | 1919 | if (!gop.found_existing) { |
| 1918 | 1920 | gop.value_ptr.* = .{}; |
| 1919 | 1921 | } |
| 1920 | 1922 | const unnamed_consts = gop.value_ptr; |
| 1921 | 1923 | |
| 1922 | const decl = module.declPtr(decl_index); | |
| 1923 | const decl_name = try decl.getFullyQualifiedName(module); | |
| 1924 | defer gpa.free(decl_name); | |
| 1924 | const decl = mod.declPtr(decl_index); | |
| 1925 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 1925 | 1926 | |
| 1926 | 1927 | const name_str_index = blk: { |
| 1927 | 1928 | const index = unnamed_consts.items.len; |
| ... | ... | @@ -1935,20 +1936,20 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 1935 | 1936 | |
| 1936 | 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 | 1940 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| 1940 | 1941 | }); |
| 1941 | 1942 | var code = switch (res) { |
| 1942 | 1943 | .ok => code_buffer.items, |
| 1943 | 1944 | .fail => |em| { |
| 1944 | 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 | 1947 | log.err("{s}", .{em.msg}); |
| 1947 | 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 | 1953 | const atom = self.getAtomPtr(atom_index); |
| 1953 | 1954 | atom.size = code.len; |
| 1954 | 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 | 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 | 1976 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 1976 | 1977 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1977 | 1978 | } |
| 1978 | 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 | 1982 | const tracy = trace(@src()); |
| 1982 | 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 | 1988 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1988 | 1989 | } |
| 1989 | if (decl.val.castTag(.variable)) |payload| { | |
| 1990 | const variable = payload.data; | |
| 1990 | if (decl.val.getVariable(mod)) |variable| { | |
| 1991 | 1991 | if (variable.is_extern) { |
| 1992 | 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| | |
| 1997 | payload.data.is_threadlocal and !self.base.options.single_threaded | |
| 1996 | const is_threadlocal = if (decl.val.getVariable(mod)) |variable| | |
| 1997 | variable.is_threadlocal and !self.base.options.single_threaded | |
| 1998 | 1998 | else |
| 1999 | 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 | 2002 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2003 | 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 | 2007 | defer code_buffer.deinit(); |
| 2008 | 2008 | |
| 2009 | 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 | 2011 | else |
| 2012 | 2012 | null; |
| 2013 | 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 | 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 | 2018 | .ty = decl.ty, |
| 2019 | 2019 | .val = decl_val, |
| 2020 | 2020 | }, &code_buffer, .{ |
| ... | ... | @@ -2023,7 +2023,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2023 | 2023 | .parent_atom_index = sym_index, |
| 2024 | 2024 | }) |
| 2025 | 2025 | else |
| 2026 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | |
| 2026 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ | |
| 2027 | 2027 | .ty = decl.ty, |
| 2028 | 2028 | .val = decl_val, |
| 2029 | 2029 | }, &code_buffer, .none, .{ |
| ... | ... | @@ -2034,7 +2034,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2034 | 2034 | .ok => code_buffer.items, |
| 2035 | 2035 | .fail => |em| { |
| 2036 | 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 | 2038 | return; |
| 2039 | 2039 | }, |
| 2040 | 2040 | }; |
| ... | ... | @@ -2042,7 +2042,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2042 | 2042 | |
| 2043 | 2043 | if (decl_state) |*ds| { |
| 2044 | 2044 | try self.d_sym.?.dwarf.commitDeclState( |
| 2045 | module, | |
| 2045 | mod, | |
| 2046 | 2046 | decl_index, |
| 2047 | 2047 | addr, |
| 2048 | 2048 | self.getAtom(atom_index).size, |
| ... | ... | @@ -2052,7 +2052,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2052 | 2052 | |
| 2053 | 2053 | // Since we updated the vaddr and the size, each corresponding export symbol also |
| 2054 | 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 | 2058 | fn updateLazySymbolAtom( |
| ... | ... | @@ -2081,8 +2081,8 @@ fn updateLazySymbolAtom( |
| 2081 | 2081 | const atom = self.getAtomPtr(atom_index); |
| 2082 | 2082 | const local_sym_index = atom.getSymbolIndex().?; |
| 2083 | 2083 | |
| 2084 | const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl| | |
| 2085 | mod.declPtr(owner_decl).srcLoc() | |
| 2084 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| | |
| 2085 | mod.declPtr(owner_decl).srcLoc(mod) | |
| 2086 | 2086 | else |
| 2087 | 2087 | Module.SrcLoc{ |
| 2088 | 2088 | .file_scope = undefined, |
| ... | ... | @@ -2126,7 +2126,8 @@ fn updateLazySymbolAtom( |
| 2126 | 2126 | } |
| 2127 | 2127 | |
| 2128 | 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 | 2131 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 2131 | 2132 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 2132 | 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 | 2145 | metadata.state.* = .pending_flush; |
| 2145 | 2146 | const atom = metadata.atom.*; |
| 2146 | 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 | 2149 | .code => self.text_section_index.?, |
| 2149 | 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 | 2153 | } |
| 2153 | 2154 | |
| 2154 | 2155 | fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { |
| 2156 | const mod = self.base.options.module.?; | |
| 2155 | 2157 | // Lowering a TLV on macOS involves two stages: |
| 2156 | 2158 | // 1. first we lower the initializer into appopriate section (__thread_data or __thread_bss) |
| 2157 | 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 | 2177 | |
| 2176 | 2178 | const decl = module.declPtr(decl_index); |
| 2177 | 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 | 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 | 2183 | .ty = decl.ty, |
| 2182 | 2184 | .val = decl_val, |
| 2183 | 2185 | }, &code_buffer, .{ |
| ... | ... | @@ -2186,7 +2188,7 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D |
| 2186 | 2188 | .parent_atom_index = init_sym_index, |
| 2187 | 2189 | }) |
| 2188 | 2190 | else |
| 2189 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | |
| 2191 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ | |
| 2190 | 2192 | .ty = decl.ty, |
| 2191 | 2193 | .val = decl_val, |
| 2192 | 2194 | }, &code_buffer, .none, .{ |
| ... | ... | @@ -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); | |
| 2208 | defer gpa.free(decl_name); | |
| 2209 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(module)); | |
| 2209 | 2210 | |
| 2210 | 2211 | const init_sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{decl_name}); |
| 2211 | 2212 | defer gpa.free(init_sym_name); |
| ... | ... | @@ -2262,12 +2263,13 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2262 | 2263 | const decl = self.base.options.module.?.declPtr(decl_index); |
| 2263 | 2264 | const ty = decl.ty; |
| 2264 | 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 | 2268 | const mode = self.base.options.optimize_mode; |
| 2267 | 2269 | const single_threaded = self.base.options.single_threaded; |
| 2268 | 2270 | const sect_id: u8 = blk: { |
| 2269 | 2271 | // TODO finish and audit this function |
| 2270 | if (val.isUndefDeep()) { | |
| 2272 | if (val.isUndefDeep(mod)) { | |
| 2271 | 2273 | if (mode == .ReleaseFast or mode == .ReleaseSmall) { |
| 2272 | 2274 | @panic("TODO __DATA,__bss"); |
| 2273 | 2275 | } else { |
| ... | ... | @@ -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| { | |
| 2279 | if (variable.data.is_threadlocal and !single_threaded) { | |
| 2280 | if (val.getVariable(mod)) |variable| { | |
| 2281 | if (variable.is_threadlocal and !single_threaded) { | |
| 2280 | 2282 | break :blk self.thread_data_section_index.?; |
| 2281 | 2283 | } |
| 2282 | 2284 | break :blk self.data_section_index.?; |
| ... | ... | @@ -2286,7 +2288,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2286 | 2288 | // TODO: what if this is a function pointer? |
| 2287 | 2289 | .Fn => break :blk self.text_section_index.?, |
| 2288 | 2290 | else => { |
| 2289 | if (val.castTag(.variable)) |_| { | |
| 2291 | if (val.getVariable(mod)) |_| { | |
| 2290 | 2292 | break :blk self.data_section_index.?; |
| 2291 | 2293 | } |
| 2292 | 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 | 2303 | const mod = self.base.options.module.?; |
| 2302 | 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); | |
| 2307 | defer gpa.free(decl_name); | |
| 2308 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 2308 | 2309 | |
| 2309 | 2310 | const decl_metadata = self.decls.get(decl_index).?; |
| 2310 | 2311 | const atom_index = decl_metadata.atom; |
| ... | ... | @@ -2376,7 +2377,7 @@ pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.De |
| 2376 | 2377 | |
| 2377 | 2378 | pub fn updateDeclExports( |
| 2378 | 2379 | self: *MachO, |
| 2379 | module: *Module, | |
| 2380 | mod: *Module, | |
| 2380 | 2381 | decl_index: Module.Decl.Index, |
| 2381 | 2382 | exports: []const *Module.Export, |
| 2382 | 2383 | ) File.UpdateDeclExportsError!void { |
| ... | ... | @@ -2385,7 +2386,7 @@ pub fn updateDeclExports( |
| 2385 | 2386 | } |
| 2386 | 2387 | if (build_options.have_llvm) { |
| 2387 | 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 | 2392 | const tracy = trace(@src()); |
| ... | ... | @@ -2393,26 +2394,28 @@ pub fn updateDeclExports( |
| 2393 | 2394 | |
| 2394 | 2395 | const gpa = self.base.allocator; |
| 2395 | 2396 | |
| 2396 | const decl = module.declPtr(decl_index); | |
| 2397 | const decl = mod.declPtr(decl_index); | |
| 2397 | 2398 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2398 | 2399 | const atom = self.getAtom(atom_index); |
| 2399 | 2400 | const decl_sym = atom.getSymbol(self); |
| 2400 | 2401 | const decl_metadata = self.decls.getPtr(decl_index).?; |
| 2401 | 2402 | |
| 2402 | 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 | 2407 | defer gpa.free(exp_name); |
| 2405 | 2408 | |
| 2406 | 2409 | log.debug("adding new export '{s}'", .{exp_name}); |
| 2407 | 2410 | |
| 2408 | if (exp.options.section) |section_name| { | |
| 2409 | if (!mem.eql(u8, section_name, "__text")) { | |
| 2410 | try module.failed_exports.putNoClobber( | |
| 2411 | module.gpa, | |
| 2411 | if (exp.opts.section.unwrap()) |section_name| { | |
| 2412 | if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) { | |
| 2413 | try mod.failed_exports.putNoClobber( | |
| 2414 | mod.gpa, | |
| 2412 | 2415 | exp, |
| 2413 | 2416 | try Module.ErrorMsg.create( |
| 2414 | 2417 | gpa, |
| 2415 | decl.srcLoc(), | |
| 2418 | decl.srcLoc(mod), | |
| 2416 | 2419 | "Unimplemented: ExportOptions.section", |
| 2417 | 2420 | .{}, |
| 2418 | 2421 | ), |
| ... | ... | @@ -2421,13 +2424,13 @@ pub fn updateDeclExports( |
| 2421 | 2424 | } |
| 2422 | 2425 | } |
| 2423 | 2426 | |
| 2424 | if (exp.options.linkage == .LinkOnce) { | |
| 2425 | try module.failed_exports.putNoClobber( | |
| 2426 | module.gpa, | |
| 2427 | if (exp.opts.linkage == .LinkOnce) { | |
| 2428 | try mod.failed_exports.putNoClobber( | |
| 2429 | mod.gpa, | |
| 2427 | 2430 | exp, |
| 2428 | 2431 | try Module.ErrorMsg.create( |
| 2429 | 2432 | gpa, |
| 2430 | decl.srcLoc(), | |
| 2433 | decl.srcLoc(mod), | |
| 2431 | 2434 | "Unimplemented: GlobalLinkage.LinkOnce", |
| 2432 | 2435 | .{}, |
| 2433 | 2436 | ), |
| ... | ... | @@ -2450,7 +2453,7 @@ pub fn updateDeclExports( |
| 2450 | 2453 | .n_value = decl_sym.n_value, |
| 2451 | 2454 | }; |
| 2452 | 2455 | |
| 2453 | switch (exp.options.linkage) { | |
| 2456 | switch (exp.opts.linkage) { | |
| 2454 | 2457 | .Internal => { |
| 2455 | 2458 | // Symbol should be hidden, or in MachO lingo, private extern. |
| 2456 | 2459 | // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF. |
| ... | ... | @@ -2471,9 +2474,9 @@ pub fn updateDeclExports( |
| 2471 | 2474 | // TODO: this needs rethinking |
| 2472 | 2475 | const global = self.getGlobal(exp_name).?; |
| 2473 | 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 | 2478 | gpa, |
| 2476 | decl.srcLoc(), | |
| 2479 | decl.srcLoc(mod), | |
| 2477 | 2480 | \\LinkError: symbol '{s}' defined multiple times |
| 2478 | 2481 | , |
| 2479 | 2482 | .{exp_name}, |
| ... | ... | @@ -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 | 2496 | if (self.llvm_object) |_| return; |
| 2490 | 2497 | const metadata = self.decls.getPtr(decl_index) orelse return; |
| 2491 | 2498 | |
| 2492 | 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 | 2502 | defer gpa.free(exp_name); |
| 2495 | 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 | 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 | 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 | 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 | 213 | const gpa = self.base.allocator; |
| 214 | 214 | const mod = self.base.options.module.?; |
| 215 | 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 | 217 | if (fn_map_res.found_existing) { |
| 218 | 218 | if (try fn_map_res.value_ptr.functions.fetchPut(gpa, decl_index, out)) |old_entry| { |
| 219 | 219 | gpa.free(old_entry.value.code); |
| 220 | 220 | gpa.free(old_entry.value.lineinfo); |
| 221 | 221 | } |
| 222 | 222 | } else { |
| 223 | const file = decl.getFileScope(); | |
| 223 | const file = decl.getFileScope(mod); | |
| 224 | 224 | const arena = self.path_arena.allocator(); |
| 225 | 225 | // each file gets a symbol |
| 226 | 226 | fn_map_res.value_ptr.* = .{ |
| ... | ... | @@ -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 | 280 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 281 | 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 | 285 | const decl_index = func.owner_decl; |
| 285 | const decl = module.declPtr(decl_index); | |
| 286 | const decl = mod.declPtr(decl_index); | |
| 286 | 287 | self.freeUnnamedConsts(decl_index); |
| 287 | 288 | |
| 288 | 289 | _ = try self.seeDecl(decl_index); |
| 289 | log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); | |
| 290 | 290 | |
| 291 | 291 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 292 | 292 | defer code_buffer.deinit(); |
| ... | ... | @@ -298,8 +298,8 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 298 | 298 | |
| 299 | 299 | const res = try codegen.generateFunction( |
| 300 | 300 | &self.base, |
| 301 | decl.srcLoc(), | |
| 302 | func, | |
| 301 | decl.srcLoc(mod), | |
| 302 | func_index, | |
| 303 | 303 | air, |
| 304 | 304 | liveness, |
| 305 | 305 | &code_buffer, |
| ... | ... | @@ -316,7 +316,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 316 | 316 | .ok => try code_buffer.toOwnedSlice(), |
| 317 | 317 | .fail => |em| { |
| 318 | 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 | 320 | return; |
| 321 | 321 | }, |
| 322 | 322 | }; |
| ... | ... | @@ -344,8 +344,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 344 | 344 | } |
| 345 | 345 | const unnamed_consts = gop.value_ptr; |
| 346 | 346 | |
| 347 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 348 | defer self.base.allocator.free(decl_name); | |
| 347 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 349 | 348 | |
| 350 | 349 | const index = unnamed_consts.items.len; |
| 351 | 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 | 365 | }; |
| 367 | 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 | 369 | .none = {}, |
| 371 | 370 | }, .{ |
| 372 | 371 | .parent_atom_index = @enumToInt(decl_index), |
| ... | ... | @@ -388,14 +387,13 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 388 | 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 { | |
| 392 | const decl = module.declPtr(decl_index); | |
| 390 | pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void { | |
| 391 | const decl = mod.declPtr(decl_index); | |
| 393 | 392 | |
| 394 | if (decl.val.tag() == .extern_fn) { | |
| 393 | if (decl.val.getExternFunc(mod)) |_| { | |
| 395 | 394 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 396 | 395 | } |
| 397 | if (decl.val.castTag(.variable)) |payload| { | |
| 398 | const variable = payload.data; | |
| 396 | if (decl.val.getVariable(mod)) |variable| { | |
| 399 | 397 | if (variable.is_extern) { |
| 400 | 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 | 401 | |
| 404 | 402 | _ = try self.seeDecl(decl_index); |
| 405 | 403 | |
| 406 | log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index }); | |
| 407 | ||
| 408 | 404 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 409 | 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 | 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 | 409 | .ty = decl.ty, |
| 414 | 410 | .val = decl_val, |
| 415 | 411 | }, &code_buffer, .{ .none = {} }, .{ |
| ... | ... | @@ -419,7 +415,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) |
| 419 | 415 | .ok => code_buffer.items, |
| 420 | 416 | .fail => |em| { |
| 421 | 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 | 419 | return; |
| 424 | 420 | }, |
| 425 | 421 | }; |
| ... | ... | @@ -432,9 +428,9 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) |
| 432 | 428 | } |
| 433 | 429 | /// called at the end of update{Decl,Func} |
| 434 | 430 | fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { |
| 435 | const decl = self.base.options.module.?.declPtr(decl_index); | |
| 436 | const is_fn = (decl.ty.zigTypeTag() == .Fn); | |
| 437 | log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name }); | |
| 431 | const mod = self.base.options.module.?; | |
| 432 | const decl = mod.declPtr(decl_index); | |
| 433 | const is_fn = (decl.ty.zigTypeTag(mod) == .Fn); | |
| 438 | 434 | const sym_t: aout.Sym.Type = if (is_fn) .t else .d; |
| 439 | 435 | |
| 440 | 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 | 441 | const sym: aout.Sym = .{ |
| 446 | 442 | .value = undefined, // the value of stuff gets filled in in flushModule |
| 447 | 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 | 447 | if (decl_block.sym_index) |s| { |
| ... | ... | @@ -566,10 +562,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 566 | 562 | var it = fentry.value_ptr.functions.iterator(); |
| 567 | 563 | while (it.next()) |entry| { |
| 568 | 564 | const decl_index = entry.key_ptr.*; |
| 569 | const decl = mod.declPtr(decl_index); | |
| 570 | 565 | const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); |
| 571 | 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 | 568 | // connect the previous decl to the next |
| 575 | 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 | 609 | var it = self.data_decl_table.iterator(); |
| 616 | 610 | while (it.next()) |entry| { |
| 617 | 611 | const decl_index = entry.key_ptr.*; |
| 618 | const decl = mod.declPtr(decl_index); | |
| 619 | 612 | const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); |
| 620 | 613 | const code = entry.value_ptr.*; |
| 621 | log.debug("write data decl {*} ({s})", .{ decl, decl.name }); | |
| 622 | 614 | |
| 623 | 615 | foff += code.len; |
| 624 | 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 | 686 | const source_decl = mod.declPtr(source_decl_index); |
| 695 | 687 | for (kv.value_ptr.items) |reloc| { |
| 696 | 688 | const target_decl_index = reloc.target; |
| 697 | const target_decl = mod.declPtr(target_decl_index); | |
| 698 | 689 | const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index); |
| 699 | 690 | const target_decl_offset = target_decl_block.offset.?; |
| 700 | 691 | |
| 701 | 692 | const offset = reloc.offset; |
| 702 | 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 | 695 | const code = blk: { |
| 707 | const is_fn = source_decl.ty.zigTypeTag() == .Fn; | |
| 696 | const is_fn = source_decl.ty.zigTypeTag(mod) == .Fn; | |
| 708 | 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 | 699 | const output = table.get(source_decl_index).?; |
| 711 | 700 | break :blk output.code; |
| 712 | 701 | } else { |
| ... | ... | @@ -728,7 +717,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 728 | 717 | } |
| 729 | 718 | fn addDeclExports( |
| 730 | 719 | self: *Plan9, |
| 731 | module: *Module, | |
| 720 | mod: *Module, | |
| 732 | 721 | decl_index: Module.Decl.Index, |
| 733 | 722 | exports: []const *Module.Export, |
| 734 | 723 | ) !void { |
| ... | ... | @@ -736,12 +725,13 @@ fn addDeclExports( |
| 736 | 725 | const decl_block = self.getDeclBlock(metadata.index); |
| 737 | 726 | |
| 738 | 727 | for (exports) |exp| { |
| 728 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | |
| 739 | 729 | // plan9 does not support custom sections |
| 740 | if (exp.options.section) |section_name| { | |
| 741 | if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) { | |
| 742 | try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create( | |
| 730 | if (exp.opts.section.unwrap()) |section_name| { | |
| 731 | if (!mod.intern_pool.stringEqlSlice(section_name, ".text") and !mod.intern_pool.stringEqlSlice(section_name, ".data")) { | |
| 732 | try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( | |
| 743 | 733 | self.base.allocator, |
| 744 | module.declPtr(decl_index).srcLoc(), | |
| 734 | mod.declPtr(decl_index).srcLoc(mod), | |
| 745 | 735 | "plan9 does not support extra sections", |
| 746 | 736 | .{}, |
| 747 | 737 | )); |
| ... | ... | @@ -751,10 +741,10 @@ fn addDeclExports( |
| 751 | 741 | const sym = .{ |
| 752 | 742 | .value = decl_block.offset.?, |
| 753 | 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 | 748 | self.syms.items[i] = sym; |
| 759 | 749 | } else { |
| 760 | 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 | 760 | // in the deleteUnusedDecl function. |
| 771 | 761 | const mod = self.base.options.module.?; |
| 772 | 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 | 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 | 766 | var submap = symidx_and_submap.functions; |
| 777 | 767 | if (submap.fetchSwapRemove(decl_index)) |removed_entry| { |
| 778 | 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 | 945 | try w.writeAll(sym.name); |
| 956 | 946 | try w.writeByte(0); |
| 957 | 947 | } |
| 948 | ||
| 958 | 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 | 952 | const writer = buf.writer(); |
| 960 | 953 | // write the f symbols |
| 961 | 954 | { |
| ... | ... | @@ -979,7 +972,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 979 | 972 | const sym = self.syms.items[decl_block.sym_index.?]; |
| 980 | 973 | try self.writeSym(writer, sym); |
| 981 | 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 | 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 | 998 | const sym = self.syms.items[decl_block.sym_index.?]; |
| 1006 | 999 | try self.writeSym(writer, sym); |
| 1007 | 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 | 1002 | const s = self.syms.items[exp_i]; |
| 1010 | 1003 | if (mem.eql(u8, s.name, "_start")) |
| 1011 | 1004 | self.entry_val = s.value; |
| ... | ... | @@ -1031,7 +1024,7 @@ pub fn getDeclVAddr( |
| 1031 | 1024 | ) !u64 { |
| 1032 | 1025 | const mod = self.base.options.module.?; |
| 1033 | 1026 | const decl = mod.declPtr(decl_index); |
| 1034 | if (decl.ty.zigTypeTag() == .Fn) { | |
| 1027 | if (decl.ty.zigTypeTag(mod) == .Fn) { | |
| 1035 | 1028 | var start = self.bases.text; |
| 1036 | 1029 | var it_file = self.fn_decl_table.iterator(); |
| 1037 | 1030 | while (it_file.next()) |fentry| { |
src/link/SpirV.zig+9-6| ... | ... | @@ -103,11 +103,13 @@ pub fn deinit(self: *SpirV) void { |
| 103 | 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 | 107 | if (build_options.skip_non_native) { |
| 108 | 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 | 113 | var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link); |
| 112 | 114 | defer decl_gen.deinit(); |
| 113 | 115 | |
| ... | ... | @@ -131,12 +133,12 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index) |
| 131 | 133 | |
| 132 | 134 | pub fn updateDeclExports( |
| 133 | 135 | self: *SpirV, |
| 134 | module: *Module, | |
| 136 | mod: *Module, | |
| 135 | 137 | decl_index: Module.Decl.Index, |
| 136 | 138 | exports: []const *Module.Export, |
| 137 | 139 | ) !void { |
| 138 | const decl = module.declPtr(decl_index); | |
| 139 | if (decl.val.tag() == .function and decl.ty.fnCallingConvention() == .Kernel) { | |
| 140 | const decl = mod.declPtr(decl_index); | |
| 141 | if (decl.val.getFunctionIndex(mod) != .none and decl.ty.fnCallingConvention(mod) == .Kernel) { | |
| 140 | 142 | // TODO: Unify with resolveDecl in spirv.zig. |
| 141 | 143 | const entry = try self.decl_link.getOrPut(decl_index); |
| 142 | 144 | if (!entry.found_existing) { |
| ... | ... | @@ -145,7 +147,7 @@ pub fn updateDeclExports( |
| 145 | 147 | const spv_decl_index = entry.value_ptr.*; |
| 146 | 148 | |
| 147 | 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 | 190 | var error_info = std.ArrayList(u8).init(self.spv.arena); |
| 189 | 191 | try error_info.appendSlice("zig_errors"); |
| 190 | 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 | 195 | // Errors can contain pretty much any character - to encode them in a string we must escape |
| 193 | 196 | // them somehow. Easiest here is to use some established scheme, one which also preseves the |
| 194 | 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 | 149 | /// into the final binary. |
| 150 | 150 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, |
| 151 | 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 | 154 | /// Maps a symbol's location to an atom. This can be used to find meta |
| 154 | 155 | /// data of a symbol, such as its size, or its offset to perform a relocation. |
| 155 | 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 | 515 | /// Leaves index undefined and the default flags (0). |
| 515 | 516 | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { |
| 516 | 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 | 522 | const sym_index = @intCast(u32, wasm.symbols.items.len); |
| 518 | 523 | const loc: SymbolLoc = .{ .index = sym_index, .file = null }; |
| 519 | 524 | try wasm.symbols.append(wasm.base.allocator, .{ |
| ... | ... | @@ -691,7 +696,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { |
| 691 | 696 | try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {}); |
| 692 | 697 | |
| 693 | 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 | 701 | continue; |
| 697 | 702 | } |
| ... | ... | @@ -801,7 +806,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { |
| 801 | 806 | try wasm.resolved_symbols.put(wasm.base.allocator, location, {}); |
| 802 | 807 | assert(wasm.resolved_symbols.swapRemove(existing_loc)); |
| 803 | 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 | 817 | log.debug("Resolving symbols in archives", .{}); |
| 813 | 818 | var index: u32 = 0; |
| 814 | 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 | 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 | 825 | const offset = archive.toc.get(sym_name) orelse { |
| 819 | 826 | // symbol does not exist in this archive |
| 820 | 827 | continue; |
| 821 | 828 | }; |
| 822 | 829 | |
| 823 | log.debug("Detected symbol '{s}' in archive '{s}', parsing objects..", .{ sym_name, archive.name }); | |
| 824 | 830 | // Symbol is found in unparsed object file within current archive. |
| 825 | 831 | // Parse object and and resolve symbols again before we check remaining |
| 826 | 832 | // undefined symbols. |
| ... | ... | @@ -1191,28 +1197,36 @@ fn validateFeatures( |
| 1191 | 1197 | /// if one or multiple undefined references exist. When none exist, the symbol will |
| 1192 | 1198 | /// not be created, ensuring we don't unneccesarily emit unreferenced symbols. |
| 1193 | 1199 | fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1194 | if (wasm.undefs.fetchSwapRemove("__heap_base")) |kv| { | |
| 1195 | const loc = try wasm.createSyntheticSymbol("__heap_base", .data); | |
| 1196 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | |
| 1197 | _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations. | |
| 1200 | if (wasm.string_table.getOffset("__heap_base")) |name_offset| { | |
| 1201 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { | |
| 1202 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); | |
| 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| { | |
| 1201 | const loc = try wasm.createSyntheticSymbol("__heap_end", .data); | |
| 1202 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | |
| 1203 | _ = wasm.resolved_symbols.swapRemove(loc); | |
| 1208 | if (wasm.string_table.getOffset("__heap_end")) |name_offset| { | |
| 1209 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { | |
| 1210 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); | |
| 1211 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | |
| 1212 | _ = wasm.resolved_symbols.swapRemove(loc); | |
| 1213 | } | |
| 1204 | 1214 | } |
| 1205 | 1215 | |
| 1206 | 1216 | if (!wasm.base.options.shared_memory) { |
| 1207 | if (wasm.undefs.fetchSwapRemove("__tls_base")) |kv| { | |
| 1208 | const loc = try wasm.createSyntheticSymbol("__tls_base", .global); | |
| 1209 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | |
| 1217 | if (wasm.string_table.getOffset("__tls_base")) |name_offset| { | |
| 1218 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { | |
| 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| { | |
| 1213 | const loc = try wasm.createSyntheticSymbol("__zig_errors_len", .data); | |
| 1214 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | |
| 1215 | _ = wasm.resolved_symbols.swapRemove(kv.value); | |
| 1224 | if (wasm.string_table.getOffset("__zig_errors_len")) |name_offset| { | |
| 1225 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { | |
| 1226 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); | |
| 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 | 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 | 1342 | if (build_options.skip_non_native and builtin.object_format != .wasm) { |
| 1329 | 1343 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1330 | 1344 | } |
| 1331 | 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 | 1349 | const tracy = trace(@src()); |
| 1336 | 1350 | defer tracy.end(); |
| 1337 | 1351 | |
| 1352 | const func = mod.funcPtr(func_index); | |
| 1338 | 1353 | const decl_index = func.owner_decl; |
| 1339 | 1354 | const decl = mod.declPtr(decl_index); |
| 1340 | 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 | 1363 | defer code_writer.deinit(); |
| 1349 | 1364 | // const result = try codegen.generateFunction( |
| 1350 | 1365 | // &wasm.base, |
| 1351 | // decl.srcLoc(), | |
| 1366 | // decl.srcLoc(mod), | |
| 1352 | 1367 | // func, |
| 1353 | 1368 | // air, |
| 1354 | 1369 | // liveness, |
| ... | ... | @@ -1357,8 +1372,8 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes |
| 1357 | 1372 | // ); |
| 1358 | 1373 | const result = try codegen.generateFunction( |
| 1359 | 1374 | &wasm.base, |
| 1360 | decl.srcLoc(), | |
| 1361 | func, | |
| 1375 | decl.srcLoc(mod), | |
| 1376 | func_index, | |
| 1362 | 1377 | air, |
| 1363 | 1378 | liveness, |
| 1364 | 1379 | &code_writer, |
| ... | ... | @@ -1403,9 +1418,9 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi |
| 1403 | 1418 | defer tracy.end(); |
| 1404 | 1419 | |
| 1405 | 1420 | const decl = mod.declPtr(decl_index); |
| 1406 | if (decl.val.castTag(.function)) |_| { | |
| 1421 | if (decl.val.getFunction(mod)) |_| { | |
| 1407 | 1422 | return; |
| 1408 | } else if (decl.val.castTag(.extern_fn)) |_| { | |
| 1423 | } else if (decl.val.getExternFunc(mod)) |_| { | |
| 1409 | 1424 | return; |
| 1410 | 1425 | } |
| 1411 | 1426 | |
| ... | ... | @@ -1413,19 +1428,20 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi |
| 1413 | 1428 | const atom = wasm.getAtomPtr(atom_index); |
| 1414 | 1429 | atom.clear(); |
| 1415 | 1430 | |
| 1416 | if (decl.isExtern()) { | |
| 1417 | const variable = decl.getVariable().?; | |
| 1418 | const name = mem.sliceTo(decl.name, 0); | |
| 1419 | return wasm.addOrUpdateImport(name, atom.sym_index, variable.lib_name, null); | |
| 1431 | if (decl.isExtern(mod)) { | |
| 1432 | const variable = decl.getOwnedVariable(mod).?; | |
| 1433 | const name = mod.intern_pool.stringToSlice(decl.name); | |
| 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 | 1439 | var code_writer = std.ArrayList(u8).init(wasm.base.allocator); |
| 1424 | 1440 | defer code_writer.deinit(); |
| 1425 | 1441 | |
| 1426 | 1442 | const res = try codegen.generateSymbol( |
| 1427 | 1443 | &wasm.base, |
| 1428 | decl.srcLoc(), | |
| 1444 | decl.srcLoc(mod), | |
| 1429 | 1445 | .{ .ty = decl.ty, .val = val }, |
| 1430 | 1446 | &code_writer, |
| 1431 | 1447 | .none, |
| ... | ... | @@ -1451,8 +1467,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.I |
| 1451 | 1467 | defer tracy.end(); |
| 1452 | 1468 | |
| 1453 | 1469 | const decl = mod.declPtr(decl_index); |
| 1454 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 1455 | defer wasm.base.allocator.free(decl_name); | |
| 1470 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 1456 | 1471 | |
| 1457 | 1472 | log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); |
| 1458 | 1473 | try dw.updateDeclLineNumber(mod, decl_index); |
| ... | ... | @@ -1465,15 +1480,14 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 |
| 1465 | 1480 | const atom_index = wasm.decls.get(decl_index).?; |
| 1466 | 1481 | const atom = wasm.getAtomPtr(atom_index); |
| 1467 | 1482 | const symbol = &wasm.symbols.items[atom.sym_index]; |
| 1468 | const full_name = try decl.getFullyQualifiedName(mod); | |
| 1469 | defer wasm.base.allocator.free(full_name); | |
| 1483 | const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 1470 | 1484 | symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name); |
| 1471 | 1485 | try atom.code.appendSlice(wasm.base.allocator, code); |
| 1472 | 1486 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); |
| 1473 | 1487 | |
| 1474 | 1488 | atom.size = @intCast(u32, code.len); |
| 1475 | 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 | 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 | 1537 | /// Returns the symbol index of the local |
| 1524 | 1538 | /// The given `decl` is the parent decl whom owns the constant. |
| 1525 | 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 | 1540 | const mod = wasm.base.options.module.?; |
| 1541 | assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions | |
| 1529 | 1542 | const decl = mod.declPtr(decl_index); |
| 1530 | 1543 | |
| 1531 | 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 | 1547 | const parent_atom = wasm.getAtomPtr(parent_atom_index); |
| 1535 | 1548 | const local_index = parent_atom.locals.items.len; |
| 1536 | 1549 | try parent_atom.locals.append(wasm.base.allocator, atom_index); |
| 1537 | const fqdn = try decl.getFullyQualifiedName(mod); | |
| 1538 | defer wasm.base.allocator.free(fqdn); | |
| 1539 | const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index }); | |
| 1550 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 1551 | const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ | |
| 1552 | fqn, local_index, | |
| 1553 | }); | |
| 1540 | 1554 | defer wasm.base.allocator.free(name); |
| 1541 | 1555 | var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); |
| 1542 | 1556 | defer value_bytes.deinit(); |
| 1543 | 1557 | |
| 1544 | 1558 | const code = code: { |
| 1545 | 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 | 1561 | wasm.symbols.items[atom.sym_index] = .{ |
| 1548 | 1562 | .name = try wasm.string_table.put(wasm.base.allocator, name), |
| 1549 | 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 | 1569 | |
| 1556 | 1570 | const result = try codegen.generateSymbol( |
| 1557 | 1571 | &wasm.base, |
| 1558 | decl.srcLoc(), | |
| 1572 | decl.srcLoc(mod), | |
| 1559 | 1573 | tv, |
| 1560 | 1574 | &value_bytes, |
| 1561 | 1575 | .none, |
| ... | ... | @@ -1611,7 +1625,7 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u3 |
| 1611 | 1625 | wasm.symbols.items[sym_index] = symbol; |
| 1612 | 1626 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; |
| 1613 | 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 | 1629 | return sym_index; |
| 1616 | 1630 | } |
| 1617 | 1631 | |
| ... | ... | @@ -1632,7 +1646,7 @@ pub fn getDeclVAddr( |
| 1632 | 1646 | const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; |
| 1633 | 1647 | const atom = wasm.getAtomPtr(atom_index); |
| 1634 | 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 | 1650 | assert(reloc_info.addend == 0); // addend not allowed for function relocations |
| 1637 | 1651 | // We found a function pointer, so add it to our table, |
| 1638 | 1652 | // as function pointers are not allowed to be stored inside the data section. |
| ... | ... | @@ -1689,36 +1703,37 @@ pub fn updateDeclExports( |
| 1689 | 1703 | const decl = mod.declPtr(decl_index); |
| 1690 | 1704 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1691 | 1705 | const atom = wasm.getAtom(atom_index); |
| 1706 | const gpa = mod.gpa; | |
| 1692 | 1707 | |
| 1693 | 1708 | for (exports) |exp| { |
| 1694 | if (exp.options.section) |section| { | |
| 1695 | try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create( | |
| 1696 | mod.gpa, | |
| 1697 | decl.srcLoc(), | |
| 1709 | if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section| { | |
| 1710 | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( | |
| 1711 | gpa, | |
| 1712 | decl.srcLoc(mod), | |
| 1698 | 1713 | "Unimplemented: ExportOptions.section '{s}'", |
| 1699 | 1714 | .{section}, |
| 1700 | 1715 | )); |
| 1701 | 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 | 1720 | if (wasm.globals.getPtr(export_name)) |existing_loc| { |
| 1706 | 1721 | if (existing_loc.index == atom.sym_index) continue; |
| 1707 | 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 | 1725 | // When both the to-be-exported symbol and the already existing symbol |
| 1711 | 1726 | // are strong symbols, we have a linker error. |
| 1712 | 1727 | // In the other case we replace one with the other. |
| 1713 | 1728 | if (!exp_is_weak and !existing_sym.isWeak()) { |
| 1714 | try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( | |
| 1715 | mod.gpa, | |
| 1716 | decl.srcLoc(), | |
| 1717 | \\LinkError: symbol '{s}' defined multiple times | |
| 1729 | try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( | |
| 1730 | gpa, | |
| 1731 | decl.srcLoc(mod), | |
| 1732 | \\LinkError: symbol '{}' defined multiple times | |
| 1718 | 1733 | \\ first definition in '{s}' |
| 1719 | 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 | 1738 | continue; |
| 1724 | 1739 | } else if (exp_is_weak) { |
| ... | ... | @@ -1735,7 +1750,7 @@ pub fn updateDeclExports( |
| 1735 | 1750 | const exported_atom = wasm.getAtom(exported_atom_index); |
| 1736 | 1751 | const sym_loc = exported_atom.symbolLoc(); |
| 1737 | 1752 | const symbol = sym_loc.getSymbol(wasm); |
| 1738 | switch (exp.options.linkage) { | |
| 1753 | switch (exp.opts.linkage) { | |
| 1739 | 1754 | .Internal => { |
| 1740 | 1755 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 1741 | 1756 | }, |
| ... | ... | @@ -1744,9 +1759,9 @@ pub fn updateDeclExports( |
| 1744 | 1759 | }, |
| 1745 | 1760 | .Strong => {}, // symbols are strong by default |
| 1746 | 1761 | .LinkOnce => { |
| 1747 | try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create( | |
| 1748 | mod.gpa, | |
| 1749 | decl.srcLoc(), | |
| 1762 | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( | |
| 1763 | gpa, | |
| 1764 | decl.srcLoc(mod), | |
| 1750 | 1765 | "Unimplemented: LinkOnce", |
| 1751 | 1766 | .{}, |
| 1752 | 1767 | )); |
| ... | ... | @@ -1754,7 +1769,7 @@ pub fn updateDeclExports( |
| 1754 | 1769 | }, |
| 1755 | 1770 | } |
| 1756 | 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 | 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 | 1783 | |
| 1769 | 1784 | // if the symbol was previously undefined, remove it as an import |
| 1770 | 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 | 1807 | assert(wasm.symbol_atom.remove(local_atom.symbolLoc())); |
| 1793 | 1808 | } |
| 1794 | 1809 | |
| 1795 | if (decl.isExtern()) { | |
| 1810 | if (decl.isExtern(mod)) { | |
| 1796 | 1811 | _ = wasm.imports.remove(atom.symbolLoc()); |
| 1797 | 1812 | } |
| 1798 | 1813 | _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc()); |
| ... | ... | @@ -1853,7 +1868,7 @@ pub fn addOrUpdateImport( |
| 1853 | 1868 | /// Symbol index that is external |
| 1854 | 1869 | symbol_index: u32, |
| 1855 | 1870 | /// Optional library name (i.e. `extern "c" fn foo() void` |
| 1856 | lib_name: ?[*:0]const u8, | |
| 1871 | lib_name: ?[:0]const u8, | |
| 1857 | 1872 | /// The index of the type that represents the function signature |
| 1858 | 1873 | /// when the extern is a function. When this is null, a data-symbol |
| 1859 | 1874 | /// is asserted instead. |
| ... | ... | @@ -1864,7 +1879,7 @@ pub fn addOrUpdateImport( |
| 1864 | 1879 | // Also mangle the name when the lib name is set and not equal to "C" so imports with the same |
| 1865 | 1880 | // name but different module can be resolved correctly. |
| 1866 | 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 | 1883 | const full_name = if (mangle_name) full_name: { |
| 1869 | 1884 | break :full_name try std.fmt.allocPrint(wasm.base.allocator, "{s}|{s}", .{ name, lib_name.? }); |
| 1870 | 1885 | } else name; |
| ... | ... | @@ -1884,13 +1899,13 @@ pub fn addOrUpdateImport( |
| 1884 | 1899 | const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; |
| 1885 | 1900 | global_gop.value_ptr.* = loc; |
| 1886 | 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 | 1905 | if (type_index) |ty_index| { |
| 1891 | 1906 | const gop = try wasm.imports.getOrPut(wasm.base.allocator, .{ .index = symbol_index, .file = null }); |
| 1892 | 1907 | const module_name = if (lib_name) |l_name| blk: { |
| 1893 | break :blk mem.sliceTo(l_name, 0); | |
| 1908 | break :blk l_name; | |
| 1894 | 1909 | } else wasm.host_name; |
| 1895 | 1910 | if (!gop.found_existing) { |
| 1896 | 1911 | gop.value_ptr.* = .{ |
| ... | ... | @@ -2932,8 +2947,9 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { |
| 2932 | 2947 | |
| 2933 | 2948 | const atom_index = try wasm.createAtom(); |
| 2934 | 2949 | const atom = wasm.getAtomPtr(atom_index); |
| 2935 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | |
| 2936 | atom.alignment = slice_ty.abiAlignment(wasm.base.options.target); | |
| 2950 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 2951 | const mod = wasm.base.options.module.?; | |
| 2952 | atom.alignment = slice_ty.abiAlignment(mod); | |
| 2937 | 2953 | const sym_index = atom.sym_index; |
| 2938 | 2954 | |
| 2939 | 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 | 3001 | // Addend for each relocation to the table |
| 2986 | 3002 | var addend: u32 = 0; |
| 2987 | 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 | 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 | 3009 | const offset = @intCast(u32, atom.code.items.len); |
| 2993 | 3010 | // first we create the data for the slice of the name |
| 2994 | 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 | 3017 | .offset = offset, |
| 3001 | 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 | 3021 | addend += len; |
| 3005 | 3022 | |
| 3006 | 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 | 3383 | var decl_it = wasm.decls.iterator(); |
| 3367 | 3384 | while (decl_it.next()) |entry| { |
| 3368 | 3385 | const decl = mod.declPtr(entry.key_ptr.*); |
| 3369 | if (decl.isExtern()) continue; | |
| 3386 | if (decl.isExtern(mod)) continue; | |
| 3370 | 3387 | const atom_index = entry.value_ptr.*; |
| 3371 | 3388 | const atom = wasm.getAtomPtr(atom_index); |
| 3372 | if (decl.ty.zigTypeTag() == .Fn) { | |
| 3389 | if (decl.ty.zigTypeTag(mod) == .Fn) { | |
| 3373 | 3390 | try wasm.parseAtom(atom_index, .function); |
| 3374 | } else if (decl.getVariable()) |variable| { | |
| 3375 | if (!variable.is_mutable) { | |
| 3391 | } else if (decl.getOwnedVariable(mod)) |variable| { | |
| 3392 | if (variable.is_const) { | |
| 3376 | 3393 | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 3377 | } else if (variable.init.isUndefDeep()) { | |
| 3394 | } else if (variable.init.toValue().isUndefDeep(mod)) { | |
| 3378 | 3395 | // for safe build modes, we store the atom in the data segment, |
| 3379 | 3396 | // whereas for unsafe build modes we store it in bss. |
| 3380 | 3397 | const is_initialized = wasm.base.options.optimize_mode == .Debug or |
src/main.zig+5| ... | ... | @@ -569,6 +569,7 @@ const usage_build_generic = |
| 569 | 569 | \\ --verbose-link Display linker invocations |
| 570 | 570 | \\ --verbose-cc Display C compiler invocations |
| 571 | 571 | \\ --verbose-air Enable compiler debug output for Zig AIR |
| 572 | \\ --verbose-intern-pool Enable compiler debug output for InternPool | |
| 572 | 573 | \\ --verbose-llvm-ir[=path] Enable compiler debug output for unoptimized LLVM IR |
| 573 | 574 | \\ --verbose-llvm-bc=[path] Enable compiler debug output for unoptimized LLVM BC |
| 574 | 575 | \\ --verbose-cimport Enable compiler debug output for C imports |
| ... | ... | @@ -735,6 +736,7 @@ fn buildOutputType( |
| 735 | 736 | var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK"); |
| 736 | 737 | var verbose_cc = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_CC"); |
| 737 | 738 | var verbose_air = false; |
| 739 | var verbose_intern_pool = false; | |
| 738 | 740 | var verbose_llvm_ir: ?[]const u8 = null; |
| 739 | 741 | var verbose_llvm_bc: ?[]const u8 = null; |
| 740 | 742 | var verbose_cimport = false; |
| ... | ... | @@ -1460,6 +1462,8 @@ fn buildOutputType( |
| 1460 | 1462 | verbose_cc = true; |
| 1461 | 1463 | } else if (mem.eql(u8, arg, "--verbose-air")) { |
| 1462 | 1464 | verbose_air = true; |
| 1465 | } else if (mem.eql(u8, arg, "--verbose-intern-pool")) { | |
| 1466 | verbose_intern_pool = true; | |
| 1463 | 1467 | } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { |
| 1464 | 1468 | verbose_llvm_ir = "-"; |
| 1465 | 1469 | } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { |
| ... | ... | @@ -3156,6 +3160,7 @@ fn buildOutputType( |
| 3156 | 3160 | .verbose_cc = verbose_cc, |
| 3157 | 3161 | .verbose_link = verbose_link, |
| 3158 | 3162 | .verbose_air = verbose_air, |
| 3163 | .verbose_intern_pool = verbose_intern_pool, | |
| 3159 | 3164 | .verbose_llvm_ir = verbose_llvm_ir, |
| 3160 | 3165 | .verbose_llvm_bc = verbose_llvm_bc, |
| 3161 | 3166 | .verbose_cimport = verbose_cimport, |
src/print_air.zig+32-37| ... | ... | @@ -7,6 +7,7 @@ const Value = @import("value.zig").Value; |
| 7 | 7 | const Type = @import("type.zig").Type; |
| 8 | 8 | const Air = @import("Air.zig"); |
| 9 | 9 | const Liveness = @import("Liveness.zig"); |
| 10 | const InternPool = @import("InternPool.zig"); | |
| 10 | 11 | |
| 11 | 12 | pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) void { |
| 12 | 13 | const instruction_bytes = air.instructions.len * |
| ... | ... | @@ -14,12 +15,11 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo |
| 14 | 15 | // the debug safety tag but we want to measure release size. |
| 15 | 16 | (@sizeOf(Air.Inst.Tag) + 8); |
| 16 | 17 | const extra_bytes = air.extra.len * @sizeOf(u32); |
| 17 | const values_bytes = air.values.len * @sizeOf(Value); | |
| 18 | 18 | const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0; |
| 19 | 19 | const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0; |
| 20 | 20 | const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0; |
| 21 | 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 | 23 | liveness_special_bytes + tomb_bytes; |
| 24 | 24 | |
| 25 | 25 | // zig fmt: off |
| ... | ... | @@ -27,7 +27,6 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo |
| 27 | 27 | \\# Total AIR+Liveness bytes: {} |
| 28 | 28 | \\# AIR Instructions: {d} ({}) |
| 29 | 29 | \\# AIR Extra Data: {d} ({}) |
| 30 | \\# AIR Values Bytes: {d} ({}) | |
| 31 | 30 | \\# Liveness tomb_bits: {} |
| 32 | 31 | \\# Liveness Extra Data: {d} ({}) |
| 33 | 32 | \\# Liveness special table: {d} ({}) |
| ... | ... | @@ -36,7 +35,6 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo |
| 36 | 35 | fmtIntSizeBin(total_bytes), |
| 37 | 36 | air.instructions.len, fmtIntSizeBin(instruction_bytes), |
| 38 | 37 | air.extra.len, fmtIntSizeBin(extra_bytes), |
| 39 | air.values.len, fmtIntSizeBin(values_bytes), | |
| 40 | 38 | fmtIntSizeBin(tomb_bytes), |
| 41 | 39 | if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes), |
| 42 | 40 | if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes), |
| ... | ... | @@ -92,14 +90,10 @@ const Writer = struct { |
| 92 | 90 | |
| 93 | 91 | fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void { |
| 94 | 92 | for (w.air.instructions.items(.tag), 0..) |tag, i| { |
| 93 | if (tag != .interned) continue; | |
| 95 | 94 | const inst = @intCast(Air.Inst.Index, i); |
| 96 | switch (tag) { | |
| 97 | .constant, .const_ty => { | |
| 98 | try w.writeInst(s, inst); | |
| 99 | try s.writeByte('\n'); | |
| 100 | }, | |
| 101 | else => continue, | |
| 102 | } | |
| 95 | try w.writeInst(s, inst); | |
| 96 | try s.writeByte('\n'); | |
| 103 | 97 | } |
| 104 | 98 | } |
| 105 | 99 | |
| ... | ... | @@ -225,7 +219,6 @@ const Writer = struct { |
| 225 | 219 | .save_err_return_trace_index, |
| 226 | 220 | => try w.writeNoOp(s, inst), |
| 227 | 221 | |
| 228 | .const_ty, | |
| 229 | 222 | .alloc, |
| 230 | 223 | .ret_ptr, |
| 231 | 224 | .err_return_trace, |
| ... | ... | @@ -304,7 +297,9 @@ const Writer = struct { |
| 304 | 297 | |
| 305 | 298 | .struct_field_ptr => try w.writeStructField(s, inst), |
| 306 | 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 | 303 | .assembly => try w.writeAssembly(s, inst), |
| 309 | 304 | .dbg_stmt => try w.writeDbgStmt(s, inst), |
| 310 | 305 | |
| ... | ... | @@ -364,13 +359,7 @@ const Writer = struct { |
| 364 | 359 | } |
| 365 | 360 | |
| 366 | 361 | fn writeType(w: *Writer, s: anytype, ty: Type) !void { |
| 367 | const t = ty.tag(); | |
| 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 | } | |
| 362 | return ty.print(s, w.module); | |
| 374 | 363 | } |
| 375 | 364 | |
| 376 | 365 | fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| ... | ... | @@ -432,9 +421,10 @@ const Writer = struct { |
| 432 | 421 | } |
| 433 | 422 | |
| 434 | 423 | fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 424 | const mod = w.module; | |
| 435 | 425 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; |
| 436 | 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 | 428 | const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]); |
| 439 | 429 | |
| 440 | 430 | try w.writeType(s, vector_ty); |
| ... | ... | @@ -511,10 +501,11 @@ const Writer = struct { |
| 511 | 501 | } |
| 512 | 502 | |
| 513 | 503 | fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 504 | const mod = w.module; | |
| 514 | 505 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 515 | 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 | 509 | try w.writeType(s, elem_ty); |
| 519 | 510 | try s.writeAll(", "); |
| 520 | 511 | try w.writeOperand(s, inst, 0, pl_op.operand); |
| ... | ... | @@ -605,12 +596,12 @@ const Writer = struct { |
| 605 | 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 { | |
| 609 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; | |
| 610 | const val = w.air.values[ty_pl.payload]; | |
| 611 | const ty = w.air.getRefType(ty_pl.ty); | |
| 599 | fn writeInterned(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | |
| 600 | const mod = w.module; | |
| 601 | const ip_index = w.air.instructions.items(.data)[inst].interned; | |
| 602 | const ty = mod.intern_pool.indexToKey(ip_index).typeOf().toType(); | |
| 612 | 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 | 607 | fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| ... | ... | @@ -621,7 +612,7 @@ const Writer = struct { |
| 621 | 612 | var extra_i: usize = extra.end; |
| 622 | 613 | var op_index: usize = 0; |
| 623 | 614 | |
| 624 | const ret_ty = w.air.typeOfIndex(inst); | |
| 615 | const ret_ty = w.typeOfIndex(inst); | |
| 625 | 616 | try w.writeType(s, ret_ty); |
| 626 | 617 | |
| 627 | 618 | if (is_volatile) { |
| ... | ... | @@ -692,17 +683,17 @@ const Writer = struct { |
| 692 | 683 | } |
| 693 | 684 | |
| 694 | 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; | |
| 696 | const function = w.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 697 | const owner_decl = w.module.declPtr(function.owner_decl); | |
| 698 | try s.print("{s}", .{owner_decl.name}); | |
| 686 | const ty_fn = w.air.instructions.items(.data)[inst].ty_fn; | |
| 687 | const func_index = ty_fn.func; | |
| 688 | const owner_decl = w.module.declPtr(w.module.funcPtr(func_index).owner_decl); | |
| 689 | try s.print("{}", .{owner_decl.name.fmt(&w.module.intern_pool)}); | |
| 699 | 690 | } |
| 700 | 691 | |
| 701 | 692 | fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 702 | 693 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 703 | 694 | try w.writeOperand(s, inst, 0, pl_op.operand); |
| 704 | 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 | 699 | fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| ... | ... | @@ -965,14 +956,13 @@ const Writer = struct { |
| 965 | 956 | operand: Air.Inst.Ref, |
| 966 | 957 | dies: bool, |
| 967 | 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 | 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 | 968 | fn writeInstIndex( |
| ... | ... | @@ -985,4 +975,9 @@ const Writer = struct { |
| 985 | 975 | try s.print("%{d}", .{inst}); |
| 986 | 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 | 3 | const Allocator = std.mem.Allocator; |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | const Ast = std.zig.Ast; |
| 6 | const InternPool = @import("InternPool.zig"); | |
| 6 | 7 | |
| 7 | 8 | const Zir = @import("Zir.zig"); |
| 8 | 9 | const Module = @import("Module.zig"); |
| ... | ... | @@ -1191,7 +1192,7 @@ const Writer = struct { |
| 1191 | 1192 | .field => { |
| 1192 | 1193 | const field_name = self.code.nullTerminatedString(extra.data.field_name_start); |
| 1193 | 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 | 1198 | try stream.writeAll(", ["); |
| ... | ... | @@ -2468,14 +2469,9 @@ const Writer = struct { |
| 2468 | 2469 | } |
| 2469 | 2470 | |
| 2470 | 2471 | fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void { |
| 2471 | var i: usize = @enumToInt(ref); | |
| 2472 | ||
| 2473 | if (i < Zir.Inst.Ref.typed_value_map.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)); | |
| 2472 | const i = @enumToInt(ref); | |
| 2473 | if (i < InternPool.static_len) return stream.print("@{}", .{@intToEnum(InternPool.Index, i)}); | |
| 2474 | return self.writeInstIndex(stream, i - InternPool.static_len); | |
| 2479 | 2475 | } |
| 2480 | 2476 | |
| 2481 | 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 | 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 | 515 | pub fn defaultAddressSpace( |
| 644 | 516 | target: std.Target, |
| 645 | 517 | context: enum { |
| ... | ... | @@ -777,3 +649,14 @@ pub fn compilerRtIntAbbrev(bits: u16) []const u8 { |
| 777 | 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 | 9 | const target_util = @import("target.zig"); |
| 10 | 10 | const TypedValue = @import("TypedValue.zig"); |
| 11 | 11 | const Sema = @import("Sema.zig"); |
| 12 | const InternPool = @import("InternPool.zig"); | |
| 12 | 13 | |
| 13 | const file_struct = @This(); | |
| 14 | ||
| 15 | /// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication. | |
| 16 | /// It's important for this type to be small. | |
| 17 | /// Types are not de-duplicated, which helps with multi-threading since it obviates the requirement | |
| 18 | /// of obtaining a lock on a global type table, as well as making the | |
| 19 | /// garbage collection bookkeeping simpler. | |
| 20 | /// This union takes advantage of the fact that the first page of memory | |
| 21 | /// is unmapped, giving us 4096 possible enum tags that have no payload. | |
| 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 | } | |
| 14 | /// Both types and values are canonically represented by a single 32-bit integer | |
| 15 | /// which is an index into an `InternPool` data structure. | |
| 16 | /// This struct abstracts around this storage by providing methods only | |
| 17 | /// applicable to types rather than values in general. | |
| 18 | pub const Type = struct { | |
| 19 | ip_index: InternPool.Index, | |
| 20 | ||
| 21 | pub fn zigTypeTag(ty: Type, mod: *const Module) std.builtin.TypeId { | |
| 22 | return ty.zigTypeTagOrPoison(mod) catch unreachable; | |
| 160 | 23 | } |
| 161 | 24 | |
| 162 | pub fn baseZigTypeTag(self: Type) std.builtin.TypeId { | |
| 163 | return switch (self.zigTypeTag()) { | |
| 164 | .ErrorUnion => self.errorUnionPayload().baseZigTypeTag(), | |
| 25 | pub fn zigTypeTagOrPoison(ty: Type, mod: *const Module) error{GenericPoison}!std.builtin.TypeId { | |
| 26 | return mod.intern_pool.zigTypeTagOrPoison(ty.toIntern()); | |
| 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 | 32 | .Optional => { |
| 166 | var buf: Payload.ElemType = undefined; | |
| 167 | return self.optionalChild(&buf).baseZigTypeTag(); | |
| 33 | return self.optionalChild(mod).baseZigTypeTag(mod); | |
| 168 | 34 | }, |
| 169 | 35 | else => |t| t, |
| 170 | 36 | }; |
| 171 | 37 | } |
| 172 | 38 | |
| 173 | pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool { | |
| 174 | return switch (ty.zigTypeTag()) { | |
| 39 | pub fn isSelfComparable(ty: Type, mod: *const Module, is_equality_cmp: bool) bool { | |
| 40 | return switch (ty.zigTypeTag(mod)) { | |
| 175 | 41 | .Int, |
| 176 | 42 | .Float, |
| 177 | 43 | .ComptimeFloat, |
| 178 | 44 | .ComptimeInt, |
| 179 | 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 | 49 | .Bool, |
| 184 | 50 | .Type, |
| ... | ... | @@ -201,1317 +67,70 @@ pub const Type = extern union { |
| 201 | 67 | .Frame, |
| 202 | 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 | 71 | .Optional => { |
| 206 | 72 | if (!is_equality_cmp) return false; |
| 207 | var buf: Payload.ElemType = undefined; | |
| 208 | return ty.optionalChild(&buf).isSelfComparable(is_equality_cmp); | |
| 73 | return ty.optionalChild(mod).isSelfComparable(mod, 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 | 78 | /// If it is a function pointer, returns the function type. Otherwise returns null. |
| 288 | pub fn castPtrToFn(ty: Type) ?Type { | |
| 289 | if (ty.zigTypeTag() != .Pointer) return null; | |
| 290 | const elem_ty = ty.childType(); | |
| 291 | if (elem_ty.zigTypeTag() != .Fn) return null; | |
| 79 | pub fn castPtrToFn(ty: Type, mod: *const Module) ?Type { | |
| 80 | if (ty.zigTypeTag(mod) != .Pointer) return null; | |
| 81 | const elem_ty = ty.childType(mod); | |
| 82 | if (elem_ty.zigTypeTag(mod) != .Fn) return null; | |
| 292 | 83 | return elem_ty; |
| 293 | 84 | } |
| 294 | 85 | |
| 295 | pub fn ptrIsMutable(ty: Type) bool { | |
| 296 | return switch (ty.tag()) { | |
| 297 | .single_const_pointer_to_comptime_int, | |
| 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 | }; | |
| 86 | /// Asserts the type is a pointer. | |
| 87 | pub fn ptrIsMutable(ty: Type, mod: *const Module) bool { | |
| 88 | return !mod.intern_pool.indexToKey(ty.toIntern()).ptr_type.flags.is_const; | |
| 328 | 89 | } |
| 329 | 90 | |
| 330 | pub fn ptrInfo(self: Type) Payload.Pointer { | |
| 331 | switch (self.tag()) { | |
| 332 | .single_const_pointer_to_comptime_int => return .{ .data = .{ | |
| 333 | .pointee_type = Type.initTag(.comptime_int), | |
| 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 | } | |
| 91 | pub const ArrayInfo = struct { | |
| 92 | elem_type: Type, | |
| 93 | sentinel: ?Value = null, | |
| 94 | len: u64, | |
| 1275 | 95 | }; |
| 1276 | ||
| 1277 | pub fn copy(self: Type, allocator: Allocator) error{OutOfMemory}!Type { | |
| 1278 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | |
| 1279 | return Type{ .tag_if_small_enough = self.tag_if_small_enough }; | |
| 1280 | } else switch (self.ptr_otherwise.tag) { | |
| 1281 | .u1, | |
| 1282 | .u8, | |
| 1283 | .i8, | |
| 1284 | .u16, | |
| 1285 | .i16, | |
| 1286 | .u29, | |
| 1287 | .u32, | |
| 1288 | .i32, | |
| 1289 | .u64, | |
| 1290 | .i64, | |
| 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); | |
| 96 | ||
| 97 | pub fn arrayInfo(self: Type, mod: *const Module) ArrayInfo { | |
| 98 | return .{ | |
| 99 | .len = self.arrayLen(mod), | |
| 100 | .sentinel = self.sentinel(mod), | |
| 101 | .elem_type = self.childType(mod), | |
| 102 | }; | |
| 103 | } | |
| 104 | ||
| 105 | pub fn ptrInfoIp(ip: *const InternPool, ty: InternPool.Index) InternPool.Key.PtrType { | |
| 106 | return switch (ip.indexToKey(ty)) { | |
| 107 | .ptr_type => |p| p, | |
| 108 | .opt_type => |child| switch (ip.indexToKey(child)) { | |
| 109 | .ptr_type => |p| p, | |
| 110 | else => unreachable, | |
| 1496 | 111 | }, |
| 1497 | .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), | |
| 1498 | .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred), | |
| 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 | } | |
| 112 | else => unreachable, | |
| 113 | }; | |
| 1508 | 114 | } |
| 1509 | 115 | |
| 1510 | fn copyPayloadShallow(self: Type, allocator: Allocator, comptime T: type) error{OutOfMemory}!Type { | |
| 1511 | const payload = self.cast(T).?; | |
| 1512 | const new_payload = try allocator.create(T); | |
| 1513 | new_payload.* = payload.*; | |
| 1514 | return Type{ .ptr_otherwise = &new_payload.base }; | |
| 116 | pub fn ptrInfo(ty: Type, mod: *const Module) Payload.Pointer.Data { | |
| 117 | return Payload.Pointer.Data.fromKey(ptrInfoIp(&mod.intern_pool, ty.toIntern())); | |
| 118 | } | |
| 119 | ||
| 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 | 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 | 169 | } |
| 1551 | 170 | |
| 1552 | 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 | 173 | pub fn dump( |
| 1555 | 174 | start_type: Type, |
| 1556 | 175 | comptime unused_format_string: []const u8, |
| ... | ... | @@ -1559,372 +178,7 @@ pub const Type = extern union { |
| 1559 | 178 | ) @TypeOf(writer).Error!void { |
| 1560 | 179 | _ = options; |
| 1561 | 180 | comptime assert(unused_format_string.len == 0); |
| 1562 | if (true) { | |
| 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 | } | |
| 181 | return writer.print("{any}", .{start_type.ip_index}); | |
| 1928 | 182 | } |
| 1929 | 183 | |
| 1930 | 184 | pub const nameAllocArena = nameAlloc; |
| ... | ... | @@ -1938,253 +192,16 @@ pub const Type = extern union { |
| 1938 | 192 | |
| 1939 | 193 | /// Prints a name suitable for `@typeName`. |
| 1940 | 194 | pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void { |
| 1941 | const t = ty.tag(); | |
| 1942 | switch (t) { | |
| 1943 | .inferred_alloc_const => unreachable, | |
| 1944 | .inferred_alloc_mut => unreachable, | |
| 1945 | .generic_poison => unreachable, | |
| 1946 | ||
| 1947 | // TODO get rid of these Type.Tag values. | |
| 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("}"); | |
| 195 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 196 | .int_type => |int_type| { | |
| 197 | const sign_char: u8 = switch (int_type.signedness) { | |
| 198 | .signed => 'i', | |
| 199 | .unsigned => 'u', | |
| 200 | }; | |
| 201 | return writer.print("{c}{d}", .{ sign_char, int_type.bits }); | |
| 2175 | 202 | }, |
| 2176 | ||
| 2177 | .pointer, | |
| 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; | |
| 203 | .ptr_type => { | |
| 204 | const info = ty.ptrInfo(mod); | |
| 2188 | 205 | |
| 2189 | 206 | if (info.sentinel) |s| switch (info.size) { |
| 2190 | 207 | .One, .C => unreachable, |
| ... | ... | @@ -2200,7 +217,7 @@ pub const Type = extern union { |
| 2200 | 217 | if (info.@"align" != 0) { |
| 2201 | 218 | try writer.print("align({d}", .{info.@"align"}); |
| 2202 | 219 | } else { |
| 2203 | const alignment = info.pointee_type.abiAlignment(mod.getTarget()); | |
| 220 | const alignment = info.pointee_type.abiAlignment(mod); | |
| 2204 | 221 | try writer.print("align({d}", .{alignment}); |
| 2205 | 222 | } |
| 2206 | 223 | |
| ... | ... | @@ -2222,127 +239,228 @@ pub const Type = extern union { |
| 2222 | 239 | if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero "); |
| 2223 | 240 | |
| 2224 | 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 => { | |
| 2228 | const bits = ty.castTag(.int_signed).?.data; | |
| 2229 | return writer.print("i{d}", .{bits}); | |
| 2230 | }, | |
| 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); | |
| 372 | .union_type => |union_type| { | |
| 373 | const union_obj = mod.unionPtr(union_type.index); | |
| 374 | const decl = mod.declPtr(union_obj.owner_decl); | |
| 375 | try decl.renderFullyQualifiedName(mod, writer); | |
| 2244 | 376 | }, |
| 2245 | .optional_single_const_pointer => { | |
| 2246 | const pointee_type = ty.castTag(.optional_single_const_pointer).?.data; | |
| 2247 | try writer.writeAll("?*const "); | |
| 2248 | try print(pointee_type, writer, mod); | |
| 377 | .opaque_type => |opaque_type| { | |
| 378 | const decl = mod.declPtr(opaque_type.decl); | |
| 379 | try decl.renderFullyQualifiedName(mod, writer); | |
| 2249 | 380 | }, |
| 2250 | .anyframe_T => { | |
| 2251 | const return_type = ty.castTag(.anyframe_T).?.data; | |
| 2252 | try writer.print("anyframe->", .{}); | |
| 2253 | try print(return_type, writer, mod); | |
| 381 | .enum_type => |enum_type| { | |
| 382 | const decl = mod.declPtr(enum_type.decl); | |
| 383 | try decl.renderFullyQualifiedName(mod, writer); | |
| 2254 | 384 | }, |
| 2255 | .error_set => { | |
| 2256 | const names = ty.castTag(.error_set).?.data.names.keys(); | |
| 2257 | try writer.writeAll("error{"); | |
| 2258 | for (names, 0..) |name, i| { | |
| 2259 | if (i != 0) try writer.writeByte(','); | |
| 2260 | try writer.writeAll(name); | |
| 385 | .func_type => |fn_info| { | |
| 386 | if (fn_info.is_noinline) { | |
| 387 | try writer.writeAll("noinline "); | |
| 2261 | 388 | } |
| 2262 | try writer.writeAll("}"); | |
| 2263 | }, | |
| 2264 | .error_set_single => { | |
| 2265 | const name = ty.castTag(.error_set_single).?.data; | |
| 2266 | return writer.print("error{{{s}}}", .{name}); | |
| 2267 | }, | |
| 2268 | .error_set_merged => { | |
| 2269 | const names = ty.castTag(.error_set_merged).?.data.keys(); | |
| 2270 | try writer.writeAll("error{"); | |
| 2271 | for (names, 0..) |name, i| { | |
| 2272 | if (i != 0) try writer.writeByte(','); | |
| 2273 | try writer.writeAll(name); | |
| 389 | try writer.writeAll("fn("); | |
| 390 | for (fn_info.param_types, 0..) |param_ty, i| { | |
| 391 | if (i != 0) try writer.writeAll(", "); | |
| 392 | if (std.math.cast(u5, i)) |index| { | |
| 393 | if (fn_info.paramIsComptime(index)) { | |
| 394 | try writer.writeAll("comptime "); | |
| 395 | } | |
| 396 | if (fn_info.paramIsNoalias(index)) { | |
| 397 | try writer.writeAll("noalias "); | |
| 398 | } | |
| 399 | } | |
| 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 { | |
| 2281 | switch (self.tag()) { | |
| 2282 | .u1 => return Value.initTag(.u1_type), | |
| 2283 | .u8 => return Value.initTag(.u8_type), | |
| 2284 | .i8 => return Value.initTag(.i8_type), | |
| 2285 | .u16 => return Value.initTag(.u16_type), | |
| 2286 | .u29 => return Value.initTag(.u29_type), | |
| 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 | } | |
| 457 | pub fn toIntern(ty: Type) InternPool.Index { | |
| 458 | assert(ty.ip_index != .none); | |
| 459 | return ty.ip_index; | |
| 460 | } | |
| 461 | ||
| 462 | pub fn toValue(self: Type) Value { | |
| 463 | return self.toIntern().toValue(); | |
| 2346 | 464 | } |
| 2347 | 465 | |
| 2348 | 466 | const RuntimeBitsError = Module.CompileError || error{NeedLazy}; |
| ... | ... | @@ -2360,365 +478,319 @@ pub const Type = extern union { |
| 2360 | 478 | /// may return false positives. |
| 2361 | 479 | pub fn hasRuntimeBitsAdvanced( |
| 2362 | 480 | ty: Type, |
| 481 | mod: *Module, | |
| 2363 | 482 | ignore_comptime_only: bool, |
| 2364 | 483 | strat: AbiAlignmentAdvancedStrat, |
| 2365 | 484 | ) RuntimeBitsError!bool { |
| 2366 | switch (ty.tag()) { | |
| 2367 | .u1, | |
| 2368 | .u8, | |
| 2369 | .i8, | |
| 2370 | .u16, | |
| 2371 | .i16, | |
| 2372 | .u29, | |
| 2373 | .u32, | |
| 2374 | .i32, | |
| 2375 | .u64, | |
| 2376 | .i64, | |
| 2377 | .u128, | |
| 2378 | .i128, | |
| 2379 | .usize, | |
| 2380 | .isize, | |
| 2381 | .c_char, | |
| 2382 | .c_short, | |
| 2383 | .c_ushort, | |
| 2384 | .c_int, | |
| 2385 | .c_uint, | |
| 2386 | .c_long, | |
| 2387 | .c_ulong, | |
| 2388 | .c_longlong, | |
| 2389 | .c_ulonglong, | |
| 2390 | .c_longdouble, | |
| 2391 | .f16, | |
| 2392 | .f32, | |
| 2393 | .f64, | |
| 2394 | .f80, | |
| 2395 | .f128, | |
| 2396 | .bool, | |
| 2397 | .anyerror, | |
| 2398 | .const_slice_u8, | |
| 2399 | .const_slice_u8_sentinel_0, | |
| 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)) | |
| 485 | return switch (ty.toIntern()) { | |
| 486 | // False because it is a comptime-only type. | |
| 487 | .empty_struct_type => false, | |
| 488 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 489 | .int_type => |int_type| int_type.bits != 0, | |
| 490 | .ptr_type => |ptr_type| { | |
| 491 | // Pointers to zero-bit types still have a runtime address; however, pointers | |
| 492 | // to comptime-only types do not, with the exception of function pointers. | |
| 493 | if (ignore_comptime_only) return true; | |
| 494 | const child_ty = ptr_type.child.toType(); | |
| 495 | if (child_ty.zigTypeTag(mod) == .Fn) return !mod.typeToFunc(child_ty).?.is_generic; | |
| 496 | if (strat == .sema) return !(try strat.sema.typeRequiresComptime(ty)); | |
| 497 | return !comptimeOnly(ty, mod); | |
| 498 | }, | |
| 499 | .anyframe_type => true, | |
| 500 | .array_type => |array_type| { | |
| 501 | if (array_type.sentinel != .none) { | |
| 502 | return array_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); | |
| 503 | } else { | |
| 504 | return array_type.len > 0 and | |
| 505 | try array_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); | |
| 506 | } | |
| 507 | }, | |
| 508 | .vector_type => |vector_type| { | |
| 509 | return vector_type.len > 0 and | |
| 510 | try vector_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); | |
| 511 | }, | |
| 512 | .opt_type => |child| { | |
| 513 | const child_ty = child.toType(); | |
| 514 | if (child_ty.isNoReturn(mod)) { | |
| 515 | // Then the optional is comptime-known to be null. | |
| 516 | return false; | |
| 517 | } | |
| 518 | if (ignore_comptime_only) { | |
| 2541 | 519 | return true; |
| 2542 | } else { | |
| 2543 | return false; | |
| 2544 | } | |
| 2545 | }, | |
| 2546 | .union_safety_tagged, .union_tagged => { | |
| 2547 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 2548 | if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) { | |
| 2549 | return true; | |
| 2550 | } | |
| 2551 | ||
| 2552 | switch (strat) { | |
| 2553 | .sema => |sema| _ = try sema.resolveTypeFields(ty), | |
| 2554 | .eager => assert(union_obj.haveFieldTypes()), | |
| 2555 | .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, | |
| 2556 | } | |
| 2557 | for (union_obj.fields.values()) |value| { | |
| 2558 | if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) | |
| 520 | } else if (strat == .sema) { | |
| 521 | return !(try strat.sema.typeRequiresComptime(child_ty)); | |
| 522 | } else { | |
| 523 | return !comptimeOnly(child_ty, mod); | |
| 524 | } | |
| 525 | }, | |
| 526 | .error_union_type, | |
| 527 | .error_set_type, | |
| 528 | .inferred_error_set_type, | |
| 529 | => true, | |
| 530 | ||
| 531 | // These are function *bodies*, not pointers. | |
| 532 | // They return false here because they are comptime-only types. | |
| 533 | // Special exceptions have to be made when emitting functions due to | |
| 534 | // this returning false. | |
| 535 | .func_type => false, | |
| 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 | 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 | 613 | return false; |
| 2562 | } | |
| 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), | |
| 614 | }, | |
| 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 => { | |
| 2573 | const tuple = ty.tupleFields(); | |
| 2574 | for (tuple.types, 0..) |field_ty, i| { | |
| 2575 | const val = tuple.values[i]; | |
| 2576 | if (val.tag() != .unreachable_value) continue; // comptime field | |
| 2577 | if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true; | |
| 2578 | } | |
| 2579 | return false; | |
| 646 | .opaque_type => true, | |
| 647 | .enum_type => |enum_type| enum_type.tag_ty.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat), | |
| 648 | ||
| 649 | // values, not types | |
| 650 | .undef, | |
| 651 | .runtime_value, | |
| 652 | .simple_value, | |
| 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 | ||
| 2582 | .inferred_alloc_const => unreachable, | |
| 2583 | .inferred_alloc_mut => unreachable, | |
| 2584 | .generic_poison => unreachable, | |
| 2585 | } | |
| 671 | }; | |
| 2586 | 672 | } |
| 2587 | 673 | |
| 2588 | 674 | /// true if and only if the type has a well-defined memory layout |
| 2589 | 675 | /// readFrom/writeToMemory are supported only for types with a well- |
| 2590 | 676 | /// defined memory layout |
| 2591 | pub fn hasWellDefinedLayout(ty: Type) bool { | |
| 2592 | return switch (ty.tag()) { | |
| 2593 | .u1, | |
| 2594 | .u8, | |
| 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, | |
| 677 | pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool { | |
| 678 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 679 | .int_type, | |
| 680 | .vector_type, | |
| 2643 | 681 | => true, |
| 2644 | 682 | |
| 2645 | .anyopaque, | |
| 2646 | .anyerror, | |
| 2647 | .noreturn, | |
| 2648 | .null, | |
| 2649 | .@"anyframe", | |
| 2650 | .undefined, | |
| 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, | |
| 683 | .error_union_type, | |
| 684 | .error_set_type, | |
| 685 | .inferred_error_set_type, | |
| 686 | .anon_struct_type, | |
| 687 | .opaque_type, | |
| 688 | .anyframe_type, | |
| 2672 | 689 | // These are function bodies, not function pointers. |
| 2673 | .fn_noreturn_no_args, | |
| 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, | |
| 690 | .func_type, | |
| 2690 | 691 | => false, |
| 2691 | 692 | |
| 2692 | .enum_full, | |
| 2693 | .enum_nonexhaustive, | |
| 2694 | => !ty.cast(Payload.EnumFull).?.data.tag_ty_inferred, | |
| 2695 | ||
| 2696 | .inferred_alloc_mut => unreachable, | |
| 2697 | .inferred_alloc_const => unreachable, | |
| 693 | .array_type => |array_type| array_type.child.toType().hasWellDefinedLayout(mod), | |
| 694 | .opt_type => ty.isPtrLikeOptional(mod), | |
| 695 | .ptr_type => |ptr_type| ptr_type.flags.size != .Slice, | |
| 2698 | 696 | |
| 2699 | .array, | |
| 2700 | .array_sentinel, | |
| 2701 | => ty.childType().hasWellDefinedLayout(), | |
| 697 | .simple_type => |t| switch (t) { | |
| 698 | .f16, | |
| 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(), | |
| 2704 | .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto, | |
| 2705 | .@"union", .union_safety_tagged => ty.cast(Payload.Union).?.data.layout != .Auto, | |
| 2706 | .union_tagged => false, | |
| 719 | .anyerror, | |
| 720 | .anyopaque, | |
| 721 | .atomic_order, | |
| 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 { | |
| 2711 | return hasRuntimeBitsAdvanced(ty, false, .eager) catch unreachable; | |
| 782 | pub fn hasRuntimeBits(ty: Type, mod: *Module) bool { | |
| 783 | return hasRuntimeBitsAdvanced(ty, mod, false, .eager) catch unreachable; | |
| 2712 | 784 | } |
| 2713 | 785 | |
| 2714 | pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool { | |
| 2715 | return hasRuntimeBitsAdvanced(ty, true, .eager) catch unreachable; | |
| 786 | pub fn hasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool { | |
| 787 | return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable; | |
| 2716 | 788 | } |
| 2717 | 789 | |
| 2718 | pub fn isFnOrHasRuntimeBits(ty: Type) bool { | |
| 2719 | switch (ty.zigTypeTag()) { | |
| 790 | pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool { | |
| 791 | switch (ty.zigTypeTag(mod)) { | |
| 2720 | 792 | .Fn => { |
| 2721 | const fn_info = ty.fnInfo(); | |
| 793 | const fn_info = mod.typeToFunc(ty).?; | |
| 2722 | 794 | if (fn_info.is_generic) return false; |
| 2723 | 795 | if (fn_info.is_var_args) return true; |
| 2724 | 796 | switch (fn_info.cc) { |
| ... | ... | @@ -2727,131 +799,66 @@ pub const Type = extern union { |
| 2727 | 799 | .Inline => return false, |
| 2728 | 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 | 803 | return true; |
| 2732 | 804 | }, |
| 2733 | else => return ty.hasRuntimeBits(), | |
| 805 | else => return ty.hasRuntimeBits(mod), | |
| 2734 | 806 | } |
| 2735 | 807 | } |
| 2736 | 808 | |
| 2737 | 809 | /// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive. |
| 2738 | pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type) bool { | |
| 2739 | return switch (ty.zigTypeTag()) { | |
| 810 | pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool { | |
| 811 | return switch (ty.zigTypeTag(mod)) { | |
| 2740 | 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 | |
| 2746 | pub fn isNoReturn(ty: Type) bool { | |
| 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 | } | |
| 817 | pub fn isNoReturn(ty: Type, mod: *Module) bool { | |
| 818 | return mod.intern_pool.isNoReturn(ty.toIntern()); | |
| 2761 | 819 | } |
| 2762 | 820 | |
| 2763 | 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 { | |
| 2765 | return ptrAlignmentAdvanced(ty, target, null) catch unreachable; | |
| 2766 | } | |
| 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 | }, | |
| 822 | pub fn ptrAlignment(ty: Type, mod: *Module) u32 { | |
| 823 | return ptrAlignmentAdvanced(ty, mod, null) catch unreachable; | |
| 824 | } | |
| 2788 | 825 | |
| 2789 | .manyptr_u8, | |
| 2790 | .manyptr_const_u8, | |
| 2791 | .manyptr_const_u8_sentinel_0, | |
| 2792 | .const_slice_u8, | |
| 2793 | .const_slice_u8_sentinel_0, | |
| 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"; | |
| 826 | pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !u32 { | |
| 827 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 828 | .ptr_type => |ptr_type| { | |
| 829 | if (ptr_type.flags.alignment.toByteUnitsOptional()) |a| { | |
| 830 | return @intCast(u32, a); | |
| 2800 | 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 | 833 | return res.scalar; |
| 2803 | 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), | |
| 2808 | ||
| 838 | .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema), | |
| 2809 | 839 | else => unreachable, |
| 2810 | } | |
| 840 | }; | |
| 2811 | 841 | } |
| 2812 | 842 | |
| 2813 | pub fn ptrAddressSpace(self: Type) std.builtin.AddressSpace { | |
| 2814 | return switch (self.tag()) { | |
| 2815 | .single_const_pointer_to_comptime_int, | |
| 2816 | .const_slice_u8, | |
| 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 | ||
| 843 | pub fn ptrAddressSpace(ty: Type, mod: *const Module) std.builtin.AddressSpace { | |
| 844 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 845 | .ptr_type => |ptr_type| ptr_type.flags.address_space, | |
| 846 | .opt_type => |child| mod.intern_pool.indexToKey(child).ptr_type.flags.address_space, | |
| 2841 | 847 | else => unreachable, |
| 2842 | 848 | }; |
| 2843 | 849 | } |
| 2844 | 850 | |
| 2845 | 851 | /// Returns 0 for 0-bit types. |
| 2846 | pub fn abiAlignment(ty: Type, target: Target) u32 { | |
| 2847 | return (ty.abiAlignmentAdvanced(target, .eager) catch unreachable).scalar; | |
| 852 | pub fn abiAlignment(ty: Type, mod: *Module) u32 { | |
| 853 | return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; | |
| 2848 | 854 | } |
| 2849 | 855 | |
| 2850 | 856 | /// May capture a reference to `ty`. |
| 2851 | pub fn lazyAbiAlignment(ty: Type, target: Target, arena: Allocator) !Value { | |
| 2852 | switch (try ty.abiAlignmentAdvanced(target, .{ .lazy = arena })) { | |
| 857 | /// Returned value has type `comptime_int`. | |
| 858 | pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value { | |
| 859 | switch (try ty.abiAlignmentAdvanced(mod, .lazy)) { | |
| 2853 | 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 | 869 | |
| 2863 | 870 | pub const AbiAlignmentAdvancedStrat = union(enum) { |
| 2864 | 871 | eager, |
| 2865 | lazy: Allocator, | |
| 872 | lazy, | |
| 2866 | 873 | sema: *Sema, |
| 2867 | 874 | }; |
| 2868 | 875 | |
| ... | ... | @@ -2874,314 +881,322 @@ pub const Type = extern union { |
| 2874 | 881 | /// necessary, possibly returning a CompileError. |
| 2875 | 882 | pub fn abiAlignmentAdvanced( |
| 2876 | 883 | ty: Type, |
| 2877 | target: Target, | |
| 884 | mod: *Module, | |
| 2878 | 885 | strat: AbiAlignmentAdvancedStrat, |
| 2879 | 886 | ) Module.CompileError!AbiAlignmentAdvanced { |
| 887 | const target = mod.getTarget(); | |
| 888 | ||
| 2880 | 889 | const opt_sema = switch (strat) { |
| 2881 | 890 | .sema => |sema| sema, |
| 2882 | 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, | |
| 2919 | .usize, | |
| 2920 | .single_const_pointer_to_comptime_int, | |
| 2921 | .const_slice_u8, | |
| 2922 | .const_slice_u8_sentinel_0, | |
| 2923 | .single_const_pointer, | |
| 2924 | .single_mut_pointer, | |
| 2925 | .many_const_pointer, | |
| 2926 | .many_mut_pointer, | |
| 2927 | .c_const_pointer, | |
| 2928 | .c_mut_pointer, | |
| 2929 | .const_slice, | |
| 2930 | .mut_slice, | |
| 2931 | .optional_single_const_pointer, | |
| 2932 | .optional_single_mut_pointer, | |
| 2933 | .pointer, | |
| 2934 | .manyptr_u8, | |
| 2935 | .manyptr_const_u8, | |
| 2936 | .manyptr_const_u8_sentinel_0, | |
| 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) }; | |
| 894 | switch (ty.toIntern()) { | |
| 895 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 }, | |
| 896 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 897 | .int_type => |int_type| { | |
| 898 | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; | |
| 899 | return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) }; | |
| 900 | }, | |
| 901 | .ptr_type, .anyframe_type => { | |
| 902 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | |
| 903 | }, | |
| 904 | .array_type => |array_type| { | |
| 905 | return array_type.child.toType().abiAlignmentAdvanced(mod, strat); | |
| 906 | }, | |
| 907 | .vector_type => |vector_type| { | |
| 908 | const bits_u64 = try bitSizeAdvanced(vector_type.child.toType(), mod, opt_sema); | |
| 909 | const bits = @intCast(u32, bits_u64); | |
| 910 | const bytes = ((bits * vector_type.len) + 7) / 8; | |
| 911 | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); | |
| 912 | return AbiAlignmentAdvanced{ .scalar = alignment }; | |
| 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 => { | |
| 3000 | const bits: u16 = ty.cast(Payload.Bits).?.data; | |
| 3001 | if (bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; | |
| 3002 | return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(bits, target) }; | |
| 3003 | }, | |
| 915 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), | |
| 916 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), | |
| 3004 | 917 | |
| 3005 | .optional => { | |
| 3006 | var buf: Payload.ElemType = undefined; | |
| 3007 | const child_type = ty.optionalChild(&buf); | |
| 918 | // TODO revisit this when we have the concept of the error tag type | |
| 919 | .error_set_type, .inferred_error_set_type => return AbiAlignmentAdvanced{ .scalar = 2 }, | |
| 3008 | 920 | |
| 3009 | switch (child_type.zigTypeTag()) { | |
| 3010 | .Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 3011 | .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, target, strat), | |
| 3012 | .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 }, | |
| 3013 | else => {}, | |
| 3014 | } | |
| 921 | // represents machine code; not a pointer | |
| 922 | .func_type => |func_type| return AbiAlignmentAdvanced{ | |
| 923 | .scalar = if (func_type.alignment.toByteUnitsOptional()) |a| | |
| 924 | @intCast(u32, a) | |
| 925 | else | |
| 926 | target_util.defaultFunctionAlignment(target), | |
| 927 | }, | |
| 3015 | 928 | |
| 3016 | switch (strat) { | |
| 3017 | .eager, .sema => { | |
| 3018 | if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | |
| 3019 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | |
| 3020 | else => |e| return e, | |
| 3021 | })) { | |
| 3022 | return AbiAlignmentAdvanced{ .scalar = 1 }; | |
| 3023 | } | |
| 3024 | return child_type.abiAlignmentAdvanced(target, strat); | |
| 929 | .simple_type => |t| switch (t) { | |
| 930 | .bool, | |
| 931 | .atomic_order, | |
| 932 | .atomic_rmw_op, | |
| 933 | .calling_convention, | |
| 934 | .address_space, | |
| 935 | .float_mode, | |
| 936 | .reduce_op, | |
| 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)) { | |
| 3027 | .scalar => |x| return AbiAlignmentAdvanced{ .scalar = @max(x, 1) }, | |
| 3028 | .val => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 965 | .f80 => switch (target.c_type_bit_size(.longdouble)) { | |
| 966 | 80 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | |
| 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 => { | |
| 3034 | // This code needs to be kept in sync with the equivalent switch prong | |
| 3035 | // in abiSizeAdvanced. | |
| 3036 | const data = ty.castTag(.error_union).?.data; | |
| 3037 | const code_align = abiAlignment(Type.anyerror, target); | |
| 3038 | switch (strat) { | |
| 3039 | .eager, .sema => { | |
| 3040 | if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | |
| 3041 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | |
| 3042 | else => |e| return e, | |
| 3043 | })) { | |
| 3044 | return AbiAlignmentAdvanced{ .scalar = code_align }; | |
| 977 | // TODO revisit this when we have the concept of the error tag type | |
| 978 | .anyerror => return AbiAlignmentAdvanced{ .scalar = 2 }, | |
| 979 | ||
| 980 | .void, | |
| 981 | .type, | |
| 982 | .comptime_int, | |
| 983 | .comptime_float, | |
| 984 | .null, | |
| 985 | .undefined, | |
| 986 | .enum_literal, | |
| 987 | .type_info, | |
| 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( | |
| 3047 | code_align, | |
| 3048 | (try data.payload.abiAlignmentAdvanced(target, strat)).scalar, | |
| 3049 | ) }; | |
| 3050 | }, | |
| 3051 | .lazy => |arena| { | |
| 3052 | switch (try data.payload.abiAlignmentAdvanced(target, strat)) { | |
| 3053 | .scalar => |payload_align| { | |
| 3054 | return AbiAlignmentAdvanced{ | |
| 3055 | .scalar = @max(code_align, payload_align), | |
| 3056 | }; | |
| 3057 | }, | |
| 3058 | .val => {}, | |
| 1004 | _ = try sema.resolveTypeFields(ty); | |
| 1005 | } | |
| 1006 | if (!struct_obj.haveFieldTypes()) switch (strat) { | |
| 1007 | .eager => unreachable, // struct layout not resolved | |
| 1008 | .sema => unreachable, // handled above | |
| 1009 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1010 | .ty = .comptime_int_type, | |
| 1011 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1012 | } })).toValue() }, | |
| 1013 | }; | |
| 1014 | if (struct_obj.layout == .Packed) { | |
| 1015 | switch (strat) { | |
| 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) }; | |
| 3061 | }, | |
| 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) }; | |
| 1023 | assert(struct_obj.haveLayout()); | |
| 1024 | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(mod) }; | |
| 3073 | 1025 | } |
| 3074 | _ = try sema.resolveTypeFields(ty); | |
| 3075 | } | |
| 3076 | if (!struct_obj.haveFieldTypes()) switch (strat) { | |
| 3077 | .eager => unreachable, // struct layout not resolved | |
| 3078 | .sema => unreachable, // handled above | |
| 3079 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 3080 | }; | |
| 3081 | if (struct_obj.layout == .Packed) { | |
| 3082 | switch (strat) { | |
| 3083 | .sema => |sema| try sema.resolveTypeLayout(ty), | |
| 3084 | .lazy => |arena| { | |
| 3085 | if (!struct_obj.haveLayout()) { | |
| 3086 | return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }; | |
| 1026 | ||
| 1027 | const fields = ty.structFields(mod); | |
| 1028 | var big_align: u32 = 0; | |
| 1029 | for (fields.values()) |field| { | |
| 1030 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | |
| 1031 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1032 | .ty = .comptime_int_type, | |
| 1033 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1034 | } })).toValue() }, | |
| 1035 | else => |e| return e, | |
| 1036 | })) continue; | |
| 1037 | ||
| 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 | }, | |
| 3089 | .eager => {}, | |
| 1060 | } | |
| 3090 | 1061 | } |
| 3091 | assert(struct_obj.haveLayout()); | |
| 3092 | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(target) }; | |
| 3093 | } | |
| 3094 | ||
| 3095 | const fields = ty.structFields(); | |
| 3096 | var big_align: u32 = 0; | |
| 3097 | for (fields.values()) |field| { | |
| 3098 | if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | |
| 3099 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | |
| 3100 | else => |e| return e, | |
| 3101 | })) continue; | |
| 3102 | ||
| 3103 | const field_align = if (field.abi_align != 0) | |
| 3104 | field.abi_align | |
| 3105 | else switch (try field.ty.abiAlignmentAdvanced(target, strat)) { | |
| 3106 | .scalar => |a| a, | |
| 3107 | .val => switch (strat) { | |
| 3108 | .eager => unreachable, // struct layout not resolved | |
| 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); | |
| 1062 | return AbiAlignmentAdvanced{ .scalar = big_align }; | |
| 1063 | }, | |
| 1064 | .anon_struct_type => |tuple| { | |
| 1065 | var big_align: u32 = 0; | |
| 1066 | for (tuple.types, tuple.values) |field_ty, val| { | |
| 1067 | if (val != .none) continue; // comptime field | |
| 1068 | if (!(field_ty.toType().hasRuntimeBits(mod))) continue; | |
| 1069 | ||
| 1070 | switch (try field_ty.toType().abiAlignmentAdvanced(mod, strat)) { | |
| 1071 | .scalar => |field_align| big_align = @max(big_align, field_align), | |
| 1072 | .val => switch (strat) { | |
| 1073 | .eager => unreachable, // field type alignment not resolved | |
| 1074 | .sema => unreachable, // passed to abiAlignmentAdvanced above | |
| 1075 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1076 | .ty = .comptime_int_type, | |
| 1077 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1078 | } })).toValue() }, | |
| 1079 | }, | |
| 3121 | 1080 | } |
| 3122 | 1081 | } |
| 3123 | } | |
| 3124 | return AbiAlignmentAdvanced{ .scalar = big_align }; | |
| 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; | |
| 1082 | return AbiAlignmentAdvanced{ .scalar = big_align }; | |
| 1083 | }, | |
| 3134 | 1084 | |
| 3135 | switch (try field_ty.abiAlignmentAdvanced(target, strat)) { | |
| 3136 | .scalar => |field_align| big_align = @max(big_align, field_align), | |
| 3137 | .val => switch (strat) { | |
| 3138 | .eager => unreachable, // field type alignment not resolved | |
| 3139 | .sema => unreachable, // passed to abiAlignmentAdvanced above | |
| 3140 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 3141 | }, | |
| 3142 | } | |
| 3143 | } | |
| 3144 | return AbiAlignmentAdvanced{ .scalar = big_align }; | |
| 1085 | .union_type => |union_type| { | |
| 1086 | const union_obj = mod.unionPtr(union_type.index); | |
| 1087 | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); | |
| 1088 | }, | |
| 1089 | .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 }, | |
| 1090 | .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) }, | |
| 1091 | ||
| 1092 | // values, not types | |
| 1093 | .undef, | |
| 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 => { | |
| 3148 | var buffer: Payload.Bits = undefined; | |
| 3149 | const int_tag_ty = ty.intTagType(&buffer); | |
| 3150 | return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(target) }; | |
| 3151 | }, | |
| 3152 | .@"union" => { | |
| 3153 | const union_obj = ty.castTag(.@"union").?.data; | |
| 3154 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false); | |
| 3155 | }, | |
| 3156 | .union_safety_tagged, .union_tagged => { | |
| 3157 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3158 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true); | |
| 1117 | fn abiAlignmentAdvancedErrorUnion( | |
| 1118 | ty: Type, | |
| 1119 | mod: *Module, | |
| 1120 | strat: AbiAlignmentAdvancedStrat, | |
| 1121 | payload_ty: Type, | |
| 1122 | ) Module.CompileError!AbiAlignmentAdvanced { | |
| 1123 | // This code needs to be kept in sync with the equivalent switch prong | |
| 1124 | // in abiSizeAdvanced. | |
| 1125 | const code_align = abiAlignment(Type.anyerror, mod); | |
| 1126 | switch (strat) { | |
| 1127 | .eager, .sema => { | |
| 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, | |
| 3162 | .void, | |
| 3163 | .empty_struct_literal, | |
| 3164 | .type, | |
| 3165 | .comptime_int, | |
| 3166 | .comptime_float, | |
| 3167 | .null, | |
| 3168 | .undefined, | |
| 3169 | .enum_literal, | |
| 3170 | .type_info, | |
| 3171 | => return AbiAlignmentAdvanced{ .scalar = 0 }, | |
| 1159 | fn abiAlignmentAdvancedOptional( | |
| 1160 | ty: Type, | |
| 1161 | mod: *Module, | |
| 1162 | strat: AbiAlignmentAdvancedStrat, | |
| 1163 | ) Module.CompileError!AbiAlignmentAdvanced { | |
| 1164 | const target = mod.getTarget(); | |
| 1165 | const child_type = ty.optionalChild(mod); | |
| 3172 | 1166 | |
| 3173 | .noreturn, | |
| 3174 | .inferred_alloc_const, | |
| 3175 | .inferred_alloc_mut, | |
| 3176 | => unreachable, | |
| 1167 | switch (child_type.zigTypeTag(mod)) { | |
| 1168 | .Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 1169 | .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat), | |
| 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 | 1197 | pub fn abiAlignmentAdvancedUnion( |
| 3183 | 1198 | ty: Type, |
| 3184 | target: Target, | |
| 1199 | mod: *Module, | |
| 3185 | 1200 | strat: AbiAlignmentAdvancedStrat, |
| 3186 | 1201 | union_obj: *Module.Union, |
| 3187 | 1202 | have_tag: bool, |
| ... | ... | @@ -3195,6 +1210,7 @@ pub const Type = extern union { |
| 3195 | 1210 | // We'll guess "pointer-aligned", if the union has an |
| 3196 | 1211 | // underaligned pointer field then some allocations |
| 3197 | 1212 | // might require explicit alignment. |
| 1213 | const target = mod.getTarget(); | |
| 3198 | 1214 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; |
| 3199 | 1215 | } |
| 3200 | 1216 | _ = try sema.resolveTypeFields(ty); |
| ... | ... | @@ -3202,32 +1218,41 @@ pub const Type = extern union { |
| 3202 | 1218 | if (!union_obj.haveFieldTypes()) switch (strat) { |
| 3203 | 1219 | .eager => unreachable, // union layout not resolved |
| 3204 | 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 | 1226 | if (union_obj.fields.count() == 0) { |
| 3208 | 1227 | if (have_tag) { |
| 3209 | return abiAlignmentAdvanced(union_obj.tag_ty, target, strat); | |
| 1228 | return abiAlignmentAdvanced(union_obj.tag_ty, mod, strat); | |
| 3210 | 1229 | } else { |
| 3211 | 1230 | return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) }; |
| 3212 | 1231 | } |
| 3213 | 1232 | } |
| 3214 | 1233 | |
| 3215 | 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 | 1236 | for (union_obj.fields.values()) |field| { |
| 3218 | if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | |
| 3219 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | |
| 1237 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | |
| 1238 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1239 | .ty = .comptime_int_type, | |
| 1240 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1241 | } })).toValue() }, | |
| 3220 | 1242 | else => |e| return e, |
| 3221 | 1243 | })) continue; |
| 3222 | 1244 | |
| 3223 | 1245 | const field_align = if (field.abi_align != 0) |
| 3224 | 1246 | field.abi_align |
| 3225 | else switch (try field.ty.abiAlignmentAdvanced(target, strat)) { | |
| 1247 | else switch (try field.ty.abiAlignmentAdvanced(mod, strat)) { | |
| 3226 | 1248 | .scalar => |a| a, |
| 3227 | 1249 | .val => switch (strat) { |
| 3228 | 1250 | .eager => unreachable, // struct layout not resolved |
| 3229 | 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 | 1258 | max_align = @max(max_align, field_align); |
| ... | ... | @@ -3236,17 +1261,17 @@ pub const Type = extern union { |
| 3236 | 1261 | } |
| 3237 | 1262 | |
| 3238 | 1263 | /// May capture a reference to `ty`. |
| 3239 | pub fn lazyAbiSize(ty: Type, target: Target, arena: Allocator) !Value { | |
| 3240 | switch (try ty.abiSizeAdvanced(target, .{ .lazy = arena })) { | |
| 1264 | pub fn lazyAbiSize(ty: Type, mod: *Module) !Value { | |
| 1265 | switch (try ty.abiSizeAdvanced(mod, .lazy)) { | |
| 3241 | 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 | 1271 | /// Asserts the type has the ABI size already resolved. |
| 3247 | 1272 | /// Types that return false for hasRuntimeBits() return 0. |
| 3248 | pub fn abiSize(ty: Type, target: Target) u64 { | |
| 3249 | return (abiSizeAdvanced(ty, target, .eager) catch unreachable).scalar; | |
| 1273 | pub fn abiSize(ty: Type, mod: *Module) u64 { | |
| 1274 | return (abiSizeAdvanced(ty, mod, .eager) catch unreachable).scalar; | |
| 3250 | 1275 | } |
| 3251 | 1276 | |
| 3252 | 1277 | const AbiSizeAdvanced = union(enum) { |
| ... | ... | @@ -3262,315 +1287,310 @@ pub const Type = extern union { |
| 3262 | 1287 | /// necessary, possibly returning a CompileError. |
| 3263 | 1288 | pub fn abiSizeAdvanced( |
| 3264 | 1289 | ty: Type, |
| 3265 | target: Target, | |
| 1290 | mod: *Module, | |
| 3266 | 1291 | strat: AbiAlignmentAdvancedStrat, |
| 3267 | 1292 | ) Module.CompileError!AbiSizeAdvanced { |
| 3268 | switch (ty.tag()) { | |
| 3269 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer | |
| 3270 | .fn_void_no_args => unreachable, // represents machine code; not a pointer | |
| 3271 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer | |
| 3272 | .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer | |
| 3273 | .function => unreachable, // represents machine code; not a pointer | |
| 3274 | .@"opaque" => unreachable, // no size available | |
| 3275 | .noreturn => unreachable, | |
| 3276 | .inferred_alloc_const => unreachable, | |
| 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) }; | |
| 1293 | const target = mod.getTarget(); | |
| 1294 | ||
| 1295 | switch (ty.toIntern()) { | |
| 1296 | .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 }, | |
| 1297 | ||
| 1298 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1299 | .int_type => |int_type| { | |
| 1300 | if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; | |
| 1301 | return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) }; | |
| 3312 | 1302 | }, |
| 3313 | else => { | |
| 3314 | switch (strat) { | |
| 3315 | .sema => |sema| try sema.resolveTypeLayout(ty), | |
| 3316 | .lazy => |arena| { | |
| 3317 | if (ty.castTag(.@"struct")) |payload| { | |
| 3318 | const struct_obj = payload.data; | |
| 3319 | if (!struct_obj.haveLayout()) { | |
| 3320 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | |
| 3321 | } | |
| 3322 | } | |
| 1303 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 1304 | .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, | |
| 1305 | else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 1306 | }, | |
| 1307 | .anyframe_type => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 1308 | ||
| 1309 | .array_type => |array_type| { | |
| 1310 | const len = array_type.len + @boolToInt(array_type.sentinel != .none); | |
| 1311 | switch (try array_type.child.toType().abiSizeAdvanced(mod, strat)) { | |
| 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 | }, | |
| 3333 | ||
| 3334 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { | |
| 3335 | var buffer: Payload.Bits = undefined; | |
| 3336 | const int_tag_ty = ty.intTagType(&buffer); | |
| 3337 | return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(target) }; | |
| 3338 | }, | |
| 3339 | .@"union" => { | |
| 3340 | const union_obj = ty.castTag(.@"union").?.data; | |
| 3341 | return abiSizeAdvancedUnion(ty, target, strat, union_obj, false); | |
| 3342 | }, | |
| 3343 | .union_safety_tagged, .union_tagged => { | |
| 3344 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3345 | return abiSizeAdvancedUnion(ty, target, strat, union_obj, true); | |
| 3346 | }, | |
| 3347 | ||
| 3348 | .u1, | |
| 3349 | .u8, | |
| 3350 | .i8, | |
| 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, | |
| 1322 | .vector_type => |vector_type| { | |
| 1323 | const opt_sema = switch (strat) { | |
| 1324 | .sema => |sema| sema, | |
| 1325 | .eager => null, | |
| 1326 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1327 | .ty = .comptime_int_type, | |
| 1328 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1329 | } })).toValue() }, | |
| 1330 | }; | |
| 1331 | const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); | |
| 1332 | const elem_bits = @intCast(u32, elem_bits_u64); | |
| 1333 | const total_bits = elem_bits * vector_type.len; | |
| 1334 | const total_bytes = (total_bits + 7) / 8; | |
| 1335 | const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) { | |
| 1336 | .scalar => |x| x, | |
| 1337 | .val => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1338 | .ty = .comptime_int_type, | |
| 1339 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1340 | } })).toValue() }, | |
| 3456 | 1341 | }; |
| 3457 | const u80_ty = initPayload(&payload.base); | |
| 3458 | return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, target) }; | |
| 1342 | const result = std.mem.alignForwardGeneric(u32, total_bytes, alignment); | |
| 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 => { | |
| 3483 | var buf: Payload.ElemType = undefined; | |
| 3484 | const child_type = ty.optionalChild(&buf); | |
| 3485 | ||
| 3486 | if (child_type.isNoReturn()) { | |
| 3487 | return AbiSizeAdvanced{ .scalar = 0 }; | |
| 3488 | } | |
| 3489 | ||
| 3490 | if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | |
| 3491 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, | |
| 3492 | else => |e| return e, | |
| 3493 | })) return AbiSizeAdvanced{ .scalar = 1 }; | |
| 3494 | ||
| 3495 | if (ty.optionalReprIsPayload()) { | |
| 3496 | return abiSizeAdvanced(child_type, target, strat); | |
| 3497 | } | |
| 1346 | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), | |
| 1347 | ||
| 1348 | // TODO revisit this when we have the concept of the error tag type | |
| 1349 | .error_set_type, .inferred_error_set_type => return AbiSizeAdvanced{ .scalar = 2 }, | |
| 1350 | ||
| 1351 | .error_union_type => |error_union_type| { | |
| 1352 | const payload_ty = error_union_type.payload_type.toType(); | |
| 1353 | // This code needs to be kept in sync with the equivalent switch prong | |
| 1354 | // in abiAlignmentAdvanced. | |
| 1355 | const code_size = abiSize(Type.anyerror, mod); | |
| 1356 | if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | |
| 1357 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1358 | .ty = .comptime_int_type, | |
| 1359 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1360 | } })).toValue() }, | |
| 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)) { | |
| 3500 | .scalar => |elem_size| elem_size, | |
| 3501 | .val => switch (strat) { | |
| 3502 | .sema => unreachable, | |
| 3503 | .eager => unreachable, | |
| 3504 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | |
| 1380 | var size: u64 = 0; | |
| 1381 | if (code_align > payload_align) { | |
| 1382 | size += code_size; | |
| 1383 | size = std.mem.alignForwardGeneric(u64, size, payload_align); | |
| 1384 | size += payload_size; | |
| 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 | |
| 3509 | // field and a boolean as the second. Since the child type's abi alignment is | |
| 3510 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal | |
| 3511 | // to the child type's ABI alignment. | |
| 3512 | return AbiSizeAdvanced{ | |
| 3513 | .scalar = child_type.abiAlignment(target) + payload_size, | |
| 3514 | }; | |
| 3515 | }, | |
| 3516 | ||
| 3517 | .error_union => { | |
| 3518 | // This code needs to be kept in sync with the equivalent switch prong | |
| 3519 | // in abiAlignmentAdvanced. | |
| 3520 | const data = ty.castTag(.error_union).?.data; | |
| 3521 | const code_size = abiSize(Type.anyerror, target); | |
| 3522 | if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | |
| 3523 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, | |
| 3524 | else => |e| return e, | |
| 3525 | })) { | |
| 3526 | // Same as anyerror. | |
| 3527 | return AbiSizeAdvanced{ .scalar = code_size }; | |
| 3528 | } | |
| 3529 | const code_align = abiAlignment(Type.anyerror, target); | |
| 3530 | const payload_align = abiAlignment(data.payload, target); | |
| 3531 | const payload_size = switch (try data.payload.abiSizeAdvanced(target, strat)) { | |
| 3532 | .scalar => |elem_size| elem_size, | |
| 3533 | .val => switch (strat) { | |
| 3534 | .sema => unreachable, | |
| 3535 | .eager => unreachable, | |
| 3536 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | |
| 1418 | .usize, | |
| 1419 | .isize, | |
| 1420 | => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 1421 | ||
| 1422 | .c_char => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.char) }, | |
| 1423 | .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) }, | |
| 1424 | .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) }, | |
| 1425 | .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) }, | |
| 1426 | .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) }, | |
| 1427 | .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) }, | |
| 1428 | .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) }, | |
| 1429 | .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) }, | |
| 1430 | .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) }, | |
| 1431 | .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, | |
| 1432 | ||
| 1433 | .anyopaque, | |
| 1434 | .void, | |
| 1435 | .type, | |
| 1436 | .comptime_int, | |
| 1437 | .comptime_float, | |
| 1438 | .null, | |
| 1439 | .undefined, | |
| 1440 | .enum_literal, | |
| 1441 | => return AbiSizeAdvanced{ .scalar = 0 }, | |
| 1442 | ||
| 1443 | // TODO revisit this when we have the concept of the error tag type | |
| 1444 | .anyerror => return AbiSizeAdvanced{ .scalar = 2 }, | |
| 1445 | ||
| 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; | |
| 3541 | if (code_align > payload_align) { | |
| 3542 | size += code_size; | |
| 3543 | size = std.mem.alignForwardGeneric(u64, size, payload_align); | |
| 3544 | size += payload_size; | |
| 3545 | size = std.mem.alignForwardGeneric(u64, size, code_align); | |
| 3546 | } else { | |
| 3547 | size += payload_size; | |
| 3548 | size = std.mem.alignForwardGeneric(u64, size, code_align); | |
| 3549 | size += code_size; | |
| 3550 | size = std.mem.alignForwardGeneric(u64, size, payload_align); | |
| 3551 | } | |
| 3552 | return AbiSizeAdvanced{ .scalar = size }; | |
| 1502 | .union_type => |union_type| { | |
| 1503 | const union_obj = mod.unionPtr(union_type.index); | |
| 1504 | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); | |
| 1505 | }, | |
| 1506 | .opaque_type => unreachable, // no size available | |
| 1507 | .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) }, | |
| 1508 | ||
| 1509 | // values, not types | |
| 1510 | .undef, | |
| 1511 | .runtime_value, | |
| 1512 | .simple_value, | |
| 1513 | .variable, | |
| 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 | 1534 | pub fn abiSizeAdvancedUnion( |
| 3558 | 1535 | ty: Type, |
| 3559 | target: Target, | |
| 1536 | mod: *Module, | |
| 3560 | 1537 | strat: AbiAlignmentAdvancedStrat, |
| 3561 | 1538 | union_obj: *Module.Union, |
| 3562 | 1539 | have_tag: bool, |
| 3563 | 1540 | ) Module.CompileError!AbiSizeAdvanced { |
| 3564 | 1541 | switch (strat) { |
| 3565 | 1542 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 3566 | .lazy => |arena| { | |
| 3567 | if (!union_obj.haveLayout()) { | |
| 3568 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | |
| 3569 | } | |
| 3570 | }, | |
| 1543 | .lazy => if (!union_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1544 | .ty = .comptime_int_type, | |
| 1545 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1546 | } })).toValue() }, | |
| 3571 | 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 | 1596 | fn intAbiSize(bits: u16, target: Target) u64 { |
| ... | ... | @@ -3585,8 +1605,8 @@ pub const Type = extern union { |
| 3585 | 1605 | ); |
| 3586 | 1606 | } |
| 3587 | 1607 | |
| 3588 | pub fn bitSize(ty: Type, target: Target) u64 { | |
| 3589 | return bitSizeAdvanced(ty, target, null) catch unreachable; | |
| 1608 | pub fn bitSize(ty: Type, mod: *Module) u64 { | |
| 1609 | return bitSizeAdvanced(ty, mod, null) catch unreachable; | |
| 3590 | 1610 | } |
| 3591 | 1611 | |
| 3592 | 1612 | /// If you pass `opt_sema`, any recursive type resolutions will happen if |
| ... | ... | @@ -3594,568 +1614,318 @@ pub const Type = extern union { |
| 3594 | 1614 | /// the type is fully resolved, and there will be no error, guaranteed. |
| 3595 | 1615 | pub fn bitSizeAdvanced( |
| 3596 | 1616 | ty: Type, |
| 3597 | target: Target, | |
| 1617 | mod: *Module, | |
| 3598 | 1618 | opt_sema: ?*Sema, |
| 3599 | 1619 | ) Module.CompileError!u64 { |
| 1620 | const target = mod.getTarget(); | |
| 1621 | ||
| 3600 | 1622 | const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; |
| 3601 | switch (ty.tag()) { | |
| 3602 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer | |
| 3603 | .fn_void_no_args => unreachable, // represents machine code; not a pointer | |
| 3604 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer | |
| 3605 | .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer | |
| 3606 | .function => unreachable, // represents machine code; not a pointer | |
| 3607 | .anyopaque => unreachable, | |
| 3608 | .type => unreachable, | |
| 3609 | .comptime_int => unreachable, | |
| 3610 | .comptime_float => unreachable, | |
| 3611 | .noreturn => unreachable, | |
| 3612 | .null => unreachable, | |
| 3613 | .undefined => unreachable, | |
| 3614 | .enum_literal => unreachable, | |
| 3615 | .single_const_pointer_to_comptime_int => unreachable, | |
| 3616 | .empty_struct => unreachable, | |
| 3617 | .empty_struct_literal => unreachable, | |
| 3618 | .inferred_alloc_const => unreachable, | |
| 3619 | .inferred_alloc_mut => unreachable, | |
| 3620 | .@"opaque" => unreachable, | |
| 3621 | .generic_poison => unreachable, | |
| 3622 | ||
| 3623 | .void => return 0, | |
| 3624 | .bool, .u1 => return 1, | |
| 3625 | .u8, .i8 => return 8, | |
| 3626 | .i16, .u16, .f16 => return 16, | |
| 3627 | .u29 => return 29, | |
| 3628 | .i32, .u32, .f32 => return 32, | |
| 3629 | .i64, .u64, .f64 => return 64, | |
| 3630 | .f80 => return 80, | |
| 3631 | .u128, .i128, .f128 => return 128, | |
| 3632 | ||
| 3633 | .@"struct" => { | |
| 3634 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 1623 | ||
| 1624 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1625 | .int_type => |int_type| return int_type.bits, | |
| 1626 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 1627 | .Slice => return target.ptrBitWidth() * 2, | |
| 1628 | else => return target.ptrBitWidth(), | |
| 1629 | }, | |
| 1630 | .anyframe_type => return target.ptrBitWidth(), | |
| 1631 | ||
| 1632 | .array_type => |array_type| { | |
| 1633 | const len = array_type.len + @boolToInt(array_type.sentinel != .none); | |
| 1634 | if (len == 0) return 0; | |
| 1635 | const elem_ty = array_type.child.toType(); | |
| 1636 | const elem_size = std.math.max(elem_ty.abiAlignment(mod), elem_ty.abiSize(mod)); | |
| 1637 | if (elem_size == 0) return 0; | |
| 1638 | const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema); | |
| 1639 | return (len - 1) * 8 * elem_size + elem_bit_size; | |
| 1640 | }, | |
| 1641 | .vector_type => |vector_type| { | |
| 1642 | const child_ty = vector_type.child.toType(); | |
| 1643 | const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema); | |
| 1644 | return elem_bit_size * vector_type.len; | |
| 1645 | }, | |
| 1646 | .opt_type => { | |
| 1647 | // Optionals and error unions are not packed so their bitsize | |
| 1648 | // includes padding bits. | |
| 1649 | return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; | |
| 1650 | }, | |
| 1651 | ||
| 1652 | // TODO revisit this when we have the concept of the error tag type | |
| 1653 | .error_set_type, .inferred_error_set_type => return 16, | |
| 1654 | ||
| 1655 | .error_union_type => { | |
| 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 | 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 | 1716 | if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty); |
| 3639 | 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 | 1722 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); |
| 3645 | if (ty.containerLayout() != .Packed) { | |
| 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); | |
| 1723 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; | |
| 3659 | 1724 | }, |
| 3660 | 1725 | |
| 3661 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 1726 | .union_type => |union_type| { | |
| 3662 | 1727 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); |
| 3663 | if (ty.containerLayout() != .Packed) { | |
| 3664 | return (try ty.abiSizeAdvanced(target, strat)).scalar * 8; | |
| 1728 | if (ty.containerLayout(mod) != .Packed) { | |
| 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 | 1732 | assert(union_obj.haveFieldTypes()); |
| 3668 | 1733 | |
| 3669 | 1734 | var size: u64 = 0; |
| 3670 | 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 | 1738 | return size; |
| 3674 | 1739 | }, |
| 3675 | ||
| 3676 | .vector => { | |
| 3677 | const payload = ty.castTag(.vector).?.data; | |
| 3678 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, opt_sema); | |
| 3679 | return elem_bit_size * payload.len; | |
| 3680 | }, | |
| 3681 | .array_u8 => return 8 * ty.castTag(.array_u8).?.data, | |
| 3682 | .array_u8_sentinel_0 => return 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1), | |
| 3683 | .array => { | |
| 3684 | const payload = ty.castTag(.array).?.data; | |
| 3685 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); | |
| 3686 | if (elem_size == 0 or payload.len == 0) | |
| 3687 | return @as(u64, 0); | |
| 3688 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, opt_sema); | |
| 3689 | return (payload.len - 1) * 8 * elem_size + elem_bit_size; | |
| 3690 | }, | |
| 3691 | .array_sentinel => { | |
| 3692 | const payload = ty.castTag(.array_sentinel).?.data; | |
| 3693 | const elem_size = std.math.max( | |
| 3694 | payload.elem_type.abiAlignment(target), | |
| 3695 | payload.elem_type.abiSize(target), | |
| 3696 | ); | |
| 3697 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, opt_sema); | |
| 3698 | return payload.len * 8 * elem_size + elem_bit_size; | |
| 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"), | |
| 1740 | .opaque_type => unreachable, | |
| 1741 | .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema), | |
| 1742 | ||
| 1743 | // values, not types | |
| 1744 | .undef, | |
| 1745 | .runtime_value, | |
| 1746 | .simple_value, | |
| 1747 | .variable, | |
| 1748 | .extern_func, | |
| 1749 | .func, | |
| 1750 | .int, | |
| 1751 | .err, | |
| 1752 | .error_union, | |
| 1753 | .enum_literal, | |
| 1754 | .enum_tag, | |
| 1755 | .empty_enum_value, | |
| 1756 | .float, | |
| 1757 | .ptr, | |
| 1758 | .opt, | |
| 1759 | .aggregate, | |
| 1760 | .un, | |
| 1761 | // memoization, not types | |
| 1762 | .memoized_call, | |
| 1763 | => unreachable, | |
| 3780 | 1764 | } |
| 3781 | 1765 | } |
| 3782 | 1766 | |
| 3783 | 1767 | /// Returns true if the type's layout is already resolved and it is safe |
| 3784 | 1768 | /// to use `abiSize`, `abiAlignment` and `bitSize` on it. |
| 3785 | pub fn layoutIsResolved(ty: Type) bool { | |
| 3786 | switch (ty.zigTypeTag()) { | |
| 1769 | pub fn layoutIsResolved(ty: Type, mod: *Module) bool { | |
| 1770 | switch (ty.zigTypeTag(mod)) { | |
| 3787 | 1771 | .Struct => { |
| 3788 | if (ty.castTag(.@"struct")) |struct_ty| { | |
| 3789 | return struct_ty.data.haveLayout(); | |
| 1772 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 1773 | return struct_obj.haveLayout(); | |
| 3790 | 1774 | } |
| 3791 | 1775 | return true; |
| 3792 | 1776 | }, |
| 3793 | 1777 | .Union => { |
| 3794 | if (ty.cast(Payload.Union)) |union_ty| { | |
| 3795 | return union_ty.data.haveLayout(); | |
| 1778 | if (mod.typeToUnion(ty)) |union_obj| { | |
| 1779 | return union_obj.haveLayout(); | |
| 3796 | 1780 | } |
| 3797 | 1781 | return true; |
| 3798 | 1782 | }, |
| 3799 | 1783 | .Array => { |
| 3800 | if (ty.arrayLenIncludingSentinel() == 0) return true; | |
| 3801 | return ty.childType().layoutIsResolved(); | |
| 1784 | if (ty.arrayLenIncludingSentinel(mod) == 0) return true; | |
| 1785 | return ty.childType(mod).layoutIsResolved(mod); | |
| 3802 | 1786 | }, |
| 3803 | 1787 | .Optional => { |
| 3804 | var buf: Type.Payload.ElemType = undefined; | |
| 3805 | const payload_ty = ty.optionalChild(&buf); | |
| 3806 | return payload_ty.layoutIsResolved(); | |
| 1788 | const payload_ty = ty.optionalChild(mod); | |
| 1789 | return payload_ty.layoutIsResolved(mod); | |
| 3807 | 1790 | }, |
| 3808 | 1791 | .ErrorUnion => { |
| 3809 | const payload_ty = ty.errorUnionPayload(); | |
| 3810 | return payload_ty.layoutIsResolved(); | |
| 1792 | const payload_ty = ty.errorUnionPayload(mod); | |
| 1793 | return payload_ty.layoutIsResolved(mod); | |
| 3811 | 1794 | }, |
| 3812 | 1795 | else => return true, |
| 3813 | 1796 | } |
| 3814 | 1797 | } |
| 3815 | 1798 | |
| 3816 | pub fn isSinglePointer(self: Type) bool { | |
| 3817 | return switch (self.tag()) { | |
| 3818 | .single_const_pointer, | |
| 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 | ||
| 1799 | pub fn isSinglePointer(ty: Type, mod: *const Module) bool { | |
| 1800 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1801 | .ptr_type => |ptr_info| ptr_info.flags.size == .One, | |
| 3827 | 1802 | else => false, |
| 3828 | 1803 | }; |
| 3829 | 1804 | } |
| 3830 | 1805 | |
| 3831 | 1806 | /// Asserts `ty` is a pointer. |
| 3832 | pub fn ptrSize(ty: Type) std.builtin.Type.Pointer.Size { | |
| 3833 | return ptrSizeOrNull(ty).?; | |
| 1807 | pub fn ptrSize(ty: Type, mod: *const Module) std.builtin.Type.Pointer.Size { | |
| 1808 | return ptrSizeOrNull(ty, mod).?; | |
| 3834 | 1809 | } |
| 3835 | 1810 | |
| 3836 | 1811 | /// Returns `null` if `ty` is not a pointer. |
| 3837 | pub fn ptrSizeOrNull(ty: Type) ?std.builtin.Type.Pointer.Size { | |
| 3838 | return switch (ty.tag()) { | |
| 3839 | .const_slice, | |
| 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 | ||
| 1812 | pub fn ptrSizeOrNull(ty: Type, mod: *const Module) ?std.builtin.Type.Pointer.Size { | |
| 1813 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1814 | .ptr_type => |ptr_info| ptr_info.flags.size, | |
| 3865 | 1815 | else => null, |
| 3866 | 1816 | }; |
| 3867 | 1817 | } |
| 3868 | 1818 | |
| 3869 | pub fn isSlice(self: Type) bool { | |
| 3870 | return switch (self.tag()) { | |
| 3871 | .const_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 | ||
| 1819 | pub fn isSlice(ty: Type, mod: *const Module) bool { | |
| 1820 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1821 | .ptr_type => |ptr_type| ptr_type.flags.size == .Slice, | |
| 3879 | 1822 | else => false, |
| 3880 | 1823 | }; |
| 3881 | 1824 | } |
| 3882 | 1825 | |
| 3883 | pub const SlicePtrFieldTypeBuffer = union { | |
| 3884 | elem_type: Payload.ElemType, | |
| 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 | } | |
| 1826 | pub fn slicePtrFieldType(ty: Type, mod: *const Module) Type { | |
| 1827 | return mod.intern_pool.slicePtrType(ty.toIntern()).toType(); | |
| 3966 | 1828 | } |
| 3967 | 1829 | |
| 3968 | pub fn isConstPtr(self: Type) bool { | |
| 3969 | return switch (self.tag()) { | |
| 3970 | .single_const_pointer, | |
| 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 | ||
| 1830 | pub fn isConstPtr(ty: Type, mod: *const Module) bool { | |
| 1831 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1832 | .ptr_type => |ptr_type| ptr_type.flags.is_const, | |
| 3983 | 1833 | else => false, |
| 3984 | 1834 | }; |
| 3985 | 1835 | } |
| 3986 | 1836 | |
| 3987 | pub fn isVolatilePtr(self: Type) bool { | |
| 3988 | return switch (self.tag()) { | |
| 3989 | .pointer => { | |
| 3990 | const payload = self.castTag(.pointer).?.data; | |
| 3991 | return payload.@"volatile"; | |
| 3992 | }, | |
| 1837 | pub fn isVolatilePtr(ty: Type, mod: *const Module) bool { | |
| 1838 | return isVolatilePtrIp(ty, &mod.intern_pool); | |
| 1839 | } | |
| 1840 | ||
| 1841 | pub fn isVolatilePtrIp(ty: Type, ip: *const InternPool) bool { | |
| 1842 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 1843 | .ptr_type => |ptr_type| ptr_type.flags.is_volatile, | |
| 3993 | 1844 | else => false, |
| 3994 | 1845 | }; |
| 3995 | 1846 | } |
| 3996 | 1847 | |
| 3997 | pub fn isAllowzeroPtr(self: Type) bool { | |
| 3998 | return switch (self.tag()) { | |
| 3999 | .pointer => { | |
| 4000 | const payload = self.castTag(.pointer).?.data; | |
| 4001 | return payload.@"allowzero"; | |
| 4002 | }, | |
| 4003 | else => return self.zigTypeTag() == .Optional, | |
| 1848 | pub fn isAllowzeroPtr(ty: Type, mod: *const Module) bool { | |
| 1849 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1850 | .ptr_type => |ptr_type| ptr_type.flags.is_allowzero, | |
| 1851 | .opt_type => true, | |
| 1852 | else => false, | |
| 4004 | 1853 | }; |
| 4005 | 1854 | } |
| 4006 | 1855 | |
| 4007 | pub fn isCPtr(self: Type) bool { | |
| 4008 | return switch (self.tag()) { | |
| 4009 | .c_const_pointer, | |
| 4010 | .c_mut_pointer, | |
| 4011 | => return true, | |
| 4012 | ||
| 4013 | .pointer => self.castTag(.pointer).?.data.size == .C, | |
| 4014 | ||
| 4015 | else => return false, | |
| 1856 | pub fn isCPtr(ty: Type, mod: *const Module) bool { | |
| 1857 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1858 | .ptr_type => |ptr_type| ptr_type.flags.size == .C, | |
| 1859 | else => false, | |
| 4016 | 1860 | }; |
| 4017 | 1861 | } |
| 4018 | 1862 | |
| 4019 | pub fn isPtrAtRuntime(self: Type) bool { | |
| 4020 | switch (self.tag()) { | |
| 4021 | .c_const_pointer, | |
| 4022 | .c_mut_pointer, | |
| 4023 | .many_const_pointer, | |
| 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, | |
| 1863 | pub fn isPtrAtRuntime(ty: Type, mod: *const Module) bool { | |
| 1864 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1865 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 1866 | .Slice => false, | |
| 1867 | .One, .Many, .C => true, | |
| 4038 | 1868 | }, |
| 4039 | ||
| 4040 | .optional => { | |
| 4041 | var buf: Payload.ElemType = undefined; | |
| 4042 | const child_type = self.optionalChild(&buf); | |
| 4043 | if (child_type.zigTypeTag() != .Pointer) return false; | |
| 4044 | const info = child_type.ptrInfo().data; | |
| 4045 | switch (info.size) { | |
| 4046 | .Slice, .C => return false, | |
| 4047 | .Many, .One => return !info.@"allowzero", | |
| 4048 | } | |
| 1869 | .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) { | |
| 1870 | .ptr_type => |p| switch (p.flags.size) { | |
| 1871 | .Slice, .C => false, | |
| 1872 | .Many, .One => !p.flags.is_allowzero, | |
| 1873 | }, | |
| 1874 | else => false, | |
| 4049 | 1875 | }, |
| 4050 | ||
| 4051 | else => return false, | |
| 4052 | } | |
| 1876 | else => false, | |
| 1877 | }; | |
| 4053 | 1878 | } |
| 4054 | 1879 | |
| 4055 | 1880 | /// For pointer-like optionals, returns true, otherwise returns the allowzero property |
| 4056 | 1881 | /// of pointers. |
| 4057 | pub fn ptrAllowsZero(ty: Type) bool { | |
| 4058 | if (ty.isPtrLikeOptional()) { | |
| 1882 | pub fn ptrAllowsZero(ty: Type, mod: *const Module) bool { | |
| 1883 | if (ty.isPtrLikeOptional(mod)) { | |
| 4059 | 1884 | return true; |
| 4060 | 1885 | } |
| 4061 | return ty.ptrInfo().data.@"allowzero"; | |
| 1886 | return ty.ptrInfo(mod).@"allowzero"; | |
| 4062 | 1887 | } |
| 4063 | 1888 | |
| 4064 | 1889 | /// See also `isPtrLikeOptional`. |
| 4065 | pub fn optionalReprIsPayload(ty: Type) bool { | |
| 4066 | switch (ty.tag()) { | |
| 4067 | .optional_single_const_pointer, | |
| 4068 | .optional_single_mut_pointer, | |
| 4069 | .c_const_pointer, | |
| 4070 | .c_mut_pointer, | |
| 4071 | => return true, | |
| 4072 | ||
| 4073 | .optional => { | |
| 4074 | const child_ty = ty.castTag(.optional).?.data; | |
| 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 | } | |
| 1890 | pub fn optionalReprIsPayload(ty: Type, mod: *const Module) bool { | |
| 1891 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1892 | .opt_type => |child_type| child_type == .anyerror_type or switch (mod.intern_pool.indexToKey(child_type)) { | |
| 1893 | .ptr_type => |ptr_type| ptr_type.flags.size != .C and !ptr_type.flags.is_allowzero, | |
| 1894 | .error_set_type => true, | |
| 1895 | else => false, | |
| 1896 | }, | |
| 1897 | .ptr_type => |ptr_type| ptr_type.flags.size == .C, | |
| 1898 | else => false, | |
| 1899 | }; | |
| 4092 | 1900 | } |
| 4093 | 1901 | |
| 4094 | 1902 | /// Returns true if the type is optional and would be lowered to a single pointer |
| 4095 | 1903 | /// address value, using 0 for null. Note that this returns true for C pointers. |
| 4096 | pub fn isPtrLikeOptional(self: Type) bool { | |
| 4097 | switch (self.tag()) { | |
| 4098 | .optional_single_const_pointer, | |
| 4099 | .optional_single_mut_pointer, | |
| 4100 | .c_const_pointer, | |
| 4101 | .c_mut_pointer, | |
| 4102 | => return true, | |
| 4103 | ||
| 4104 | .optional => { | |
| 4105 | const child_ty = self.castTag(.optional).?.data; | |
| 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 | } | |
| 1904 | /// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`. | |
| 1905 | pub fn isPtrLikeOptional(ty: Type, mod: *const Module) bool { | |
| 1906 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1907 | .ptr_type => |ptr_type| ptr_type.flags.size == .C, | |
| 1908 | .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) { | |
| 1909 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 1910 | .Slice, .C => false, | |
| 1911 | .Many, .One => !ptr_type.flags.is_allowzero, | |
| 1912 | }, | |
| 1913 | else => false, | |
| 4112 | 1914 | }, |
| 4113 | ||
| 4114 | .pointer => return self.castTag(.pointer).?.data.size == .C, | |
| 4115 | ||
| 4116 | else => return false, | |
| 4117 | } | |
| 1915 | else => false, | |
| 1916 | }; | |
| 4118 | 1917 | } |
| 4119 | 1918 | |
| 4120 | 1919 | /// For *[N]T, returns [N]T. |
| 4121 | 1920 | /// For *T, returns T. |
| 4122 | 1921 | /// For [*]T, returns T. |
| 4123 | pub fn childType(ty: Type) Type { | |
| 4124 | return switch (ty.tag()) { | |
| 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 | }; | |
| 1922 | pub fn childType(ty: Type, mod: *const Module) Type { | |
| 1923 | return childTypeIp(ty, &mod.intern_pool); | |
| 4154 | 1924 | } |
| 4155 | 1925 | |
| 4156 | /// Asserts the type is a pointer or array type. | |
| 4157 | /// TODO this is deprecated in favor of `childType`. | |
| 4158 | pub const elemType = childType; | |
| 1926 | pub fn childTypeIp(ty: Type, ip: *const InternPool) Type { | |
| 1927 | return ip.childType(ty.toIntern()).toType(); | |
| 1928 | } | |
| 4159 | 1929 | |
| 4160 | 1930 | /// For *[N]T, returns T. |
| 4161 | 1931 | /// For ?*T, returns T. |
| ... | ... | @@ -4166,283 +1936,178 @@ pub const Type = extern union { |
| 4166 | 1936 | /// For [N]T, returns T. |
| 4167 | 1937 | /// For []T, returns T. |
| 4168 | 1938 | /// For anyframe->T, returns T. |
| 4169 | pub fn elemType2(ty: Type) Type { | |
| 4170 | return switch (ty.tag()) { | |
| 4171 | .vector => ty.castTag(.vector).?.data.elem_type, | |
| 4172 | .array => ty.castTag(.array).?.data.elem_type, | |
| 4173 | .array_sentinel => ty.castTag(.array_sentinel).?.data.elem_type, | |
| 4174 | .many_const_pointer, | |
| 4175 | .many_mut_pointer, | |
| 4176 | .c_const_pointer, | |
| 4177 | .c_mut_pointer, | |
| 4178 | .const_slice, | |
| 4179 | .mut_slice, | |
| 4180 | => ty.castPointer().?.data, | |
| 4181 | ||
| 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 | ||
| 1939 | pub fn elemType2(ty: Type, mod: *const Module) Type { | |
| 1940 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1941 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 1942 | .One => ptr_type.child.toType().shallowElemType(mod), | |
| 1943 | .Many, .C, .Slice => ptr_type.child.toType(), | |
| 1944 | }, | |
| 1945 | .anyframe_type => |child| { | |
| 1946 | assert(child != .none); | |
| 1947 | return child.toType(); | |
| 1948 | }, | |
| 1949 | .vector_type => |vector_type| vector_type.child.toType(), | |
| 1950 | .array_type => |array_type| array_type.child.toType(), | |
| 1951 | .opt_type => |child| mod.intern_pool.childType(child).toType(), | |
| 4212 | 1952 | else => unreachable, |
| 4213 | 1953 | }; |
| 4214 | 1954 | } |
| 4215 | 1955 | |
| 4216 | fn shallowElemType(child_ty: Type) Type { | |
| 4217 | return switch (child_ty.zigTypeTag()) { | |
| 4218 | .Array, .Vector => child_ty.childType(), | |
| 1956 | fn shallowElemType(child_ty: Type, mod: *const Module) Type { | |
| 1957 | return switch (child_ty.zigTypeTag(mod)) { | |
| 1958 | .Array, .Vector => child_ty.childType(mod), | |
| 4219 | 1959 | else => child_ty, |
| 4220 | 1960 | }; |
| 4221 | 1961 | } |
| 4222 | 1962 | |
| 4223 | 1963 | /// For vectors, returns the element type. Otherwise returns self. |
| 4224 | pub fn scalarType(ty: Type) Type { | |
| 4225 | return switch (ty.zigTypeTag()) { | |
| 4226 | .Vector => ty.childType(), | |
| 1964 | pub fn scalarType(ty: Type, mod: *Module) Type { | |
| 1965 | return switch (ty.zigTypeTag(mod)) { | |
| 1966 | .Vector => ty.childType(mod), | |
| 4227 | 1967 | else => ty, |
| 4228 | 1968 | }; |
| 4229 | 1969 | } |
| 4230 | 1970 | |
| 4231 | 1971 | /// Asserts that the type is an optional. |
| 4232 | /// Resulting `Type` will have inner memory referencing `buf`. | |
| 4233 | 1972 | /// Note that for C pointers this returns the type unmodified. |
| 4234 | pub fn optionalChild(ty: Type, buf: *Payload.ElemType) Type { | |
| 4235 | return switch (ty.tag()) { | |
| 4236 | .optional => ty.castTag(.optional).?.data, | |
| 4237 | .optional_single_mut_pointer => { | |
| 4238 | buf.* = .{ | |
| 4239 | .base = .{ .tag = .single_mut_pointer }, | |
| 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); | |
| 1973 | pub fn optionalChild(ty: Type, mod: *const Module) Type { | |
| 1974 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1975 | .opt_type => |child| child.toType(), | |
| 1976 | .ptr_type => |ptr_type| b: { | |
| 1977 | assert(ptr_type.flags.size == .C); | |
| 1978 | break :b ty; | |
| 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 | 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 | 1984 | /// Returns the tag type of a union, if the type is a union and it has a tag type. |
| 4282 | 1985 | /// Otherwise, returns `null`. |
| 4283 | pub fn unionTagType(ty: Type) ?Type { | |
| 4284 | return switch (ty.tag()) { | |
| 4285 | .union_tagged => { | |
| 4286 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 4287 | assert(union_obj.haveFieldTypes()); | |
| 4288 | return union_obj.tag_ty; | |
| 1986 | pub fn unionTagType(ty: Type, mod: *Module) ?Type { | |
| 1987 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1988 | .union_type => |union_type| switch (union_type.runtime_tag) { | |
| 1989 | .tagged => { | |
| 1990 | const union_obj = mod.unionPtr(union_type.index); | |
| 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 | 1996 | else => null, |
| 4305 | 1997 | }; |
| 4306 | 1998 | } |
| 4307 | 1999 | |
| 4308 | 2000 | /// Same as `unionTagType` but includes safety tag. |
| 4309 | 2001 | /// Codegen should use this version. |
| 4310 | pub fn unionTagTypeSafety(ty: Type) ?Type { | |
| 4311 | return switch (ty.tag()) { | |
| 4312 | .union_safety_tagged, .union_tagged => { | |
| 4313 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 2002 | pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type { | |
| 2003 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2004 | .union_type => |union_type| { | |
| 2005 | if (!union_type.hasTag()) return null; | |
| 2006 | const union_obj = mod.unionPtr(union_type.index); | |
| 4314 | 2007 | assert(union_obj.haveFieldTypes()); |
| 4315 | 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 | 2010 | else => null, |
| 4332 | 2011 | }; |
| 4333 | 2012 | } |
| 4334 | 2013 | |
| 4335 | 2014 | /// Asserts the type is a union; returns the tag type, even if the tag will |
| 4336 | 2015 | /// not be stored at runtime. |
| 4337 | pub fn unionTagTypeHypothetical(ty: Type) Type { | |
| 4338 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 2016 | pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type { | |
| 2017 | const union_obj = mod.typeToUnion(ty).?; | |
| 4339 | 2018 | assert(union_obj.haveFieldTypes()); |
| 4340 | 2019 | return union_obj.tag_ty; |
| 4341 | 2020 | } |
| 4342 | 2021 | |
| 4343 | pub fn unionFields(ty: Type) Module.Union.Fields { | |
| 4344 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 2022 | pub fn unionFields(ty: Type, mod: *Module) Module.Union.Fields { | |
| 2023 | const union_obj = mod.typeToUnion(ty).?; | |
| 4345 | 2024 | assert(union_obj.haveFieldTypes()); |
| 4346 | 2025 | return union_obj.fields; |
| 4347 | 2026 | } |
| 4348 | 2027 | |
| 4349 | 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 | 2030 | const index = ty.unionTagFieldIndex(enum_tag, mod).?; |
| 4352 | 2031 | assert(union_obj.haveFieldTypes()); |
| 4353 | 2032 | return union_obj.fields.values()[index].ty; |
| 4354 | 2033 | } |
| 4355 | 2034 | |
| 4356 | 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 | 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 | 2039 | return union_obj.fields.getIndex(name); |
| 4361 | 2040 | } |
| 4362 | 2041 | |
| 4363 | pub fn unionHasAllZeroBitFieldTypes(ty: Type) bool { | |
| 4364 | return ty.cast(Payload.Union).?.data.hasAllZeroBitFieldTypes(); | |
| 2042 | pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool { | |
| 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 { | |
| 4368 | switch (ty.tag()) { | |
| 4369 | .@"union" => { | |
| 4370 | const union_obj = ty.castTag(.@"union").?.data; | |
| 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 | } | |
| 2047 | pub fn unionGetLayout(ty: Type, mod: *Module) Module.Union.Layout { | |
| 2048 | const union_type = mod.intern_pool.indexToKey(ty.toIntern()).union_type; | |
| 2049 | const union_obj = mod.unionPtr(union_type.index); | |
| 2050 | return union_obj.getLayout(mod, union_type.hasTag()); | |
| 4379 | 2051 | } |
| 4380 | 2052 | |
| 4381 | pub fn containerLayout(ty: Type) std.builtin.Type.ContainerLayout { | |
| 4382 | return switch (ty.tag()) { | |
| 4383 | .tuple, .empty_struct_literal, .anon_struct => .Auto, | |
| 4384 | .@"struct" => ty.castTag(.@"struct").?.data.layout, | |
| 4385 | .@"union" => ty.castTag(.@"union").?.data.layout, | |
| 4386 | .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout, | |
| 4387 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, | |
| 2053 | pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout { | |
| 2054 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2055 | .struct_type => |struct_type| { | |
| 2056 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto; | |
| 2057 | return struct_obj.layout; | |
| 2058 | }, | |
| 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 | 2064 | else => unreachable, |
| 4389 | 2065 | }; |
| 4390 | 2066 | } |
| 4391 | 2067 | |
| 4392 | 2068 | /// Asserts that the type is an error union. |
| 4393 | pub fn errorUnionPayload(self: Type) Type { | |
| 4394 | return switch (self.tag()) { | |
| 4395 | .anyerror_void_error_union => Type.initTag(.void), | |
| 4396 | .error_union => self.castTag(.error_union).?.data.payload, | |
| 4397 | else => unreachable, | |
| 4398 | }; | |
| 2069 | pub fn errorUnionPayload(ty: Type, mod: *Module) Type { | |
| 2070 | return mod.intern_pool.indexToKey(ty.toIntern()).error_union_type.payload_type.toType(); | |
| 4399 | 2071 | } |
| 4400 | 2072 | |
| 4401 | pub fn errorUnionSet(self: Type) Type { | |
| 4402 | return switch (self.tag()) { | |
| 4403 | .anyerror_void_error_union => Type.initTag(.anyerror), | |
| 4404 | .error_union => self.castTag(.error_union).?.data.error_set, | |
| 4405 | else => unreachable, | |
| 4406 | }; | |
| 2073 | /// Asserts that the type is an error union. | |
| 2074 | pub fn errorUnionSet(ty: Type, mod: *Module) Type { | |
| 2075 | return mod.intern_pool.indexToKey(ty.toIntern()).error_union_type.error_set_type.toType(); | |
| 4407 | 2076 | } |
| 4408 | 2077 | |
| 4409 | 2078 | /// Returns false for unresolved inferred error sets. |
| 4410 | pub fn errorSetIsEmpty(ty: Type) bool { | |
| 4411 | switch (ty.tag()) { | |
| 4412 | .anyerror => return false, | |
| 4413 | .error_set_inferred => { | |
| 4414 | const inferred_error_set = ty.castTag(.error_set_inferred).?.data; | |
| 4415 | // Can't know for sure. | |
| 4416 | if (!inferred_error_set.is_resolved) return false; | |
| 4417 | if (inferred_error_set.is_anyerror) return false; | |
| 4418 | return inferred_error_set.errors.count() == 0; | |
| 4419 | }, | |
| 4420 | .error_set_single => return false, | |
| 4421 | .error_set => { | |
| 4422 | const err_set_obj = ty.castTag(.error_set).?.data; | |
| 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; | |
| 2079 | pub fn errorSetIsEmpty(ty: Type, mod: *Module) bool { | |
| 2080 | return switch (ty.toIntern()) { | |
| 2081 | .anyerror_type => false, | |
| 2082 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2083 | .error_set_type => |error_set_type| error_set_type.names.len == 0, | |
| 2084 | .inferred_error_set_type => |index| { | |
| 2085 | const inferred_error_set = mod.inferredErrorSetPtr(index); | |
| 2086 | // Can't know for sure. | |
| 2087 | if (!inferred_error_set.is_resolved) return false; | |
| 2088 | if (inferred_error_set.is_anyerror) return false; | |
| 2089 | return inferred_error_set.errors.count() == 0; | |
| 2090 | }, | |
| 2091 | else => unreachable, | |
| 4428 | 2092 | }, |
| 4429 | else => unreachable, | |
| 4430 | } | |
| 2093 | }; | |
| 4431 | 2094 | } |
| 4432 | 2095 | |
| 4433 | 2096 | /// Returns true if it is an error set that includes anyerror, false otherwise. |
| 4434 | 2097 | /// Note that the result may be a false negative if the type did not get error set |
| 4435 | 2098 | /// resolution prior to this call. |
| 4436 | pub fn isAnyError(ty: Type) bool { | |
| 4437 | return switch (ty.tag()) { | |
| 4438 | .anyerror => true, | |
| 4439 | .error_set_inferred => ty.castTag(.error_set_inferred).?.data.is_anyerror, | |
| 4440 | else => false, | |
| 2099 | pub fn isAnyError(ty: Type, mod: *Module) bool { | |
| 2100 | return switch (ty.toIntern()) { | |
| 2101 | .anyerror_type => true, | |
| 2102 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 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 { | |
| 4445 | return switch (ty.zigTypeTag()) { | |
| 2109 | pub fn isError(ty: Type, mod: *const Module) bool { | |
| 2110 | return switch (ty.zigTypeTag(mod)) { | |
| 4446 | 2111 | .ErrorUnion, .ErrorSet => true, |
| 4447 | 2112 | else => false, |
| 4448 | 2113 | }; |
| ... | ... | @@ -4451,230 +2116,221 @@ pub const Type = extern union { |
| 4451 | 2116 | /// Returns whether ty, which must be an error set, includes an error `name`. |
| 4452 | 2117 | /// Might return a false negative if `ty` is an inferred error set and not fully |
| 4453 | 2118 | /// resolved yet. |
| 4454 | pub fn errorSetHasField(ty: Type, name: []const u8) bool { | |
| 4455 | if (ty.isAnyError()) { | |
| 4456 | return true; | |
| 4457 | } | |
| 4458 | ||
| 4459 | switch (ty.tag()) { | |
| 4460 | .error_set_single => { | |
| 4461 | const data = ty.castTag(.error_set_single).?.data; | |
| 4462 | return std.mem.eql(u8, data, name); | |
| 4463 | }, | |
| 4464 | .error_set_inferred => { | |
| 4465 | const data = ty.castTag(.error_set_inferred).?.data; | |
| 4466 | return data.errors.contains(name); | |
| 4467 | }, | |
| 4468 | .error_set_merged => { | |
| 4469 | const data = ty.castTag(.error_set_merged).?.data; | |
| 4470 | return data.contains(name); | |
| 2119 | pub fn errorSetHasFieldIp( | |
| 2120 | ip: *const InternPool, | |
| 2121 | ty: InternPool.Index, | |
| 2122 | name: InternPool.NullTerminatedString, | |
| 2123 | ) bool { | |
| 2124 | return switch (ty) { | |
| 2125 | .anyerror_type => true, | |
| 2126 | else => switch (ip.indexToKey(ty)) { | |
| 2127 | .error_set_type => |error_set_type| { | |
| 2128 | return error_set_type.nameIndex(ip, name) != null; | |
| 2129 | }, | |
| 2130 | .inferred_error_set_type => |index| { | |
| 2131 | const ies = ip.inferredErrorSetPtrConst(index); | |
| 2132 | if (ies.is_anyerror) return true; | |
| 2133 | return ies.errors.contains(name); | |
| 2134 | }, | |
| 2135 | else => unreachable, | |
| 4471 | 2136 | }, |
| 4472 | .error_set => { | |
| 4473 | const data = ty.castTag(.error_set).?.data; | |
| 4474 | return data.names.contains(name); | |
| 2137 | }; | |
| 2138 | } | |
| 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, | |
| 4477 | } | |
| 2162 | }; | |
| 4478 | 2163 | } |
| 4479 | 2164 | |
| 4480 | 2165 | /// Asserts the type is an array or vector or struct. |
| 4481 | pub fn arrayLen(ty: Type) u64 { | |
| 4482 | return switch (ty.tag()) { | |
| 4483 | .vector => ty.castTag(.vector).?.data.len, | |
| 4484 | .array => ty.castTag(.array).?.data.len, | |
| 4485 | .array_sentinel => ty.castTag(.array_sentinel).?.data.len, | |
| 4486 | .array_u8 => ty.castTag(.array_u8).?.data, | |
| 4487 | .array_u8_sentinel_0 => ty.castTag(.array_u8_sentinel_0).?.data, | |
| 4488 | .tuple => ty.castTag(.tuple).?.data.types.len, | |
| 4489 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, | |
| 4490 | .@"struct" => ty.castTag(.@"struct").?.data.fields.count(), | |
| 4491 | .empty_struct, .empty_struct_literal => 0, | |
| 2166 | pub fn arrayLen(ty: Type, mod: *const Module) u64 { | |
| 2167 | return arrayLenIp(ty, &mod.intern_pool); | |
| 2168 | } | |
| 2169 | ||
| 2170 | pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 { | |
| 2171 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 2172 | .vector_type => |vector_type| vector_type.len, | |
| 2173 | .array_type => |array_type| array_type.len, | |
| 2174 | .struct_type => |struct_type| { | |
| 2175 | const struct_obj = ip.structPtrUnwrapConst(struct_type.index) orelse return 0; | |
| 2176 | return struct_obj.fields.count(); | |
| 2177 | }, | |
| 2178 | .anon_struct_type => |tuple| tuple.types.len, | |
| 4492 | 2179 | |
| 4493 | 2180 | else => unreachable, |
| 4494 | 2181 | }; |
| 4495 | 2182 | } |
| 4496 | 2183 | |
| 4497 | pub fn arrayLenIncludingSentinel(ty: Type) u64 { | |
| 4498 | return ty.arrayLen() + @boolToInt(ty.sentinel() != null); | |
| 2184 | pub fn arrayLenIncludingSentinel(ty: Type, mod: *const Module) u64 { | |
| 2185 | return ty.arrayLen(mod) + @boolToInt(ty.sentinel(mod) != null); | |
| 4499 | 2186 | } |
| 4500 | 2187 | |
| 4501 | pub fn vectorLen(ty: Type) u32 { | |
| 4502 | return switch (ty.tag()) { | |
| 4503 | .vector => @intCast(u32, ty.castTag(.vector).?.data.len), | |
| 4504 | .tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len), | |
| 4505 | .anon_struct => @intCast(u32, ty.castTag(.anon_struct).?.data.types.len), | |
| 2188 | pub fn vectorLen(ty: Type, mod: *const Module) u32 { | |
| 2189 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2190 | .vector_type => |vector_type| vector_type.len, | |
| 2191 | .anon_struct_type => |tuple| @intCast(u32, tuple.types.len), | |
| 4506 | 2192 | else => unreachable, |
| 4507 | 2193 | }; |
| 4508 | 2194 | } |
| 4509 | 2195 | |
| 4510 | 2196 | /// Asserts the type is an array, pointer or vector. |
| 4511 | pub fn sentinel(self: Type) ?Value { | |
| 4512 | return switch (self.tag()) { | |
| 4513 | .single_const_pointer, | |
| 4514 | .single_mut_pointer, | |
| 4515 | .many_const_pointer, | |
| 4516 | .many_mut_pointer, | |
| 4517 | .c_const_pointer, | |
| 4518 | .c_mut_pointer, | |
| 4519 | .single_const_pointer_to_comptime_int, | |
| 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, | |
| 2197 | pub fn sentinel(ty: Type, mod: *const Module) ?Value { | |
| 2198 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2199 | .vector_type, | |
| 2200 | .struct_type, | |
| 2201 | .anon_struct_type, | |
| 2202 | => null, | |
| 2203 | ||
| 2204 | .array_type => |t| if (t.sentinel != .none) t.sentinel.toValue() else null, | |
| 2205 | .ptr_type => |t| if (t.sentinel != .none) t.sentinel.toValue() else null, | |
| 4540 | 2206 | |
| 4541 | 2207 | else => unreachable, |
| 4542 | 2208 | }; |
| 4543 | 2209 | } |
| 4544 | 2210 | |
| 4545 | 2211 | /// Returns true if and only if the type is a fixed-width integer. |
| 4546 | pub fn isInt(self: Type) bool { | |
| 4547 | return self.isSignedInt() or self.isUnsignedInt(); | |
| 2212 | pub fn isInt(self: Type, mod: *const Module) bool { | |
| 2213 | return self.isSignedInt(mod) or self.isUnsignedInt(mod); | |
| 4548 | 2214 | } |
| 4549 | 2215 | |
| 4550 | 2216 | /// Returns true if and only if the type is a fixed-width, signed integer. |
| 4551 | pub fn isSignedInt(self: Type) bool { | |
| 4552 | return switch (self.tag()) { | |
| 4553 | .int_signed, | |
| 4554 | .i8, | |
| 4555 | .isize, | |
| 4556 | .c_char, | |
| 4557 | .c_short, | |
| 4558 | .c_int, | |
| 4559 | .c_long, | |
| 4560 | .c_longlong, | |
| 4561 | .i16, | |
| 4562 | .i32, | |
| 4563 | .i64, | |
| 4564 | .i128, | |
| 4565 | => true, | |
| 4566 | ||
| 4567 | else => false, | |
| 2217 | pub fn isSignedInt(ty: Type, mod: *const Module) bool { | |
| 2218 | return switch (ty.toIntern()) { | |
| 2219 | .c_char_type, .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true, | |
| 2220 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2221 | .int_type => |int_type| int_type.signedness == .signed, | |
| 2222 | else => false, | |
| 2223 | }, | |
| 4568 | 2224 | }; |
| 4569 | 2225 | } |
| 4570 | 2226 | |
| 4571 | 2227 | /// Returns true if and only if the type is a fixed-width, unsigned integer. |
| 4572 | pub fn isUnsignedInt(self: Type) bool { | |
| 4573 | return switch (self.tag()) { | |
| 4574 | .int_unsigned, | |
| 4575 | .usize, | |
| 4576 | .c_ushort, | |
| 4577 | .c_uint, | |
| 4578 | .c_ulong, | |
| 4579 | .c_ulonglong, | |
| 4580 | .u1, | |
| 4581 | .u8, | |
| 4582 | .u16, | |
| 4583 | .u29, | |
| 4584 | .u32, | |
| 4585 | .u64, | |
| 4586 | .u128, | |
| 4587 | => true, | |
| 4588 | ||
| 4589 | else => false, | |
| 2228 | pub fn isUnsignedInt(ty: Type, mod: *const Module) bool { | |
| 2229 | return switch (ty.toIntern()) { | |
| 2230 | .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true, | |
| 2231 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2232 | .int_type => |int_type| int_type.signedness == .unsigned, | |
| 2233 | else => false, | |
| 2234 | }, | |
| 4590 | 2235 | }; |
| 4591 | 2236 | } |
| 4592 | 2237 | |
| 4593 | 2238 | /// Returns true for integers, enums, error sets, and packed structs. |
| 4594 | 2239 | /// If this function returns true, then intInfo() can be called on the type. |
| 4595 | pub fn isAbiInt(ty: Type) bool { | |
| 4596 | return switch (ty.zigTypeTag()) { | |
| 2240 | pub fn isAbiInt(ty: Type, mod: *Module) bool { | |
| 2241 | return switch (ty.zigTypeTag(mod)) { | |
| 4597 | 2242 | .Int, .Enum, .ErrorSet => true, |
| 4598 | .Struct => ty.containerLayout() == .Packed, | |
| 2243 | .Struct => ty.containerLayout(mod) == .Packed, | |
| 4599 | 2244 | else => false, |
| 4600 | 2245 | }; |
| 4601 | 2246 | } |
| 4602 | 2247 | |
| 4603 | 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 { | |
| 4605 | var ty = self; | |
| 4606 | while (true) switch (ty.tag()) { | |
| 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 | }, | |
| 2249 | pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType { | |
| 2250 | const target = mod.getTarget(); | |
| 2251 | var ty = starting_ty; | |
| 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 | 2255 | // TODO revisit this when error sets support custom int types |
| 4650 | 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, | |
| 4654 | ||
| 4655 | .@"struct" => { | |
| 4656 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 4657 | assert(struct_obj.layout == .Packed); | |
| 4658 | ty = struct_obj.backing_int_ty; | |
| 4659 | }, | |
| 4660 | ||
| 4661 | else => unreachable, | |
| 4662 | }; | |
| 4663 | } | |
| 4664 | ||
| 4665 | pub fn isNamedInt(self: Type) bool { | |
| 4666 | return switch (self.tag()) { | |
| 4667 | .usize, | |
| 4668 | .isize, | |
| 4669 | .c_char, | |
| 4670 | .c_short, | |
| 4671 | .c_ushort, | |
| 4672 | .c_int, | |
| 4673 | .c_uint, | |
| 4674 | .c_long, | |
| 4675 | .c_ulong, | |
| 4676 | .c_longlong, | |
| 4677 | .c_ulonglong, | |
| 2279 | // TODO revisit this when error sets support custom int types | |
| 2280 | .error_set_type, .inferred_error_set_type => return .{ .signedness = .unsigned, .bits = 16 }, | |
| 2281 | ||
| 2282 | .anon_struct_type => unreachable, | |
| 2283 | ||
| 2284 | .ptr_type => unreachable, | |
| 2285 | .anyframe_type => unreachable, | |
| 2286 | .array_type => unreachable, | |
| 2287 | ||
| 2288 | .opt_type => unreachable, | |
| 2289 | .error_union_type => unreachable, | |
| 2290 | .func_type => unreachable, | |
| 2291 | .simple_type => unreachable, // handled via Index enum tag above | |
| 2292 | ||
| 2293 | .union_type => unreachable, | |
| 2294 | .opaque_type => unreachable, | |
| 2295 | ||
| 2296 | // values, not types | |
| 2297 | .undef, | |
| 2298 | .runtime_value, | |
| 2299 | .simple_value, | |
| 2300 | .variable, | |
| 2301 | .extern_func, | |
| 2302 | .func, | |
| 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 | 2334 | => true, |
| 4679 | 2335 | |
| 4680 | 2336 | else => false, |
| ... | ... | @@ -4682,14 +2338,14 @@ pub const Type = extern union { |
| 4682 | 2338 | } |
| 4683 | 2339 | |
| 4684 | 2340 | /// Returns `false` for `comptime_float`. |
| 4685 | pub fn isRuntimeFloat(self: Type) bool { | |
| 4686 | return switch (self.tag()) { | |
| 4687 | .f16, | |
| 4688 | .f32, | |
| 4689 | .f64, | |
| 4690 | .f80, | |
| 4691 | .f128, | |
| 4692 | .c_longdouble, | |
| 2341 | pub fn isRuntimeFloat(ty: Type) bool { | |
| 2342 | return switch (ty.toIntern()) { | |
| 2343 | .f16_type, | |
| 2344 | .f32_type, | |
| 2345 | .f64_type, | |
| 2346 | .f80_type, | |
| 2347 | .f128_type, | |
| 2348 | .c_longdouble_type, | |
| 4693 | 2349 | => true, |
| 4694 | 2350 | |
| 4695 | 2351 | else => false, |
| ... | ... | @@ -4697,15 +2353,15 @@ pub const Type = extern union { |
| 4697 | 2353 | } |
| 4698 | 2354 | |
| 4699 | 2355 | /// Returns `true` for `comptime_float`. |
| 4700 | pub fn isAnyFloat(self: Type) bool { | |
| 4701 | return switch (self.tag()) { | |
| 4702 | .f16, | |
| 4703 | .f32, | |
| 4704 | .f64, | |
| 4705 | .f80, | |
| 4706 | .f128, | |
| 4707 | .c_longdouble, | |
| 4708 | .comptime_float, | |
| 2356 | pub fn isAnyFloat(ty: Type) bool { | |
| 2357 | return switch (ty.toIntern()) { | |
| 2358 | .f16_type, | |
| 2359 | .f32_type, | |
| 2360 | .f64_type, | |
| 2361 | .f80_type, | |
| 2362 | .f128_type, | |
| 2363 | .c_longdouble_type, | |
| 2364 | .comptime_float_type, | |
| 4709 | 2365 | => true, |
| 4710 | 2366 | |
| 4711 | 2367 | else => false, |
| ... | ... | @@ -4714,431 +2370,304 @@ pub const Type = extern union { |
| 4714 | 2370 | |
| 4715 | 2371 | /// Asserts the type is a fixed-size float or comptime_float. |
| 4716 | 2372 | /// Returns 128 for comptime_float types. |
| 4717 | pub fn floatBits(self: Type, target: Target) u16 { | |
| 4718 | return switch (self.tag()) { | |
| 4719 | .f16 => 16, | |
| 4720 | .f32 => 32, | |
| 4721 | .f64 => 64, | |
| 4722 | .f80 => 80, | |
| 4723 | .f128, .comptime_float => 128, | |
| 4724 | .c_longdouble => 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, | |
| 2373 | pub fn floatBits(ty: Type, target: Target) u16 { | |
| 2374 | return switch (ty.toIntern()) { | |
| 2375 | .f16_type => 16, | |
| 2376 | .f32_type => 32, | |
| 2377 | .f64_type => 64, | |
| 2378 | .f80_type => 80, | |
| 2379 | .f128_type, .comptime_float_type => 128, | |
| 2380 | .c_longdouble_type => target.c_type_bit_size(.longdouble), | |
| 4738 | 2381 | |
| 4739 | 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 | |
| 4744 | /// given by `fnParamLen`. | |
| 4745 | pub fn fnParamTypes(self: Type, types: []Type) void { | |
| 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 | }; | |
| 2386 | /// Asserts the type is a function or a function pointer. | |
| 2387 | pub fn fnReturnType(ty: Type, mod: *Module) Type { | |
| 2388 | return fnReturnTypeIp(ty, &mod.intern_pool); | |
| 4786 | 2389 | } |
| 4787 | 2390 | |
| 4788 | /// Asserts the type is a function. | |
| 4789 | pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention { | |
| 4790 | return switch (self.tag()) { | |
| 4791 | .fn_noreturn_no_args => .Unspecified, | |
| 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 | ||
| 2391 | pub fn fnReturnTypeIp(ty: Type, ip: *const InternPool) Type { | |
| 2392 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 2393 | .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type.return_type, | |
| 2394 | .func_type => |func_type| func_type.return_type, | |
| 4797 | 2395 | else => unreachable, |
| 4798 | }; | |
| 2396 | }.toType(); | |
| 4799 | 2397 | } |
| 4800 | 2398 | |
| 4801 | 2399 | /// Asserts the type is a function. |
| 4802 | pub fn fnCallingConventionAllowsZigTypes(target: Target, cc: std.builtin.CallingConvention) bool { | |
| 4803 | return switch (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 | }; | |
| 2400 | pub fn fnCallingConvention(ty: Type, mod: *Module) std.builtin.CallingConvention { | |
| 2401 | return mod.intern_pool.indexToKey(ty.toIntern()).func_type.cc; | |
| 4810 | 2402 | } |
| 4811 | 2403 | |
| 4812 | pub fn isValidParamType(self: Type) bool { | |
| 4813 | return switch (self.zigTypeTagOrPoison() catch return true) { | |
| 2404 | pub fn isValidParamType(self: Type, mod: *const Module) bool { | |
| 2405 | return switch (self.zigTypeTagOrPoison(mod) catch return true) { | |
| 4814 | 2406 | .Undefined, .Null, .Opaque, .NoReturn => false, |
| 4815 | 2407 | else => true, |
| 4816 | 2408 | }; |
| 4817 | 2409 | } |
| 4818 | 2410 | |
| 4819 | pub fn isValidReturnType(self: Type) bool { | |
| 4820 | return switch (self.zigTypeTagOrPoison() catch return true) { | |
| 2411 | pub fn isValidReturnType(self: Type, mod: *const Module) bool { | |
| 2412 | return switch (self.zigTypeTagOrPoison(mod) catch return true) { | |
| 4821 | 2413 | .Undefined, .Null, .Opaque => false, |
| 4822 | 2414 | else => true, |
| 4823 | 2415 | }; |
| 4824 | 2416 | } |
| 4825 | 2417 | |
| 4826 | 2418 | /// Asserts the type is a function. |
| 4827 | pub fn fnIsVarArgs(self: Type) bool { | |
| 4828 | return switch (self.tag()) { | |
| 4829 | .fn_noreturn_no_args => false, | |
| 4830 | .fn_void_no_args => false, | |
| 4831 | .fn_naked_noreturn_no_args => false, | |
| 4832 | .fn_ccc_void_no_args => false, | |
| 4833 | .function => self.castTag(.function).?.data.is_var_args, | |
| 4834 | ||
| 4835 | else => unreachable, | |
| 4836 | }; | |
| 4837 | } | |
| 4838 | ||
| 4839 | pub fn fnInfo(ty: Type) Payload.Function.Data { | |
| 4840 | return switch (ty.tag()) { | |
| 4841 | .fn_noreturn_no_args => .{ | |
| 4842 | .param_types = &.{}, | |
| 4843 | .comptime_params = undefined, | |
| 4844 | .return_type = initTag(.noreturn), | |
| 4845 | .cc = .Unspecified, | |
| 4846 | .alignment = 0, | |
| 4847 | .is_var_args = false, | |
| 4848 | .is_generic = false, | |
| 4849 | .is_noinline = false, | |
| 4850 | .align_is_generic = false, | |
| 4851 | .cc_is_generic = false, | |
| 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, | |
| 2419 | pub fn fnIsVarArgs(ty: Type, mod: *Module) bool { | |
| 2420 | return mod.intern_pool.indexToKey(ty.toIntern()).func_type.is_var_args; | |
| 2421 | } | |
| 2422 | ||
| 2423 | pub fn isNumeric(ty: Type, mod: *const Module) bool { | |
| 2424 | return switch (ty.toIntern()) { | |
| 2425 | .f16_type, | |
| 2426 | .f32_type, | |
| 2427 | .f64_type, | |
| 2428 | .f80_type, | |
| 2429 | .f128_type, | |
| 2430 | .c_longdouble_type, | |
| 2431 | .comptime_int_type, | |
| 2432 | .comptime_float_type, | |
| 2433 | .usize_type, | |
| 2434 | .isize_type, | |
| 2435 | .c_char_type, | |
| 2436 | .c_short_type, | |
| 2437 | .c_ushort_type, | |
| 2438 | .c_int_type, | |
| 2439 | .c_uint_type, | |
| 2440 | .c_long_type, | |
| 2441 | .c_ulong_type, | |
| 2442 | .c_longlong_type, | |
| 2443 | .c_ulonglong_type, | |
| 4942 | 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 | 2453 | /// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which |
| 4949 | 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 | 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" => { | |
| 5046 | const s = ty.castTag(.@"struct").?.data; | |
| 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 | }, | |
| 2458 | while (true) switch (ty.toIntern()) { | |
| 2459 | .empty_struct_type => return Value.empty_struct, | |
| 5055 | 2460 | |
| 5056 | .tuple, .anon_struct => { | |
| 5057 | const tuple = ty.tupleFields(); | |
| 5058 | for (tuple.values, 0..) |val, i| { | |
| 5059 | const is_comptime = val.tag() != .unreachable_value; | |
| 5060 | if (is_comptime) continue; | |
| 5061 | if (tuple.types[i].onePossibleValue() != null) continue; | |
| 5062 | return null; | |
| 5063 | } | |
| 5064 | return Value.initTag(.empty_struct_value); | |
| 5065 | }, | |
| 2461 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2462 | .int_type => |int_type| { | |
| 2463 | if (int_type.bits == 0) { | |
| 2464 | return try mod.intValue(ty, 0); | |
| 2465 | } else { | |
| 2466 | return null; | |
| 2467 | } | |
| 2468 | }, | |
| 5066 | 2469 | |
| 5067 | .enum_numbered => { | |
| 5068 | const enum_numbered = ty.castTag(.enum_numbered).?.data; | |
| 5069 | // An explicit tag type is always provided for enum_numbered. | |
| 5070 | if (enum_numbered.tag_ty.hasRuntimeBits()) { | |
| 5071 | return null; | |
| 5072 | } | |
| 5073 | assert(enum_numbered.fields.count() == 1); | |
| 5074 | return enum_numbered.values.keys()[0]; | |
| 5075 | }, | |
| 5076 | .enum_full => { | |
| 5077 | const enum_full = ty.castTag(.enum_full).?.data; | |
| 5078 | if (enum_full.tag_ty.hasRuntimeBits()) { | |
| 2470 | .ptr_type, | |
| 2471 | .error_union_type, | |
| 2472 | .func_type, | |
| 2473 | .anyframe_type, | |
| 2474 | .error_set_type, | |
| 2475 | .inferred_error_set_type, | |
| 2476 | => return null, | |
| 2477 | ||
| 2478 | inline .array_type, .vector_type => |seq_type, seq_tag| { | |
| 2479 | const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none; | |
| 2480 | if (seq_type.len + @boolToInt(has_sentinel) == 0) return (try mod.intern(.{ .aggregate = .{ | |
| 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 | 2490 | return null; |
| 5080 | } | |
| 5081 | switch (enum_full.fields.count()) { | |
| 5082 | 0 => return Value.initTag(.unreachable_value), | |
| 5083 | 1 => if (enum_full.values.count() == 0) { | |
| 5084 | return Value.zero; // auto-numbered | |
| 2491 | }, | |
| 2492 | .opt_type => |child| { | |
| 2493 | if (child == .noreturn_type) { | |
| 2494 | return try mod.nullValue(ty); | |
| 5085 | 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, | |
| 5089 | } | |
| 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 | }, | |
| 2622 | .auto, .explicit => { | |
| 2623 | if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; | |
| 5117 | 2624 | |
| 5118 | .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), | |
| 5119 | .void => return Value.initTag(.void_value), | |
| 5120 | .noreturn => return Value.initTag(.unreachable_value), | |
| 5121 | .null => return Value.initTag(.null_value), | |
| 5122 | .undefined => return Value.initTag(.undef), | |
| 2625 | switch (enum_type.names.len) { | |
| 2626 | 0 => { | |
| 2627 | const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); | |
| 2628 | return only.toValue(); | |
| 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 => { | |
| 5125 | if (ty.cast(Payload.Bits).?.data == 0) { | |
| 5126 | return Value.zero; | |
| 5127 | } else { | |
| 5128 | return null; | |
| 5129 | } | |
| 5130 | }, | |
| 5131 | .vector, .array, .array_u8 => { | |
| 5132 | if (ty.arrayLen() == 0) | |
| 5133 | return Value.initTag(.empty_array); | |
| 5134 | if (ty.elemType().onePossibleValue() != null) | |
| 5135 | return Value.initTag(.the_only_possible_value); | |
| 5136 | return null; | |
| 2649 | // values, not types | |
| 2650 | .undef, | |
| 2651 | .runtime_value, | |
| 2652 | .simple_value, | |
| 2653 | .variable, | |
| 2654 | .extern_func, | |
| 2655 | .func, | |
| 2656 | .int, | |
| 2657 | .err, | |
| 2658 | .error_union, | |
| 2659 | .enum_literal, | |
| 2660 | .enum_tag, | |
| 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 | 2675 | /// resolves field types rather than asserting they are already resolved. |
| 5147 | 2676 | /// TODO merge these implementations together with the "advanced" pattern seen |
| 5148 | 2677 | /// elsewhere in this file. |
| 5149 | pub fn comptimeOnly(ty: Type) bool { | |
| 5150 | return switch (ty.tag()) { | |
| 5151 | .u1, | |
| 5152 | .u8, | |
| 5153 | .i8, | |
| 5154 | .u16, | |
| 5155 | .i16, | |
| 5156 | .u29, | |
| 5157 | .u32, | |
| 5158 | .i32, | |
| 5159 | .u64, | |
| 5160 | .i64, | |
| 5161 | .u128, | |
| 5162 | .i128, | |
| 5163 | .usize, | |
| 5164 | .isize, | |
| 5165 | .c_char, | |
| 5166 | .c_short, | |
| 5167 | .c_ushort, | |
| 5168 | .c_int, | |
| 5169 | .c_uint, | |
| 5170 | .c_long, | |
| 5171 | .c_ulong, | |
| 5172 | .c_longlong, | |
| 5173 | .c_ulonglong, | |
| 5174 | .c_longdouble, | |
| 5175 | .f16, | |
| 5176 | .f32, | |
| 5177 | .f64, | |
| 5178 | .f80, | |
| 5179 | .f128, | |
| 5180 | .anyopaque, | |
| 5181 | .bool, | |
| 5182 | .void, | |
| 5183 | .anyerror, | |
| 5184 | .noreturn, | |
| 5185 | .@"anyframe", | |
| 5186 | .null, | |
| 5187 | .undefined, | |
| 5188 | .atomic_order, | |
| 5189 | .atomic_rmw_op, | |
| 5190 | .calling_convention, | |
| 5191 | .address_space, | |
| 5192 | .float_mode, | |
| 5193 | .reduce_op, | |
| 5194 | .modifier, | |
| 5195 | .prefetch_options, | |
| 5196 | .export_options, | |
| 5197 | .extern_options, | |
| 5198 | .manyptr_u8, | |
| 5199 | .manyptr_const_u8, | |
| 5200 | .manyptr_const_u8_sentinel_0, | |
| 5201 | .const_slice_u8, | |
| 5202 | .const_slice_u8_sentinel_0, | |
| 5203 | .anyerror_void_error_union, | |
| 5204 | .empty_struct_literal, | |
| 5205 | .empty_struct, | |
| 5206 | .error_set, | |
| 5207 | .error_set_single, | |
| 5208 | .error_set_inferred, | |
| 5209 | .error_set_merged, | |
| 5210 | .@"opaque", | |
| 5211 | .generic_poison, | |
| 5212 | .array_u8, | |
| 5213 | .array_u8_sentinel_0, | |
| 5214 | .int_signed, | |
| 5215 | .int_unsigned, | |
| 5216 | .enum_simple, | |
| 5217 | => false, | |
| 5218 | ||
| 5219 | .single_const_pointer_to_comptime_int, | |
| 5220 | .type, | |
| 5221 | .comptime_int, | |
| 5222 | .comptime_float, | |
| 5223 | .enum_literal, | |
| 5224 | .type_info, | |
| 5225 | // These are function bodies, not function pointers. | |
| 5226 | .fn_noreturn_no_args, | |
| 5227 | .fn_void_no_args, | |
| 5228 | .fn_naked_noreturn_no_args, | |
| 5229 | .fn_ccc_void_no_args, | |
| 5230 | .function, | |
| 5231 | => true, | |
| 2678 | pub fn comptimeOnly(ty: Type, mod: *Module) bool { | |
| 2679 | return switch (ty.toIntern()) { | |
| 2680 | .empty_struct_type => false, | |
| 2681 | ||
| 2682 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2683 | .int_type => false, | |
| 2684 | .ptr_type => |ptr_type| { | |
| 2685 | const child_ty = ptr_type.child.toType(); | |
| 2686 | if (child_ty.zigTypeTag(mod) == .Fn) { | |
| 2687 | return false; | |
| 2688 | } else { | |
| 2689 | return child_ty.comptimeOnly(mod); | |
| 2690 | } | |
| 2691 | }, | |
| 2692 | .anyframe_type => |child| { | |
| 2693 | if (child == .none) return false; | |
| 2694 | return child.toType().comptimeOnly(mod); | |
| 2695 | }, | |
| 2696 | .array_type => |array_type| array_type.child.toType().comptimeOnly(mod), | |
| 2697 | .vector_type => |vector_type| vector_type.child.toType().comptimeOnly(mod), | |
| 2698 | .opt_type => |child| child.toType().comptimeOnly(mod), | |
| 2699 | .error_union_type => |error_union_type| error_union_type.payload_type.toType().comptimeOnly(mod), | |
| 2700 | ||
| 2701 | .error_set_type, | |
| 2702 | .inferred_error_set_type, | |
| 2703 | => false, | |
| 2704 | ||
| 2705 | // These are function bodies, not function pointers. | |
| 2706 | .func_type => true, | |
| 2707 | ||
| 2708 | .simple_type => |t| switch (t) { | |
| 2709 | .f16, | |
| 2710 | .f32, | |
| 2711 | .f64, | |
| 2712 | .f80, | |
| 2713 | .f128, | |
| 2714 | .usize, | |
| 2715 | .isize, | |
| 2716 | .c_char, | |
| 2717 | .c_short, | |
| 2718 | .c_ushort, | |
| 2719 | .c_int, | |
| 2720 | .c_uint, | |
| 2721 | .c_long, | |
| 2722 | .c_ulong, | |
| 2723 | .c_longlong, | |
| 2724 | .c_ulonglong, | |
| 2725 | .c_longdouble, | |
| 2726 | .anyopaque, | |
| 2727 | .bool, | |
| 2728 | .void, | |
| 2729 | .anyerror, | |
| 2730 | .noreturn, | |
| 2731 | .generic_poison, | |
| 2732 | .atomic_order, | |
| 2733 | .atomic_rmw_op, | |
| 2734 | .calling_convention, | |
| 2735 | .address_space, | |
| 2736 | .float_mode, | |
| 2737 | .reduce_op, | |
| 2738 | .call_modifier, | |
| 2739 | .prefetch_options, | |
| 2740 | .export_options, | |
| 2741 | .extern_options, | |
| 2742 | => false, | |
| 2743 | ||
| 2744 | .type, | |
| 2745 | .comptime_int, | |
| 2746 | .comptime_float, | |
| 2747 | .null, | |
| 2748 | .undefined, | |
| 2749 | .enum_literal, | |
| 2750 | .type_info, | |
| 2751 | => true, | |
| 2752 | }, | |
| 2753 | .struct_type => |struct_type| { | |
| 2754 | // A struct with no fields is not comptime-only. | |
| 2755 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | |
| 2756 | switch (struct_obj.requires_comptime) { | |
| 2757 | .wip, .unknown => { | |
| 2758 | // Return false to avoid incorrect dependency loops. | |
| 2759 | // This will be handled correctly once merged with | |
| 2760 | // `Sema.typeRequiresComptime`. | |
| 2761 | return false; | |
| 2762 | }, | |
| 2763 | .no => return false, | |
| 2764 | .yes => return true, | |
| 2765 | } | |
| 2766 | }, | |
| 5232 | 2767 | |
| 5233 | .inferred_alloc_mut => unreachable, | |
| 5234 | .inferred_alloc_const => unreachable, | |
| 5235 | ||
| 5236 | .array, | |
| 5237 | .array_sentinel, | |
| 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) { | |
| 2768 | .anon_struct_type => |tuple| { | |
| 2769 | for (tuple.types, tuple.values) |field_ty, val| { | |
| 2770 | const have_comptime_val = val != .none; | |
| 2771 | if (!have_comptime_val and field_ty.toType().comptimeOnly(mod)) return true; | |
| 2772 | } | |
| 5253 | 2773 | return false; |
| 5254 | } else { | |
| 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 | }, | |
| 2774 | }, | |
| 5266 | 2775 | |
| 5267 | .tuple, .anon_struct => { | |
| 5268 | const tuple = ty.tupleFields(); | |
| 5269 | for (tuple.types, 0..) |field_ty, i| { | |
| 5270 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | |
| 5271 | if (!have_comptime_val and field_ty.comptimeOnly()) return true; | |
| 5272 | } | |
| 5273 | return false; | |
| 5274 | }, | |
| 2776 | .union_type => |union_type| { | |
| 2777 | const union_obj = mod.unionPtr(union_type.index); | |
| 2778 | switch (union_obj.requires_comptime) { | |
| 2779 | .wip, .unknown => { | |
| 2780 | // Return false to avoid incorrect dependency loops. | |
| 2781 | // This will be handled correctly once merged with | |
| 2782 | // `Sema.typeRequiresComptime`. | |
| 2783 | return false; | |
| 2784 | }, | |
| 2785 | .no => return false, | |
| 2786 | .yes => return true, | |
| 2787 | } | |
| 2788 | }, | |
| 5275 | 2789 | |
| 5276 | .@"struct" => { | |
| 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 | }, | |
| 2790 | .opaque_type => false, | |
| 5289 | 2791 | |
| 5290 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 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 | }, | |
| 2792 | .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod), | |
| 5303 | 2793 | |
| 5304 | .error_union => return ty.errorUnionPayload().comptimeOnly(), | |
| 5305 | .anyframe_T => { | |
| 5306 | const child_ty = ty.castTag(.anyframe_T).?.data; | |
| 5307 | return child_ty.comptimeOnly(); | |
| 5308 | }, | |
| 5309 | .enum_numbered => { | |
| 5310 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; | |
| 5311 | return tag_ty.comptimeOnly(); | |
| 5312 | }, | |
| 5313 | .enum_full, .enum_nonexhaustive => { | |
| 5314 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; | |
| 5315 | return tag_ty.comptimeOnly(); | |
| 2794 | // values, not types | |
| 2795 | .undef, | |
| 2796 | .runtime_value, | |
| 2797 | .simple_value, | |
| 2798 | .variable, | |
| 2799 | .extern_func, | |
| 2800 | .func, | |
| 2801 | .int, | |
| 2802 | .err, | |
| 2803 | .error_union, | |
| 2804 | .enum_literal, | |
| 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 { | |
| 5321 | return switch (ty.zigTypeTag()) { | |
| 2819 | pub fn isVector(ty: Type, mod: *const Module) bool { | |
| 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 | 2825 | .Array, .Vector => true, |
| 5323 | 2826 | else => false, |
| 5324 | 2827 | }; |
| 5325 | 2828 | } |
| 5326 | 2829 | |
| 5327 | pub fn isIndexable(ty: Type) bool { | |
| 5328 | return switch (ty.zigTypeTag()) { | |
| 2830 | pub fn isIndexable(ty: Type, mod: *Module) bool { | |
| 2831 | return switch (ty.zigTypeTag(mod)) { | |
| 5329 | 2832 | .Array, .Vector => true, |
| 5330 | .Pointer => switch (ty.ptrSize()) { | |
| 2833 | .Pointer => switch (ty.ptrSize(mod)) { | |
| 5331 | 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 | 2838 | else => false, |
| 5336 | 2839 | }; |
| 5337 | 2840 | } |
| 5338 | 2841 | |
| 5339 | pub fn indexableHasLen(ty: Type) bool { | |
| 5340 | return switch (ty.zigTypeTag()) { | |
| 2842 | pub fn indexableHasLen(ty: Type, mod: *Module) bool { | |
| 2843 | return switch (ty.zigTypeTag(mod)) { | |
| 5341 | 2844 | .Array, .Vector => true, |
| 5342 | .Pointer => switch (ty.ptrSize()) { | |
| 2845 | .Pointer => switch (ty.ptrSize(mod)) { | |
| 5343 | 2846 | .Many, .C => false, |
| 5344 | 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 | 2851 | else => false, |
| 5349 | 2852 | }; |
| 5350 | 2853 | } |
| 5351 | 2854 | |
| 5352 | 2855 | /// Returns null if the type has no namespace. |
| 5353 | pub fn getNamespace(self: Type) ?*Module.Namespace { | |
| 5354 | return switch (self.tag()) { | |
| 5355 | .@"struct" => &self.castTag(.@"struct").?.data.namespace, | |
| 5356 | .enum_full => &self.castTag(.enum_full).?.data.namespace, | |
| 5357 | .enum_nonexhaustive => &self.castTag(.enum_nonexhaustive).?.data.namespace, | |
| 5358 | .empty_struct => self.castTag(.empty_struct).?.data, | |
| 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, | |
| 2856 | pub fn getNamespaceIndex(ty: Type, mod: *Module) Module.Namespace.OptionalIndex { | |
| 2857 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2858 | .opaque_type => |opaque_type| opaque_type.namespace.toOptional(), | |
| 2859 | .struct_type => |struct_type| struct_type.namespace, | |
| 2860 | .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(), | |
| 2861 | .enum_type => |enum_type| enum_type.namespace, | |
| 5363 | 2862 | |
| 5364 | else => null, | |
| 2863 | else => .none, | |
| 5365 | 2864 | }; |
| 5366 | 2865 | } |
| 5367 | 2866 | |
| 5368 | // Works for vectors and vectors of integers. | |
| 5369 | pub fn minInt(ty: Type, arena: Allocator, target: Target) !Value { | |
| 5370 | const scalar = try minIntScalar(ty.scalarType(), arena, target); | |
| 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 | } | |
| 2867 | /// Returns null if the type has no namespace. | |
| 2868 | pub fn getNamespace(ty: Type, mod: *Module) ?*Module.Namespace { | |
| 2869 | return if (getNamespaceIndex(ty, mod).unwrap()) |i| mod.namespacePtr(i) else null; | |
| 5376 | 2870 | } |
| 5377 | 2871 | |
| 5378 | /// Asserts that self.zigTypeTag() == .Int. | |
| 5379 | pub fn minIntScalar(ty: Type, arena: Allocator, target: Target) !Value { | |
| 5380 | assert(ty.zigTypeTag() == .Int); | |
| 5381 | const info = ty.intInfo(target); | |
| 5382 | ||
| 5383 | if (info.bits == 0) { | |
| 5384 | return Value.initTag(.the_only_possible_value); | |
| 5385 | } | |
| 2872 | // Works for vectors and vectors of integers. | |
| 2873 | pub fn minInt(ty: Type, mod: *Module, dest_ty: Type) !Value { | |
| 2874 | const scalar = try minIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod)); | |
| 2875 | return if (ty.zigTypeTag(mod) == .Vector) (try mod.intern(.{ .aggregate = .{ | |
| 2876 | .ty = dest_ty.toIntern(), | |
| 2877 | .storage = .{ .repeated_elem = scalar.toIntern() }, | |
| 2878 | } })).toValue() else scalar; | |
| 2879 | } | |
| 5386 | 2880 | |
| 5387 | if (info.signedness == .unsigned) { | |
| 5388 | return Value.zero; | |
| 5389 | } | |
| 2881 | /// Asserts that the type is an integer. | |
| 2882 | pub fn minIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value { | |
| 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 | 2887 | if (std.math.cast(u6, info.bits - 1)) |shift| { |
| 5392 | 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 | 2895 | try res.setTwosCompIntLimit(.min, info.signedness, info.bits); |
| 5398 | 2896 | |
| 5399 | const res_const = 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 | } | |
| 2897 | return mod.intValue_big(dest_ty, res.toConst()); | |
| 5405 | 2898 | } |
| 5406 | 2899 | |
| 5407 | 2900 | // Works for vectors and vectors of integers. |
| 5408 | pub fn maxInt(ty: Type, arena: Allocator, target: Target) !Value { | |
| 5409 | const scalar = try maxIntScalar(ty.scalarType(), arena, target); | |
| 5410 | if (ty.zigTypeTag() == .Vector and scalar.tag() != .the_only_possible_value) { | |
| 5411 | return Value.Tag.repeated.create(arena, scalar); | |
| 5412 | } else { | |
| 5413 | return scalar; | |
| 5414 | } | |
| 2901 | /// The returned Value will have type dest_ty. | |
| 2902 | pub fn maxInt(ty: Type, mod: *Module, dest_ty: Type) !Value { | |
| 2903 | const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod)); | |
| 2904 | return if (ty.zigTypeTag(mod) == .Vector) (try mod.intern(.{ .aggregate = .{ | |
| 2905 | .ty = dest_ty.toIntern(), | |
| 2906 | .storage = .{ .repeated_elem = scalar.toIntern() }, | |
| 2907 | } })).toValue() else scalar; | |
| 5415 | 2908 | } |
| 5416 | 2909 | |
| 5417 | /// Asserts that self.zigTypeTag() == .Int. | |
| 5418 | pub fn maxIntScalar(self: Type, arena: Allocator, target: Target) !Value { | |
| 5419 | assert(self.zigTypeTag() == .Int); | |
| 5420 | const info = self.intInfo(target); | |
| 5421 | ||
| 5422 | if (info.bits == 0) { | |
| 5423 | return Value.initTag(.the_only_possible_value); | |
| 5424 | } | |
| 2910 | /// The returned Value will have type dest_ty. | |
| 2911 | pub fn maxIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value { | |
| 2912 | const info = ty.intInfo(mod); | |
| 5425 | 2913 | |
| 5426 | switch (info.bits - @boolToInt(info.signedness == .signed)) { | |
| 5427 | 0 => return Value.zero, | |
| 5428 | 1 => return Value.one, | |
| 2914 | switch (info.bits) { | |
| 2915 | 0 => return switch (info.signedness) { | |
| 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 | 2923 | else => {}, |
| 5430 | 2924 | } |
| 5431 | 2925 | |
| 5432 | 2926 | if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) { |
| 5433 | 2927 | .signed => { |
| 5434 | 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 | 2931 | .unsigned => { |
| 5438 | 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 | 2940 | try res.setTwosCompIntLimit(.max, info.signedness, info.bits); |
| 5445 | 2941 | |
| 5446 | const res_const = 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 | } | |
| 2942 | return mod.intValue_big(dest_ty, res.toConst()); | |
| 5452 | 2943 | } |
| 5453 | 2944 | |
| 5454 | 2945 | /// Asserts the type is an enum or a union. |
| 5455 | pub fn intTagType(ty: Type, buffer: *Payload.Bits) Type { | |
| 5456 | switch (ty.tag()) { | |
| 5457 | .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty, | |
| 5458 | .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty, | |
| 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), | |
| 2946 | pub fn intTagType(ty: Type, mod: *Module) Type { | |
| 2947 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2948 | .union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod), | |
| 2949 | .enum_type => |enum_type| enum_type.tag_ty.toType(), | |
| 5470 | 2950 | else => unreachable, |
| 5471 | } | |
| 2951 | }; | |
| 5472 | 2952 | } |
| 5473 | 2953 | |
| 5474 | pub fn isNonexhaustiveEnum(ty: Type) bool { | |
| 5475 | return switch (ty.tag()) { | |
| 5476 | .enum_nonexhaustive => true, | |
| 2954 | pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool { | |
| 2955 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2956 | .enum_type => |enum_type| switch (enum_type.tag_mode) { | |
| 2957 | .nonexhaustive => true, | |
| 2958 | .auto, .explicit => false, | |
| 2959 | }, | |
| 5477 | 2960 | else => false, |
| 5478 | 2961 | }; |
| 5479 | 2962 | } |
| 5480 | 2963 | |
| 5481 | 2964 | // Asserts that `ty` is an error set and not `anyerror`. |
| 5482 | pub fn errorSetNames(ty: Type) []const []const u8 { | |
| 5483 | return switch (ty.tag()) { | |
| 5484 | .error_set_single => blk: { | |
| 5485 | // Work around coercion problems | |
| 5486 | const tmp: *const [1][]const u8 = &ty.castTag(.error_set_single).?.data; | |
| 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; | |
| 2965 | pub fn errorSetNames(ty: Type, mod: *Module) []const InternPool.NullTerminatedString { | |
| 2966 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2967 | .error_set_type => |x| x.names, | |
| 2968 | .inferred_error_set_type => |index| { | |
| 2969 | const inferred_error_set = mod.inferredErrorSetPtr(index); | |
| 5493 | 2970 | assert(inferred_error_set.is_resolved); |
| 5494 | 2971 | assert(!inferred_error_set.is_anyerror); |
| 5495 | 2972 | return inferred_error_set.errors.keys(); |
| ... | ... | @@ -5498,133 +2975,43 @@ pub const Type = extern union { |
| 5498 | 2975 | }; |
| 5499 | 2976 | } |
| 5500 | 2977 | |
| 5501 | /// Merge lhs with rhs. | |
| 5502 | /// Asserts that lhs and rhs are both error sets and are resolved. | |
| 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 | }; | |
| 2978 | pub fn enumFields(ty: Type, mod: *Module) []const InternPool.NullTerminatedString { | |
| 2979 | return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names; | |
| 5539 | 2980 | } |
| 5540 | 2981 | |
| 5541 | pub fn enumFieldCount(ty: Type) usize { | |
| 5542 | return ty.enumFields().count(); | |
| 2982 | pub fn enumFieldCount(ty: Type, mod: *Module) usize { | |
| 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 { | |
| 5546 | return ty.enumFields().keys()[field_index]; | |
| 2986 | pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { | |
| 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 { | |
| 5550 | return ty.enumFields().getIndex(field_name); | |
| 2990 | pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 { | |
| 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 | 2996 | /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or |
| 5554 | 2997 | /// an integer which represents the enum value. Returns the field index in |
| 5555 | 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 { | |
| 5557 | if (enum_tag.castTag(.enum_field_index)) |payload| { | |
| 5558 | return @as(usize, payload.data); | |
| 5559 | } | |
| 5560 | const S = struct { | |
| 5561 | fn fieldWithRange(int_ty: Type, int_val: Value, end: usize, m: *Module) ?usize { | |
| 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"), | |
| 2999 | pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 { | |
| 3000 | const ip = &mod.intern_pool; | |
| 3001 | const enum_type = ip.indexToKey(ty.toIntern()).enum_type; | |
| 3002 | const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) { | |
| 3003 | .int => enum_tag.toIntern(), | |
| 3004 | .enum_tag => |info| info.int, | |
| 5619 | 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 { | |
| 5624 | switch (ty.tag()) { | |
| 5625 | .empty_struct, .empty_struct_literal => return .{}, | |
| 5626 | .@"struct" => { | |
| 5627 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3011 | pub fn structFields(ty: Type, mod: *Module) Module.Struct.Fields { | |
| 3012 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3013 | .struct_type => |struct_type| { | |
| 3014 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .{}; | |
| 5628 | 3015 | assert(struct_obj.haveFieldTypes()); |
| 5629 | 3016 | return struct_obj.fields; |
| 5630 | 3017 | }, |
| ... | ... | @@ -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 { | |
| 5636 | switch (ty.tag()) { | |
| 5637 | .@"struct" => { | |
| 5638 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3022 | pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { | |
| 3023 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3024 | .struct_type => |struct_type| { | |
| 3025 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5639 | 3026 | assert(struct_obj.haveFieldTypes()); |
| 5640 | 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 | 3030 | else => unreachable, |
| 5644 | } | |
| 3031 | }; | |
| 5645 | 3032 | } |
| 5646 | 3033 | |
| 5647 | pub fn structFieldCount(ty: Type) usize { | |
| 5648 | switch (ty.tag()) { | |
| 5649 | .@"struct" => { | |
| 5650 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3034 | pub fn structFieldCount(ty: Type, mod: *Module) usize { | |
| 3035 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3036 | .struct_type => |struct_type| { | |
| 3037 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; | |
| 5651 | 3038 | assert(struct_obj.haveFieldTypes()); |
| 5652 | 3039 | return struct_obj.fields.count(); |
| 5653 | 3040 | }, |
| 5654 | .empty_struct, .empty_struct_literal => return 0, | |
| 5655 | .tuple => return ty.castTag(.tuple).?.data.types.len, | |
| 5656 | .anon_struct => return ty.castTag(.anon_struct).?.data.types.len, | |
| 3041 | .anon_struct_type => |anon_struct| anon_struct.types.len, | |
| 5657 | 3042 | else => unreachable, |
| 5658 | } | |
| 3043 | }; | |
| 5659 | 3044 | } |
| 5660 | 3045 | |
| 5661 | 3046 | /// Supports structs and unions. |
| 5662 | pub fn structFieldType(ty: Type, index: usize) Type { | |
| 5663 | switch (ty.tag()) { | |
| 5664 | .@"struct" => { | |
| 5665 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3047 | pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { | |
| 3048 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3049 | .struct_type => |struct_type| { | |
| 3050 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5666 | 3051 | return struct_obj.fields.values()[index].ty; |
| 5667 | 3052 | }, |
| 5668 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5669 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3053 | .union_type => |union_type| { | |
| 3054 | const union_obj = mod.unionPtr(union_type.index); | |
| 5670 | 3055 | return union_obj.fields.values()[index].ty; |
| 5671 | 3056 | }, |
| 5672 | .tuple => return ty.castTag(.tuple).?.data.types[index], | |
| 5673 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index], | |
| 3057 | .anon_struct_type => |anon_struct| anon_struct.types[index].toType(), | |
| 5674 | 3058 | else => unreachable, |
| 5675 | } | |
| 3059 | }; | |
| 5676 | 3060 | } |
| 5677 | 3061 | |
| 5678 | pub fn structFieldAlign(ty: Type, index: usize, target: Target) u32 { | |
| 5679 | switch (ty.tag()) { | |
| 5680 | .@"struct" => { | |
| 5681 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3062 | pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 { | |
| 3063 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3064 | .struct_type => |struct_type| { | |
| 3065 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5682 | 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 => { | |
| 5686 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 5687 | return union_obj.fields.values()[index].normalAlignment(target); | |
| 3072 | .union_type => |union_type| { | |
| 3073 | const union_obj = mod.unionPtr(union_type.index); | |
| 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 | 3076 | else => unreachable, |
| 5692 | 3077 | } |
| 5693 | 3078 | } |
| 5694 | 3079 | |
| 5695 | pub fn structFieldDefaultValue(ty: Type, index: usize) Value { | |
| 5696 | switch (ty.tag()) { | |
| 5697 | .@"struct" => { | |
| 5698 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 5699 | return struct_obj.fields.values()[index].default_val; | |
| 3080 | pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value { | |
| 3081 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3082 | .struct_type => |struct_type| { | |
| 3083 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 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 => { | |
| 5702 | const tuple = ty.castTag(.tuple).?.data; | |
| 5703 | return tuple.values[index]; | |
| 5704 | }, | |
| 5705 | .anon_struct => { | |
| 5706 | const struct_obj = ty.castTag(.anon_struct).?.data; | |
| 5707 | return struct_obj.values[index]; | |
| 3089 | .anon_struct_type => |anon_struct| { | |
| 3090 | const val = anon_struct.values[index]; | |
| 3091 | // TODO: avoid using `unreachable` to indicate this. | |
| 3092 | if (val == .none) return Value.@"unreachable"; | |
| 3093 | return val.toValue(); | |
| 5708 | 3094 | }, |
| 5709 | 3095 | else => unreachable, |
| 5710 | 3096 | } |
| 5711 | 3097 | } |
| 5712 | 3098 | |
| 5713 | pub fn structFieldValueComptime(ty: Type, index: usize) ?Value { | |
| 5714 | switch (ty.tag()) { | |
| 5715 | .@"struct" => { | |
| 5716 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3099 | pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value { | |
| 3100 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3101 | .struct_type => |struct_type| { | |
| 3102 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5717 | 3103 | const field = struct_obj.fields.values()[index]; |
| 5718 | 3104 | if (field.is_comptime) { |
| 5719 | return field.default_val; | |
| 3105 | return field.default_val.toValue(); | |
| 5720 | 3106 | } else { |
| 5721 | return field.ty.onePossibleValue(); | |
| 3107 | return field.ty.onePossibleValue(mod); | |
| 5722 | 3108 | } |
| 5723 | 3109 | }, |
| 5724 | .tuple => { | |
| 5725 | const tuple = ty.castTag(.tuple).?.data; | |
| 3110 | .anon_struct_type => |tuple| { | |
| 5726 | 3111 | const val = tuple.values[index]; |
| 5727 | if (val.tag() == .unreachable_value) { | |
| 5728 | return tuple.types[index].onePossibleValue(); | |
| 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(); | |
| 3112 | if (val == .none) { | |
| 3113 | return tuple.types[index].toType().onePossibleValue(mod); | |
| 5738 | 3114 | } else { |
| 5739 | return val; | |
| 3115 | return val.toValue(); | |
| 5740 | 3116 | } |
| 5741 | 3117 | }, |
| 5742 | 3118 | else => unreachable, |
| 5743 | 3119 | } |
| 5744 | 3120 | } |
| 5745 | 3121 | |
| 5746 | pub fn structFieldIsComptime(ty: Type, index: usize) bool { | |
| 5747 | switch (ty.tag()) { | |
| 5748 | .@"struct" => { | |
| 5749 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3122 | pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool { | |
| 3123 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3124 | .struct_type => |struct_type| { | |
| 3125 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5750 | 3126 | if (struct_obj.layout == .Packed) return false; |
| 5751 | 3127 | const field = struct_obj.fields.values()[index]; |
| 5752 | 3128 | return field.is_comptime; |
| 5753 | 3129 | }, |
| 5754 | .tuple => { | |
| 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 | }, | |
| 3130 | .anon_struct_type => |anon_struct| anon_struct.values[index] != .none, | |
| 5764 | 3131 | else => unreachable, |
| 5765 | } | |
| 3132 | }; | |
| 5766 | 3133 | } |
| 5767 | 3134 | |
| 5768 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, target: Target) u32 { | |
| 5769 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3135 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 { | |
| 3136 | const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type; | |
| 3137 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5770 | 3138 | assert(struct_obj.layout == .Packed); |
| 5771 | 3139 | comptime assert(Type.packed_struct_layout_version == 2); |
| 5772 | 3140 | |
| ... | ... | @@ -5774,9 +3142,9 @@ pub const Type = extern union { |
| 5774 | 3142 | var elem_size_bits: u16 = undefined; |
| 5775 | 3143 | var running_bits: u16 = 0; |
| 5776 | 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 | 3148 | if (i == field_index) { |
| 5781 | 3149 | bit_offset = running_bits; |
| 5782 | 3150 | elem_size_bits = field_bits; |
| ... | ... | @@ -5797,9 +3165,10 @@ pub const Type = extern union { |
| 5797 | 3165 | offset: u64 = 0, |
| 5798 | 3166 | big_align: u32 = 0, |
| 5799 | 3167 | struct_obj: *Module.Struct, |
| 5800 | target: Target, | |
| 3168 | module: *Module, | |
| 5801 | 3169 | |
| 5802 | 3170 | pub fn next(it: *StructOffsetIterator) ?FieldOffset { |
| 3171 | const mod = it.module; | |
| 5803 | 3172 | var i = it.field; |
| 5804 | 3173 | if (it.struct_obj.fields.count() <= i) |
| 5805 | 3174 | return null; |
| ... | ... | @@ -5811,35 +3180,36 @@ pub const Type = extern union { |
| 5811 | 3180 | const field = it.struct_obj.fields.values()[i]; |
| 5812 | 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 | 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 | 3188 | it.big_align = @max(it.big_align, field_align); |
| 5820 | 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 | 3191 | return FieldOffset{ .field = i, .offset = field_offset }; |
| 5823 | 3192 | } |
| 5824 | 3193 | }; |
| 5825 | 3194 | |
| 5826 | 3195 | /// Get an iterator that iterates over all the struct field, returning the field and |
| 5827 | 3196 | /// offset of that field. Asserts that the type is a non-packed struct. |
| 5828 | pub fn iterateStructOffsets(ty: Type, target: Target) StructOffsetIterator { | |
| 5829 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3197 | pub fn iterateStructOffsets(ty: Type, mod: *Module) StructOffsetIterator { | |
| 3198 | const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type; | |
| 3199 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5830 | 3200 | assert(struct_obj.haveLayout()); |
| 5831 | 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 | 3205 | /// Supports structs and unions. |
| 5836 | pub fn structFieldOffset(ty: Type, index: usize, target: Target) u64 { | |
| 5837 | switch (ty.tag()) { | |
| 5838 | .@"struct" => { | |
| 5839 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3206 | pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 { | |
| 3207 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3208 | .struct_type => |struct_type| { | |
| 3209 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5840 | 3210 | assert(struct_obj.haveLayout()); |
| 5841 | 3211 | assert(struct_obj.layout != .Packed); |
| 5842 | var it = ty.iterateStructOffsets(target); | |
| 3212 | var it = ty.iterateStructOffsets(mod); | |
| 5843 | 3213 | while (it.next()) |field_offset| { |
| 5844 | 3214 | if (index == field_offset.field) |
| 5845 | 3215 | return field_offset.offset; |
| ... | ... | @@ -5848,34 +3218,32 @@ pub const Type = extern union { |
| 5848 | 3218 | return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1)); |
| 5849 | 3219 | }, |
| 5850 | 3220 | |
| 5851 | .tuple, .anon_struct => { | |
| 5852 | const tuple = ty.tupleFields(); | |
| 5853 | ||
| 3221 | .anon_struct_type => |tuple| { | |
| 5854 | 3222 | var offset: u64 = 0; |
| 5855 | 3223 | var big_align: u32 = 0; |
| 5856 | 3224 | |
| 5857 | for (tuple.types, 0..) |field_ty, i| { | |
| 5858 | const field_val = tuple.values[i]; | |
| 5859 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) { | |
| 3225 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 3226 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) { | |
| 5860 | 3227 | // comptime field |
| 5861 | 3228 | if (i == index) return offset; |
| 5862 | 3229 | continue; |
| 5863 | 3230 | } |
| 5864 | 3231 | |
| 5865 | const field_align = field_ty.abiAlignment(target); | |
| 3232 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 5866 | 3233 | big_align = @max(big_align, field_align); |
| 5867 | 3234 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 5868 | 3235 | if (i == index) return offset; |
| 5869 | offset += field_ty.abiSize(target); | |
| 3236 | offset += field_ty.toType().abiSize(mod); | |
| 5870 | 3237 | } |
| 5871 | 3238 | offset = std.mem.alignForwardGeneric(u64, offset, @max(big_align, 1)); |
| 5872 | 3239 | return offset; |
| 5873 | 3240 | }, |
| 5874 | 3241 | |
| 5875 | .@"union" => return 0, | |
| 5876 | .union_safety_tagged, .union_tagged => { | |
| 5877 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 5878 | const layout = union_obj.getLayout(target, true); | |
| 3242 | .union_type => |union_type| { | |
| 3243 | if (!union_type.hasTag()) | |
| 3244 | return 0; | |
| 3245 | const union_obj = mod.unionPtr(union_type.index); | |
| 3246 | const layout = union_obj.getLayout(mod, true); | |
| 5879 | 3247 | if (layout.tag_align >= layout.payload_align) { |
| 5880 | 3248 | // {Tag, Payload} |
| 5881 | 3249 | return std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align); |
| ... | ... | @@ -5884,6 +3252,7 @@ pub const Type = extern union { |
| 5884 | 3252 | return 0; |
| 5885 | 3253 | } |
| 5886 | 3254 | }, |
| 3255 | ||
| 5887 | 3256 | else => unreachable, |
| 5888 | 3257 | } |
| 5889 | 3258 | } |
| ... | ... | @@ -5893,507 +3262,92 @@ pub const Type = extern union { |
| 5893 | 3262 | } |
| 5894 | 3263 | |
| 5895 | 3264 | pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc { |
| 5896 | switch (ty.tag()) { | |
| 5897 | .enum_full, .enum_nonexhaustive => { | |
| 5898 | const enum_full = ty.cast(Payload.EnumFull).?.data; | |
| 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; | |
| 3265 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3266 | .struct_type => |struct_type| { | |
| 3267 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 5911 | 3268 | return struct_obj.srcLoc(mod); |
| 5912 | 3269 | }, |
| 5913 | .error_set => { | |
| 5914 | const error_set = ty.castTag(.error_set).?.data; | |
| 5915 | return error_set.srcLoc(mod); | |
| 5916 | }, | |
| 5917 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5918 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3270 | .union_type => |union_type| { | |
| 3271 | const union_obj = mod.unionPtr(union_type.index); | |
| 5919 | 3272 | return union_obj.srcLoc(mod); |
| 5920 | 3273 | }, |
| 5921 | .@"opaque" => { | |
| 5922 | const opaque_obj = ty.cast(Payload.Opaque).?.data; | |
| 5923 | return opaque_obj.srcLoc(mod); | |
| 5924 | }, | |
| 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 | } | |
| 3274 | .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type), | |
| 3275 | .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod), | |
| 3276 | else => null, | |
| 3277 | }; | |
| 5940 | 3278 | } |
| 5941 | 3279 | |
| 5942 | pub fn getOwnerDecl(ty: Type) Module.Decl.Index { | |
| 5943 | return ty.getOwnerDeclOrNull() orelse unreachable; | |
| 3280 | pub fn getOwnerDecl(ty: Type, mod: *Module) Module.Decl.Index { | |
| 3281 | return ty.getOwnerDeclOrNull(mod) orelse unreachable; | |
| 5944 | 3282 | } |
| 5945 | 3283 | |
| 5946 | pub fn getOwnerDeclOrNull(ty: Type) ?Module.Decl.Index { | |
| 5947 | switch (ty.tag()) { | |
| 5948 | .enum_full, .enum_nonexhaustive => { | |
| 5949 | const enum_full = ty.cast(Payload.EnumFull).?.data; | |
| 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; | |
| 3284 | pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index { | |
| 3285 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3286 | .struct_type => |struct_type| { | |
| 3287 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null; | |
| 5959 | 3288 | return struct_obj.owner_decl; |
| 5960 | 3289 | }, |
| 5961 | .error_set => { | |
| 5962 | const error_set = ty.castTag(.error_set).?.data; | |
| 5963 | return error_set.owner_decl; | |
| 5964 | }, | |
| 5965 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5966 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3290 | .union_type => |union_type| { | |
| 3291 | const union_obj = mod.unionPtr(union_type.index); | |
| 5967 | 3292 | return union_obj.owner_decl; |
| 5968 | 3293 | }, |
| 5969 | .@"opaque" => { | |
| 5970 | const opaque_obj = ty.cast(Payload.Opaque).?.data; | |
| 5971 | return opaque_obj.owner_decl; | |
| 5972 | }, | |
| 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 | } | |
| 3294 | .opaque_type => |opaque_type| opaque_type.decl, | |
| 3295 | .enum_type => |enum_type| enum_type.decl, | |
| 3296 | else => null, | |
| 3297 | }; | |
| 5988 | 3298 | } |
| 5989 | 3299 | |
| 5990 | /// This enum does not directly correspond to `std.builtin.TypeId` because | |
| 5991 | /// it has extra enum tags in it, as a way of using less memory. For example, | |
| 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 | }; | |
| 3300 | pub fn isGenericPoison(ty: Type) bool { | |
| 3301 | return ty.toIntern() == .generic_poison_type; | |
| 6258 | 3302 | } |
| 6259 | 3303 | |
| 6260 | pub fn isAnonStruct(ty: Type) bool { | |
| 6261 | return switch (ty.tag()) { | |
| 6262 | .anon_struct, .empty_struct_literal => true, | |
| 3304 | pub fn isTuple(ty: Type, mod: *Module) bool { | |
| 3305 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 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 | 3311 | else => false, |
| 6264 | 3312 | }; |
| 6265 | 3313 | } |
| 6266 | 3314 | |
| 6267 | pub fn isTupleOrAnonStruct(ty: Type) bool { | |
| 6268 | return switch (ty.tag()) { | |
| 6269 | .tuple, .empty_struct_literal, .anon_struct => true, | |
| 6270 | .@"struct" => ty.castTag(.@"struct").?.data.is_tuple, | |
| 3315 | pub fn isAnonStruct(ty: Type, mod: *Module) bool { | |
| 3316 | if (ty.toIntern() == .empty_struct_type) return true; | |
| 3317 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3318 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len > 0, | |
| 6271 | 3319 | else => false, |
| 6272 | 3320 | }; |
| 6273 | 3321 | } |
| 6274 | 3322 | |
| 6275 | pub fn isSimpleTuple(ty: Type) bool { | |
| 6276 | return switch (ty.tag()) { | |
| 6277 | .tuple, .empty_struct_literal => true, | |
| 3323 | pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool { | |
| 3324 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 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 | 3330 | else => false, |
| 6279 | 3331 | }; |
| 6280 | 3332 | } |
| 6281 | 3333 | |
| 6282 | pub fn isSimpleTupleOrAnonStruct(ty: Type) bool { | |
| 6283 | return switch (ty.tag()) { | |
| 6284 | .tuple, .empty_struct_literal, .anon_struct => true, | |
| 3334 | pub fn isSimpleTuple(ty: Type, mod: *Module) bool { | |
| 3335 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3336 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0, | |
| 6285 | 3337 | else => false, |
| 6286 | 3338 | }; |
| 6287 | 3339 | } |
| 6288 | 3340 | |
| 6289 | // Only allowed for simple tuple types | |
| 6290 | pub fn tupleFields(ty: Type) Payload.Tuple.Data { | |
| 6291 | return switch (ty.tag()) { | |
| 6292 | .tuple => ty.castTag(.tuple).?.data, | |
| 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, | |
| 3341 | pub fn isSimpleTupleOrAnonStruct(ty: Type, mod: *Module) bool { | |
| 3342 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3343 | .anon_struct_type => true, | |
| 3344 | else => false, | |
| 6299 | 3345 | }; |
| 6300 | 3346 | } |
| 6301 | 3347 | |
| 6302 | /// The sub-types are named after what fields they contain. | |
| 6303 | 3348 | pub const Payload = struct { |
| 6304 | tag: Tag, | |
| 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 | ||
| 3349 | /// TODO: remove this data structure since we have `InternPool.Key.PtrType`. | |
| 6391 | 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 | 3351 | pub const Data = struct { |
| 6398 | 3352 | pointee_type: Type, |
| 6399 | 3353 | sentinel: ?Value = null, |
| ... | ... | @@ -6417,145 +3371,103 @@ pub const Type = extern union { |
| 6417 | 3371 | @"volatile": bool = false, |
| 6418 | 3372 | size: std.builtin.Type.Pointer.Size = .One, |
| 6419 | 3373 | |
| 6420 | pub const VectorIndex = enum(u32) { | |
| 6421 | none = std.math.maxInt(u32), | |
| 6422 | runtime = std.math.maxInt(u32) - 1, | |
| 6423 | _, | |
| 6424 | }; | |
| 3374 | pub const VectorIndex = InternPool.Key.PtrType.VectorIndex; | |
| 6425 | 3375 | |
| 6426 | pub fn alignment(data: Data, target: Target) u32 { | |
| 3376 | pub fn alignment(data: Data, mod: *Module) u32 { | |
| 6427 | 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 { | |
| 6434 | pub const base_tag = Tag.error_union; | |
| 6435 | ||
| 6436 | base: Payload = Payload{ .tag = base_tag }, | |
| 6437 | data: struct { | |
| 6438 | error_set: Type, | |
| 6439 | payload: Type, | |
| 6440 | }, | |
| 6441 | }; | |
| 6442 | ||
| 6443 | pub const Decl = struct { | |
| 6444 | base: Payload, | |
| 6445 | data: *Module.Decl, | |
| 6446 | }; | |
| 6447 | ||
| 6448 | pub const Name = struct { | |
| 6449 | base: Payload, | |
| 6450 | /// memory is owned by `Module` | |
| 6451 | data: []const u8, | |
| 6452 | }; | |
| 6453 | ||
| 6454 | /// Mostly used for namespace like structs with zero fields. | |
| 6455 | /// Most commonly used for files. | |
| 6456 | pub const ContainerScope = struct { | |
| 6457 | base: Payload, | |
| 6458 | data: *Module.Namespace, | |
| 6459 | }; | |
| 6460 | ||
| 6461 | pub const Opaque = struct { | |
| 6462 | base: Payload = .{ .tag = .@"opaque" }, | |
| 6463 | data: *Module.Opaque, | |
| 6464 | }; | |
| 6465 | ||
| 6466 | pub const Struct = struct { | |
| 6467 | base: Payload = .{ .tag = .@"struct" }, | |
| 6468 | data: *Module.Struct, | |
| 6469 | }; | |
| 6470 | ||
| 6471 | pub const Tuple = struct { | |
| 6472 | base: Payload = .{ .tag = .tuple }, | |
| 6473 | data: Data, | |
| 6474 | ||
| 6475 | pub const Data = struct { | |
| 6476 | types: []Type, | |
| 6477 | /// unreachable_value elements are used to indicate runtime-known. | |
| 6478 | values: []Value, | |
| 6479 | }; | |
| 6480 | }; | |
| 6481 | ||
| 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 | }; | |
| 3400 | pub const @"u1": Type = .{ .ip_index = .u1_type }; | |
| 3401 | pub const @"u8": Type = .{ .ip_index = .u8_type }; | |
| 3402 | pub const @"u16": Type = .{ .ip_index = .u16_type }; | |
| 3403 | pub const @"u29": Type = .{ .ip_index = .u29_type }; | |
| 3404 | pub const @"u32": Type = .{ .ip_index = .u32_type }; | |
| 3405 | pub const @"u64": Type = .{ .ip_index = .u64_type }; | |
| 3406 | pub const @"u128": Type = .{ .ip_index = .u128_type }; | |
| 3407 | ||
| 3408 | pub const @"i8": Type = .{ .ip_index = .i8_type }; | |
| 3409 | pub const @"i16": Type = .{ .ip_index = .i16_type }; | |
| 3410 | pub const @"i32": Type = .{ .ip_index = .i32_type }; | |
| 3411 | pub const @"i64": Type = .{ .ip_index = .i64_type }; | |
| 3412 | pub const @"i128": Type = .{ .ip_index = .i128_type }; | |
| 3413 | ||
| 3414 | pub const @"f16": Type = .{ .ip_index = .f16_type }; | |
| 3415 | pub const @"f32": Type = .{ .ip_index = .f32_type }; | |
| 3416 | pub const @"f64": Type = .{ .ip_index = .f64_type }; | |
| 3417 | pub const @"f80": Type = .{ .ip_index = .f80_type }; | |
| 3418 | pub const @"f128": Type = .{ .ip_index = .f128_type }; | |
| 3419 | ||
| 3420 | pub const @"bool": Type = .{ .ip_index = .bool_type }; | |
| 3421 | pub const @"usize": Type = .{ .ip_index = .usize_type }; | |
| 3422 | pub const @"isize": Type = .{ .ip_index = .isize_type }; | |
| 3423 | pub const @"comptime_int": Type = .{ .ip_index = .comptime_int_type }; | |
| 3424 | pub const @"comptime_float": Type = .{ .ip_index = .comptime_float_type }; | |
| 3425 | pub const @"void": Type = .{ .ip_index = .void_type }; | |
| 3426 | pub const @"type": Type = .{ .ip_index = .type_type }; | |
| 3427 | pub const @"anyerror": Type = .{ .ip_index = .anyerror_type }; | |
| 3428 | pub const @"anyopaque": Type = .{ .ip_index = .anyopaque_type }; | |
| 3429 | pub const @"anyframe": Type = .{ .ip_index = .anyframe_type }; | |
| 3430 | pub const @"null": Type = .{ .ip_index = .null_type }; | |
| 3431 | pub const @"undefined": Type = .{ .ip_index = .undefined_type }; | |
| 3432 | pub const @"noreturn": Type = .{ .ip_index = .noreturn_type }; | |
| 3433 | ||
| 3434 | pub const @"c_char": Type = .{ .ip_index = .c_char_type }; | |
| 3435 | pub const @"c_short": Type = .{ .ip_index = .c_short_type }; | |
| 3436 | pub const @"c_ushort": Type = .{ .ip_index = .c_ushort_type }; | |
| 3437 | pub const @"c_int": Type = .{ .ip_index = .c_int_type }; | |
| 3438 | pub const @"c_uint": Type = .{ .ip_index = .c_uint_type }; | |
| 3439 | pub const @"c_long": Type = .{ .ip_index = .c_long_type }; | |
| 3440 | pub const @"c_ulong": Type = .{ .ip_index = .c_ulong_type }; | |
| 3441 | pub const @"c_longlong": Type = .{ .ip_index = .c_longlong_type }; | |
| 3442 | pub const @"c_ulonglong": Type = .{ .ip_index = .c_ulonglong_type }; | |
| 3443 | pub const @"c_longdouble": Type = .{ .ip_index = .c_longdouble_type }; | |
| 3444 | ||
| 3445 | pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type }; | |
| 3446 | pub const manyptr_u8: Type = .{ .ip_index = .manyptr_u8_type }; | |
| 3447 | pub const single_const_pointer_to_comptime_int: Type = .{ | |
| 3448 | .ip_index = .single_const_pointer_to_comptime_int_type, | |
| 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); | |
| 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); | |
| 3453 | pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; | |
| 6540 | 3454 | |
| 6541 | 3455 | pub const err_int = Type.u16; |
| 6542 | 3456 | |
| 6543 | 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 | 3462 | var d = data; |
| 6547 | 3463 | |
| 6548 | if (d.size == .C) { | |
| 6549 | d.@"allowzero" = true; | |
| 6550 | } | |
| 6551 | ||
| 6552 | 3464 | // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee |
| 6553 | 3465 | // type, we change it to 0 here. If this causes an assertion trip because the |
| 6554 | 3466 | // pointee type needs to be resolved more, that needs to be done before calling |
| 6555 | 3467 | // this ptr() function. |
| 6556 | 3468 | if (d.@"align" != 0) canonicalize: { |
| 6557 | if (!d.pointee_type.layoutIsResolved()) break :canonicalize; | |
| 6558 | if (d.@"align" == d.pointee_type.abiAlignment(target)) { | |
| 3469 | if (!d.pointee_type.layoutIsResolved(mod)) break :canonicalize; | |
| 3470 | if (d.@"align" == d.pointee_type.abiAlignment(mod)) { | |
| 6559 | 3471 | d.@"align" = 0; |
| 6560 | 3472 | } |
| 6561 | 3473 | } |
| ... | ... | @@ -6565,57 +3477,29 @@ pub const Type = extern union { |
| 6565 | 3477 | // needs to be resolved before calling this ptr() function. |
| 6566 | 3478 | if (d.host_size != 0) { |
| 6567 | 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 | 3481 | assert(d.bit_offset == 0); |
| 6570 | 3482 | d.host_size = 0; |
| 6571 | 3483 | } |
| 6572 | 3484 | } |
| 6573 | 3485 | |
| 6574 | if (d.@"align" == 0 and d.@"addrspace" == .generic and | |
| 6575 | d.bit_offset == 0 and d.host_size == 0 and d.vector_index == .none and | |
| 6576 | !d.@"allowzero" and !d.@"volatile") | |
| 6577 | { | |
| 6578 | if (d.sentinel) |sent| { | |
| 6579 | if (!d.mutable and d.pointee_type.eql(Type.u8, mod)) { | |
| 6580 | switch (d.size) { | |
| 6581 | .Slice => { | |
| 6582 | if (sent.compareAllWithZero(.eq, mod)) { | |
| 6583 | return Type.initTag(.const_slice_u8_sentinel_0); | |
| 6584 | } | |
| 6585 | }, | |
| 6586 | .Many => { | |
| 6587 | if (sent.compareAllWithZero(.eq, mod)) { | |
| 6588 | return Type.initTag(.manyptr_const_u8_sentinel_0); | |
| 6589 | } | |
| 6590 | }, | |
| 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); | |
| 3486 | return mod.ptrType(.{ | |
| 3487 | .child = d.pointee_type.ip_index, | |
| 3488 | .sentinel = if (d.sentinel) |s| s.ip_index else .none, | |
| 3489 | .flags = .{ | |
| 3490 | .alignment = InternPool.Alignment.fromByteUnits(d.@"align"), | |
| 3491 | .vector_index = d.vector_index, | |
| 3492 | .size = d.size, | |
| 3493 | .is_const = !d.mutable, | |
| 3494 | .is_volatile = d.@"volatile", | |
| 3495 | .is_allowzero = d.@"allowzero", | |
| 3496 | .address_space = d.@"addrspace", | |
| 3497 | }, | |
| 3498 | .packed_offset = .{ | |
| 3499 | .host_size = d.host_size, | |
| 3500 | .bit_offset = d.bit_offset, | |
| 3501 | }, | |
| 3502 | }); | |
| 6619 | 3503 | } |
| 6620 | 3504 | |
| 6621 | 3505 | pub fn array( |
| ... | ... | @@ -6625,68 +3509,23 @@ pub const Type = extern union { |
| 6625 | 3509 | elem_type: Type, |
| 6626 | 3510 | mod: *Module, |
| 6627 | 3511 | ) Allocator.Error!Type { |
| 6628 | if (elem_type.eql(Type.u8, mod)) { | |
| 6629 | if (sent) |some| { | |
| 6630 | if (some.eql(Value.zero, elem_type, mod)) { | |
| 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 | } | |
| 3512 | // TODO: update callsites of this function to directly call mod.arrayType | |
| 3513 | // and then delete this function. | |
| 3514 | _ = arena; | |
| 6651 | 3515 | |
| 6652 | pub fn vector(arena: Allocator, len: u64, elem_type: Type) Allocator.Error!Type { | |
| 6653 | return Tag.vector.create(arena, .{ | |
| 3516 | return mod.arrayType(.{ | |
| 6654 | 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 { | |
| 6660 | switch (child_type.tag()) { | |
| 6661 | .single_const_pointer => return Type.Tag.optional_single_const_pointer.create( | |
| 6662 | 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 | } | |
| 3523 | pub fn optional(arena: Allocator, child_type: Type, mod: *Module) Allocator.Error!Type { | |
| 3524 | // TODO: update callsites of this function to directly call | |
| 3525 | // mod.optionalType and then delete this function. | |
| 3526 | _ = arena; | |
| 6685 | 3527 | |
| 6686 | return Type.Tag.error_union.create(arena, .{ | |
| 6687 | .error_set = error_set, | |
| 6688 | .payload = payload, | |
| 6689 | }); | |
| 3528 | return mod.optionalType(child_type.ip_index); | |
| 6690 | 3529 | } |
| 6691 | 3530 | |
| 6692 | 3531 | pub fn smallestUnsignedBits(max: u64) u16 { |
| ... | ... | @@ -6696,113 +3535,7 @@ pub const Type = extern union { |
| 6696 | 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 | 3538 | /// This is only used for comptime asserts. Bump this number when you make a change |
| 6777 | 3539 | /// to packed struct layout to find out all the places in the codebase you need to edit! |
| 6778 | 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 | 11 | const Air = @import("Air.zig"); |
| 12 | 12 | const TypedValue = @import("TypedValue.zig"); |
| 13 | 13 | const Sema = @import("Sema.zig"); |
| 14 | ||
| 15 | /// This is the raw data, with no bookkeeping, no memory awareness, | |
| 16 | /// no de-duplication, and no type system awareness. | |
| 17 | /// It's important for this type to be small. | |
| 18 | /// This union takes advantage of the fact that the first page of memory | |
| 19 | /// is unmapped, giving us 4096 possible enum tags that have no payload. | |
| 20 | pub const Value = extern union { | |
| 21 | /// If the tag value is less than Tag.no_payload_count, then no pointer | |
| 22 | /// dereference is needed. | |
| 23 | tag_if_small_enough: Tag, | |
| 24 | ptr_otherwise: *Payload, | |
| 14 | const InternPool = @import("InternPool.zig"); | |
| 15 | ||
| 16 | pub const Value = struct { | |
| 17 | /// We are migrating towards using this for every Value object. However, many | |
| 18 | /// values are still represented the legacy way. This is indicated by using | |
| 19 | /// InternPool.Index.none. | |
| 20 | ip_index: InternPool.Index, | |
| 21 | ||
| 22 | /// This is the raw data, with no bookkeeping, no memory awareness, | |
| 23 | /// no de-duplication, and no type system awareness. | |
| 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 | 30 | // Keep in sync with tools/stage2_pretty_printers_common.py |
| 27 | 31 | pub const Tag = enum(usize) { |
| 28 | 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 | 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 | 35 | /// When the type is error union: |
| 156 | 36 | /// * If the tag is `.@"error"`, the error union is an error. |
| 157 | 37 | /// * If the tag is `.eu_payload`, the error union is a payload. |
| ... | ... | @@ -159,8 +39,6 @@ pub const Value = extern union { |
| 159 | 39 | /// is non-error, but the inner error union is an error, is represented as |
| 160 | 40 | /// a tag of `.eu_payload`, with a sub-tag of `.@"error"`. |
| 161 | 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 | 42 | /// When the type is optional: |
| 165 | 43 | /// * If the tag is `.null_value`, the optional is null. |
| 166 | 44 | /// * If the tag is `.opt_payload`, the optional is a payload. |
| ... | ... | @@ -168,8 +46,13 @@ pub const Value = extern union { |
| 168 | 46 | /// is non-null, but the inner optional is null, is represented as |
| 169 | 47 | /// a tag of `.opt_payload`, with a sub-tag of `.null_value`. |
| 170 | 48 | opt_payload, |
| 171 | /// A pointer to the payload of an optional, based on a pointer to an optional. | |
| 172 | opt_payload_ptr, | |
| 49 | /// Pointer and length as sub `Value` objects. | |
| 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 | 56 | /// An instance of a struct, array, or vector. |
| 174 | 57 | /// Each element/field stored as a `Value`. |
| 175 | 58 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, |
| ... | ... | @@ -177,152 +60,17 @@ pub const Value = extern union { |
| 177 | 60 | aggregate, |
| 178 | 61 | /// An instance of a union. |
| 179 | 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 | 64 | pub fn Type(comptime t: Tag) type { |
| 195 | 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 | 66 | .eu_payload, |
| 284 | 67 | .opt_payload, |
| 285 | .empty_array_sentinel, | |
| 286 | .runtime_value, | |
| 68 | .repeated, | |
| 287 | 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 | 70 | .slice => Payload.Slice, |
| 299 | ||
| 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, | |
| 71 | .bytes => Payload.Bytes, | |
| 323 | 72 | .aggregate => Payload.Aggregate, |
| 324 | 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 | 80 | .base = .{ .tag = t }, |
| 333 | 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 | 89 | pub fn Data(comptime t: Tag) type { |
| ... | ... | @@ -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 | 94 | pub fn initPayload(payload: *Payload) Value { |
| 349 | assert(@enumToInt(payload.tag) >= Tag.no_payload_count); | |
| 350 | return .{ .ptr_otherwise = payload }; | |
| 95 | return Value{ | |
| 96 | .ip_index = .none, | |
| 97 | .legacy = .{ .ptr_otherwise = payload }, | |
| 98 | }; | |
| 351 | 99 | } |
| 352 | 100 | |
| 353 | 101 | pub fn tag(self: Value) Tag { |
| 354 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | |
| 355 | return self.tag_if_small_enough; | |
| 356 | } else { | |
| 357 | return self.ptr_otherwise.tag; | |
| 358 | } | |
| 102 | assert(self.ip_index == .none); | |
| 103 | return self.legacy.ptr_otherwise.tag; | |
| 359 | 104 | } |
| 360 | 105 | |
| 361 | 106 | /// Prefer `castTag` to this. |
| 362 | 107 | pub fn cast(self: Value, comptime T: type) ?*T { |
| 108 | if (self.ip_index != .none) { | |
| 109 | return null; | |
| 110 | } | |
| 363 | 111 | if (@hasField(T, "base_tag")) { |
| 364 | 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 | 114 | inline for (@typeInfo(Tag).Enum.fields) |field| { |
| 370 | if (field.value < Tag.no_payload_count) | |
| 371 | continue; | |
| 372 | 115 | const t = @intToEnum(Tag, field.value); |
| 373 | if (self.ptr_otherwise.tag == t) { | |
| 116 | if (self.legacy.ptr_otherwise.tag == t) { | |
| 374 | 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 | 120 | return null; |
| 378 | 121 | } |
| ... | ... | @@ -381,11 +124,10 @@ pub const Value = extern union { |
| 381 | 124 | } |
| 382 | 125 | |
| 383 | 126 | pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() { |
| 384 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) | |
| 385 | return null; | |
| 127 | if (self.ip_index != .none) return null; | |
| 386 | 128 | |
| 387 | if (self.ptr_otherwise.tag == t) | |
| 388 | return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise); | |
| 129 | if (self.legacy.ptr_otherwise.tag == t) | |
| 130 | return @fieldParentPtr(t.Type(), "base", self.legacy.ptr_otherwise); | |
| 389 | 131 | |
| 390 | 132 | return null; |
| 391 | 133 | } |
| ... | ... | @@ -393,165 +135,10 @@ pub const Value = extern union { |
| 393 | 135 | /// It's intentional that this function is not passed a corresponding Type, so that |
| 394 | 136 | /// a Value can be copied from a Sema to a Decl prior to resolving struct/union field types. |
| 395 | 137 | pub fn copy(self: Value, arena: Allocator) error{OutOfMemory}!Value { |
| 396 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | |
| 397 | return Value{ .tag_if_small_enough = self.tag_if_small_enough }; | |
| 398 | } else switch (self.ptr_otherwise.tag) { | |
| 399 | .u1_type, | |
| 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 | }, | |
| 138 | if (self.ip_index != .none) { | |
| 139 | return Value{ .ip_index = self.ip_index, .legacy = undefined }; | |
| 140 | } | |
| 141 | switch (self.legacy.ptr_otherwise.tag) { | |
| 555 | 142 | .bytes => { |
| 556 | 143 | const bytes = self.castTag(.bytes).?.data; |
| 557 | 144 | const new_payload = try arena.create(Payload.Bytes); |
| ... | ... | @@ -559,14 +146,14 @@ pub const Value = extern union { |
| 559 | 146 | .base = .{ .tag = .bytes }, |
| 560 | 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 | 154 | .eu_payload, |
| 567 | 155 | .opt_payload, |
| 568 | .empty_array_sentinel, | |
| 569 | .runtime_value, | |
| 156 | .repeated, | |
| 570 | 157 | => { |
| 571 | 158 | const payload = self.cast(Payload.SubValue).?; |
| 572 | 159 | const new_payload = try arena.create(Payload.SubValue); |
| ... | ... | @@ -574,7 +161,10 @@ pub const Value = extern union { |
| 574 | 161 | .base = payload.base, |
| 575 | 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 | 169 | .slice => { |
| 580 | 170 | const payload = self.castTag(.slice).?; |
| ... | ... | @@ -586,25 +176,11 @@ pub const Value = extern union { |
| 586 | 176 | .len = try payload.data.len.copy(arena), |
| 587 | 177 | }, |
| 588 | 178 | }; |
| 589 | return Value{ .ptr_otherwise = &new_payload.base }; | |
| 590 | }, | |
| 591 | .float_16 => return self.copyPayloadShallow(arena, Payload.Float_16), | |
| 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), | |
| 179 | return Value{ | |
| 180 | .ip_index = .none, | |
| 181 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 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 | 184 | .aggregate => { |
| 609 | 185 | const payload = self.castTag(.aggregate).?; |
| 610 | 186 | const new_payload = try arena.create(Payload.Aggregate); |
| ... | ... | @@ -615,9 +191,11 @@ pub const Value = extern union { |
| 615 | 191 | for (new_payload.data, 0..) |*elem, i| { |
| 616 | 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 | 199 | .@"union" => { |
| 622 | 200 | const tag_and_val = self.castTag(.@"union").?.data; |
| 623 | 201 | const new_payload = try arena.create(Payload.Union); |
| ... | ... | @@ -628,11 +206,11 @@ pub const Value = extern union { |
| 628 | 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 | 218 | const payload = self.cast(T).?; |
| 641 | 219 | const new_payload = try arena.create(T); |
| 642 | 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 | 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 | 237 | pub fn dump( |
| 657 | 238 | start_val: Value, |
| 658 | 239 | comptime fmt: []const u8, |
| 659 | options: std.fmt.FormatOptions, | |
| 240 | _: std.fmt.FormatOptions, | |
| 660 | 241 | out_stream: anytype, |
| 661 | 242 | ) !void { |
| 662 | 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 | 248 | var val = start_val; |
| 664 | 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 | 250 | .aggregate => { |
| 733 | 251 | return out_stream.writeAll("(aggregate)"); |
| 734 | 252 | }, |
| 735 | 253 | .@"union" => { |
| 736 | 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 | 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 | 257 | .repeated => { |
| 805 | 258 | try out_stream.writeAll("(repeated) "); |
| 806 | 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 | 261 | .eu_payload => { |
| 817 | 262 | try out_stream.writeAll("(eu_payload) "); |
| 818 | val = val.castTag(.eu_payload).?.data; | |
| 263 | val = val.castTag(.repeated).?.data; | |
| 819 | 264 | }, |
| 820 | 265 | .opt_payload => { |
| 821 | 266 | try out_stream.writeAll("(opt_payload) "); |
| 822 | val = val.castTag(.opt_payload).?.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; | |
| 267 | val = val.castTag(.repeated).?.data; | |
| 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 | 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 | 308 | /// Asserts that the value is representable as an array of bytes. |
| 849 | 309 | /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. |
| 850 | 310 | pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 { |
| 851 | const target = mod.getTarget(); | |
| 852 | switch (val.tag()) { | |
| 853 | .bytes => { | |
| 854 | const bytes = val.castTag(.bytes).?.data; | |
| 855 | const adjusted_len = bytes.len - @boolToInt(ty.sentinel() != null); | |
| 856 | const adjusted_bytes = bytes[0..adjusted_len]; | |
| 857 | return allocator.dupe(u8, adjusted_bytes); | |
| 858 | }, | |
| 859 | .str_lit => { | |
| 860 | const str_lit = val.castTag(.str_lit).?.data; | |
| 861 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 862 | return allocator.dupe(u8, bytes); | |
| 863 | }, | |
| 864 | .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data), | |
| 865 | .repeated => { | |
| 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); | |
| 311 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 312 | .enum_literal => |enum_literal| allocator.dupe(u8, mod.intern_pool.stringToSlice(enum_literal)), | |
| 313 | .ptr => |ptr| switch (ptr.len) { | |
| 314 | .none => unreachable, | |
| 315 | else => try arrayToAllocatedBytes(val, ptr.len.toValue().toUnsignedInt(mod), allocator, mod), | |
| 316 | }, | |
| 317 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 318 | .bytes => |bytes| try allocator.dupe(u8, bytes), | |
| 319 | .elems => try arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod), | |
| 320 | .repeated_elem => |elem| { | |
| 321 | const byte = @intCast(u8, elem.toValue().toUnsignedInt(mod)); | |
| 322 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); | |
| 323 | @memset(result, byte); | |
| 324 | return result; | |
| 325 | }, | |
| 881 | 326 | }, |
| 882 | else => return arrayToAllocatedBytes(val, ty.arrayLen(), allocator, mod), | |
| 883 | } | |
| 327 | else => unreachable, | |
| 328 | }; | |
| 884 | 329 | } |
| 885 | 330 | |
| 886 | 331 | fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator, mod: *Module) ![]u8 { |
| 887 | 332 | const result = try allocator.alloc(u8, @intCast(usize, len)); |
| 888 | var elem_value_buf: ElemValueBuffer = undefined; | |
| 889 | 333 | for (result, 0..) |*elem, i| { |
| 890 | const elem_val = val.elemValueBuffer(mod, i, &elem_value_buf); | |
| 891 | elem.* = @intCast(u8, elem_val.toUnsignedInt(mod.getTarget())); | |
| 334 | const elem_val = try val.elemValue(mod, i); | |
| 335 | elem.* = @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 892 | 336 | } |
| 893 | 337 | return result; |
| 894 | 338 | } |
| 895 | 339 | |
| 896 | pub const ToTypeBuffer = Type.Payload.Bits; | |
| 897 | ||
| 898 | /// Asserts that the value is representable as a type. | |
| 899 | pub fn toType(self: Value, buffer: *ToTypeBuffer) Type { | |
| 900 | return switch (self.tag()) { | |
| 901 | .ty => self.castTag(.ty).?.data, | |
| 902 | .u1_type => Type.initTag(.u1), | |
| 903 | .u8_type => Type.initTag(.u8), | |
| 904 | .i8_type => Type.initTag(.i8), | |
| 905 | .u16_type => Type.initTag(.u16), | |
| 906 | .i16_type => Type.initTag(.i16), | |
| 907 | .u29_type => Type.initTag(.u29), | |
| 908 | .u32_type => Type.initTag(.u32), | |
| 909 | .i32_type => Type.initTag(.i32), | |
| 910 | .u64_type => Type.initTag(.u64), | |
| 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 | }; | |
| 340 | fn arrayToIpString(val: Value, len_u64: u64, mod: *Module) !InternPool.NullTerminatedString { | |
| 341 | const gpa = mod.gpa; | |
| 342 | const ip = &mod.intern_pool; | |
| 343 | const len = @intCast(usize, len_u64); | |
| 344 | try ip.string_bytes.ensureUnusedCapacity(gpa, len); | |
| 345 | for (0..len) |i| { | |
| 346 | // I don't think elemValue has the possibility to affect ip.string_bytes. Let's | |
| 347 | // assert just to be sure. | |
| 348 | const prev = ip.string_bytes.items.len; | |
| 349 | const elem_val = try val.elemValue(mod, i); | |
| 350 | assert(ip.string_bytes.items.len == prev); | |
| 351 | const byte = @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 352 | ip.string_bytes.appendAssumeCapacity(byte); | |
| 353 | } | |
| 354 | return ip.getOrPutTrailingString(gpa, len); | |
| 980 | 355 | } |
| 981 | 356 | |
| 982 | /// Asserts the type is an enum type. | |
| 983 | pub fn toEnum(val: Value, comptime E: type) E { | |
| 357 | pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { | |
| 358 | if (val.ip_index != .none) return (try mod.getCoerced(val, ty)).toIntern(); | |
| 984 | 359 | switch (val.tag()) { |
| 985 | .enum_field_index => { | |
| 986 | const field_index = val.castTag(.enum_field_index).?.data; | |
| 987 | return @intToEnum(E, field_index); | |
| 360 | .eu_payload => { | |
| 361 | const pl = val.castTag(.eu_payload).?.data; | |
| 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 => { | |
| 990 | const fields = std.meta.fields(E); | |
| 991 | assert(fields.len == 1); | |
| 992 | return @intToEnum(E, fields[0].value); | |
| 374 | .slice => { | |
| 375 | const pl = val.castTag(.slice).?.data; | |
| 376 | const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod); | |
| 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 { | |
| 999 | const field_index = switch (val.tag()) { | |
| 1000 | .enum_field_index => val.castTag(.enum_field_index).?.data, | |
| 1001 | .the_only_possible_value => blk: { | |
| 1002 | assert(ty.enumFieldCount() == 1); | |
| 1003 | break :blk 0; | |
| 1004 | }, | |
| 1005 | .enum_literal => i: { | |
| 1006 | const name = val.castTag(.enum_literal).?.data; | |
| 1007 | break :i ty.enumFieldIndex(name).?; | |
| 426 | pub fn unintern(val: Value, arena: Allocator, mod: *Module) Allocator.Error!Value { | |
| 427 | return if (val.ip_index == .none) val else switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 428 | .int_type, | |
| 429 | .ptr_type, | |
| 430 | .array_type, | |
| 431 | .vector_type, | |
| 432 | .opt_type, | |
| 433 | .anyframe_type, | |
| 434 | .error_union_type, | |
| 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()) { | |
| 1014 | .enum_full, .enum_nonexhaustive => { | |
| 1015 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | |
| 1016 | if (enum_full.values.count() != 0) { | |
| 1017 | return enum_full.values.keys()[field_index]; | |
| 1018 | } else { | |
| 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 | } | |
| 464 | .ptr => |ptr| switch (ptr.len) { | |
| 465 | .none => val, | |
| 466 | else => |len| Tag.slice.create(arena, .{ | |
| 467 | .ptr = val.slicePtr(mod), | |
| 468 | .len = len.toValue(), | |
| 469 | }), | |
| 1026 | 470 | }, |
| 1027 | .enum_numbered => { | |
| 1028 | const enum_obj = ty.castTag(.enum_numbered).?.data; | |
| 1029 | if (enum_obj.values.count() != 0) { | |
| 1030 | return enum_obj.values.keys()[field_index]; | |
| 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 | } | |
| 471 | ||
| 472 | .opt => |opt| switch (opt.val) { | |
| 473 | .none => val, | |
| 474 | else => |payload| Tag.opt_payload.create(arena, payload.toValue()), | |
| 1039 | 475 | }, |
| 1040 | .enum_simple => { | |
| 1041 | // Field index and integer values are the same. | |
| 1042 | buffer.* = .{ | |
| 1043 | .base = .{ .tag = .int_u64 }, | |
| 1044 | .data = field_index, | |
| 1045 | }; | |
| 1046 | return Value.initPayload(&buffer.base); | |
| 476 | ||
| 477 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 478 | .bytes => |bytes| Tag.bytes.create(arena, try arena.dupe(u8, bytes)), | |
| 479 | .elems => |old_elems| { | |
| 480 | const new_elems = try arena.alloc(Value, old_elems.len); | |
| 481 | for (new_elems, old_elems) |*new_elem, old_elem| new_elem.* = old_elem.toValue(); | |
| 482 | return Tag.aggregate.create(arena, new_elems); | |
| 483 | }, | |
| 484 | .repeated_elem => |elem| Tag.repeated.create(arena, elem.toValue()), | |
| 1047 | 485 | }, |
| 1048 | else => unreachable, | |
| 1049 | } | |
| 486 | ||
| 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 { | |
| 1053 | if (ty.zigTypeTag() == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(), mod); | |
| 496 | pub fn toIntern(val: Value) InternPool.Index { | |
| 497 | assert(val.ip_index != .none); | |
| 498 | return val.ip_index; | |
| 499 | } | |
| 1054 | 500 | |
| 1055 | const field_index = switch (val.tag()) { | |
| 1056 | .enum_field_index => val.castTag(.enum_field_index).?.data, | |
| 1057 | .the_only_possible_value => blk: { | |
| 1058 | assert(ty.enumFieldCount() == 1); | |
| 1059 | break :blk 0; | |
| 1060 | }, | |
| 1061 | .enum_literal => return val.castTag(.enum_literal).?.data, | |
| 1062 | else => field_index: { | |
| 1063 | const values = switch (ty.tag()) { | |
| 1064 | .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values, | |
| 1065 | .enum_numbered => ty.castTag(.enum_numbered).?.data.values, | |
| 1066 | .enum_simple => Module.EnumFull.ValueMap{}, | |
| 501 | /// Asserts that the value is representable as a type. | |
| 502 | pub fn toType(self: Value) Type { | |
| 503 | return self.toIntern().toType(); | |
| 504 | } | |
| 505 | ||
| 506 | pub fn enumToInt(val: Value, ty: Type, mod: *Module) Allocator.Error!Value { | |
| 507 | const ip = &mod.intern_pool; | |
| 508 | return switch (ip.indexToKey(ip.typeOf(val.toIntern()))) { | |
| 509 | // Assume it is already an integer and return it directly. | |
| 510 | .simple_type, .int_type => val, | |
| 511 | .enum_literal => |enum_literal| { | |
| 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 | 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 | }; | |
| 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, | |
| 523 | .enum_type => |enum_type| try mod.getCoerced(val, enum_type.tag_ty.toType()), | |
| 1083 | 524 | else => unreachable, |
| 1084 | 525 | }; |
| 1085 | return fields.keys()[field_index]; | |
| 1086 | 526 | } |
| 1087 | 527 | |
| 1088 | 528 | /// Asserts the value is an integer. |
| 1089 | pub fn toBigInt(val: Value, space: *BigIntSpace, target: Target) BigIntConst { | |
| 1090 | return val.toBigIntAdvanced(space, target, null) catch unreachable; | |
| 529 | pub fn toBigInt(val: Value, space: *BigIntSpace, mod: *Module) BigIntConst { | |
| 530 | return val.toBigIntAdvanced(space, mod, null) catch unreachable; | |
| 1091 | 531 | } |
| 1092 | 532 | |
| 1093 | 533 | /// Asserts the value is an integer. |
| 1094 | 534 | pub fn toBigIntAdvanced( |
| 1095 | 535 | val: Value, |
| 1096 | 536 | space: *BigIntSpace, |
| 1097 | target: Target, | |
| 537 | mod: *Module, | |
| 1098 | 538 | opt_sema: ?*Sema, |
| 1099 | 539 | ) Module.CompileError!BigIntConst { |
| 1100 | switch (val.tag()) { | |
| 1101 | .null_value, | |
| 1102 | .zero, | |
| 1103 | .bool_false, | |
| 1104 | .the_only_possible_value, // i0, u0 | |
| 1105 | => return BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 1106 | ||
| 1107 | .one, | |
| 1108 | .bool_true, | |
| 1109 | => return BigIntMutable.init(&space.limbs, 1).toConst(), | |
| 1110 | ||
| 1111 | .enum_field_index => { | |
| 1112 | const index = val.castTag(.enum_field_index).?.data; | |
| 1113 | return BigIntMutable.init(&space.limbs, index).toConst(); | |
| 1114 | }, | |
| 1115 | .runtime_value => { | |
| 1116 | const sub_val = val.castTag(.runtime_value).?.data; | |
| 1117 | return sub_val.toBigIntAdvanced(space, target, opt_sema); | |
| 540 | return switch (val.toIntern()) { | |
| 541 | .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 542 | .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(), | |
| 543 | .null_value => BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 544 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 545 | .runtime_value => |runtime_value| runtime_value.val.toValue().toBigIntAdvanced(space, mod, opt_sema), | |
| 546 | .int => |int| switch (int.storage) { | |
| 547 | .u64, .i64, .big_int => int.storage.toBigInt(space), | |
| 548 | .lazy_align, .lazy_size => |ty| { | |
| 549 | if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType()); | |
| 550 | const x = switch (int.storage) { | |
| 551 | else => unreachable, | |
| 552 | .lazy_align => ty.toType().abiAlignment(mod), | |
| 553 | .lazy_size => ty.toType().abiSize(mod), | |
| 554 | }; | |
| 555 | return BigIntMutable.init(&space.limbs, x).toConst(); | |
| 556 | }, | |
| 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(), | |
| 1120 | .int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(), | |
| 1121 | .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(), | |
| 1122 | .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(), | |
| 565 | }; | |
| 566 | } | |
| 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 => { | |
| 1127 | const ty = val.castTag(.lazy_align).?.data; | |
| 1128 | if (opt_sema) |sema| { | |
| 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 | }, | |
| 572 | pub fn getFunctionIndex(val: Value, mod: *Module) Module.Fn.OptionalIndex { | |
| 573 | return if (val.ip_index != .none) mod.intern_pool.indexToFunc(val.toIntern()) else .none; | |
| 574 | } | |
| 1142 | 575 | |
| 1143 | .elem_ptr => { | |
| 1144 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 1145 | const array_addr = (try elem_ptr.array_ptr.getUnsignedIntAdvanced(target, opt_sema)).?; | |
| 1146 | const elem_size = elem_ptr.elem_ty.abiSize(target); | |
| 1147 | const new_addr = array_addr + elem_size * elem_ptr.index; | |
| 1148 | return BigIntMutable.init(&space.limbs, new_addr).toConst(); | |
| 1149 | }, | |
| 576 | pub fn getExternFunc(val: Value, mod: *Module) ?InternPool.Key.ExternFunc { | |
| 577 | return if (val.ip_index != .none) switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 578 | .extern_func => |extern_func| extern_func, | |
| 579 | else => null, | |
| 580 | } else null; | |
| 581 | } | |
| 1150 | 582 | |
| 1151 | else => unreachable, | |
| 1152 | } | |
| 583 | pub fn getVariable(val: Value, mod: *Module) ?InternPool.Key.Variable { | |
| 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 | 590 | /// If the value fits in a u64, return it, otherwise null. |
| 1156 | 591 | /// Asserts not undefined. |
| 1157 | pub fn getUnsignedInt(val: Value, target: Target) ?u64 { | |
| 1158 | return getUnsignedIntAdvanced(val, target, null) catch unreachable; | |
| 592 | pub fn getUnsignedInt(val: Value, mod: *Module) ?u64 { | |
| 593 | return getUnsignedIntAdvanced(val, mod, null) catch unreachable; | |
| 1159 | 594 | } |
| 1160 | 595 | |
| 1161 | 596 | /// If the value fits in a u64, return it, otherwise null. |
| 1162 | 597 | /// Asserts not undefined. |
| 1163 | pub fn getUnsignedIntAdvanced(val: Value, target: Target, opt_sema: ?*Sema) !?u64 { | |
| 1164 | switch (val.tag()) { | |
| 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 | ||
| 598 | pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64 { | |
| 599 | return switch (val.toIntern()) { | |
| 1179 | 600 | .undef => unreachable, |
| 1180 | ||
| 1181 | .lazy_align => { | |
| 1182 | const ty = val.castTag(.lazy_align).?.data; | |
| 1183 | if (opt_sema) |sema| { | |
| 1184 | return (try ty.abiAlignmentAdvanced(target, .{ .sema = sema })).scalar; | |
| 1185 | } else { | |
| 1186 | return ty.abiAlignment(target); | |
| 1187 | } | |
| 1188 | }, | |
| 1189 | .lazy_size => { | |
| 1190 | const ty = val.castTag(.lazy_size).?.data; | |
| 1191 | if (opt_sema) |sema| { | |
| 1192 | return (try ty.abiSizeAdvanced(target, .{ .sema = sema })).scalar; | |
| 1193 | } else { | |
| 1194 | return ty.abiSize(target); | |
| 1195 | } | |
| 601 | .bool_false => 0, | |
| 602 | .bool_true => 1, | |
| 603 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 604 | .undef => unreachable, | |
| 605 | .int => |int| switch (int.storage) { | |
| 606 | .big_int => |big_int| big_int.to(u64) catch null, | |
| 607 | .u64 => |x| x, | |
| 608 | .i64 => |x| std.math.cast(u64, x), | |
| 609 | .lazy_align => |ty| if (opt_sema) |sema| | |
| 610 | (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar | |
| 611 | else | |
| 612 | ty.toType().abiAlignment(mod), | |
| 613 | .lazy_size => |ty| if (opt_sema) |sema| | |
| 614 | (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar | |
| 615 | else | |
| 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 | ||
| 1198 | else => return null, | |
| 1199 | } | |
| 639 | }; | |
| 1200 | 640 | } |
| 1201 | 641 | |
| 1202 | 642 | /// Asserts the value is an integer and it fits in a u64 |
| 1203 | pub fn toUnsignedInt(val: Value, target: Target) u64 { | |
| 1204 | return getUnsignedInt(val, target).?; | |
| 643 | pub fn toUnsignedInt(val: Value, mod: *Module) u64 { | |
| 644 | return getUnsignedInt(val, mod).?; | |
| 1205 | 645 | } |
| 1206 | 646 | |
| 1207 | 647 | /// Asserts the value is an integer and it fits in a i64 |
| 1208 | pub fn toSignedInt(val: Value, target: Target) i64 { | |
| 1209 | switch (val.tag()) { | |
| 1210 | .zero, | |
| 1211 | .bool_false, | |
| 1212 | .the_only_possible_value, // i0, u0 | |
| 1213 | => return 0, | |
| 1214 | ||
| 1215 | .one, | |
| 1216 | .bool_true, | |
| 1217 | => return 1, | |
| 1218 | ||
| 1219 | .int_u64 => return @intCast(i64, val.castTag(.int_u64).?.data), | |
| 1220 | .int_i64 => return val.castTag(.int_i64).?.data, | |
| 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)); | |
| 648 | pub fn toSignedInt(val: Value, mod: *Module) i64 { | |
| 649 | return switch (val.toIntern()) { | |
| 650 | .bool_false => 0, | |
| 651 | .bool_true => 1, | |
| 652 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 653 | .int => |int| switch (int.storage) { | |
| 654 | .big_int => |big_int| big_int.to(i64) catch unreachable, | |
| 655 | .i64 => |x| x, | |
| 656 | .u64 => |x| @intCast(i64, x), | |
| 657 | .lazy_align => |ty| @intCast(i64, ty.toType().abiAlignment(mod)), | |
| 658 | .lazy_size => |ty| @intCast(i64, ty.toType().abiSize(mod)), | |
| 659 | }, | |
| 660 | else => unreachable, | |
| 1231 | 661 | }, |
| 1232 | ||
| 1233 | .undef => unreachable, | |
| 1234 | else => unreachable, | |
| 1235 | } | |
| 662 | }; | |
| 1236 | 663 | } |
| 1237 | 664 | |
| 1238 | pub fn toBool(self: Value) bool { | |
| 1239 | return switch (self.tag()) { | |
| 1240 | .bool_true, .one => true, | |
| 1241 | .bool_false, .zero => 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 | }, | |
| 665 | pub fn toBool(val: Value) bool { | |
| 666 | return switch (val.toIntern()) { | |
| 667 | .bool_true => true, | |
| 668 | .bool_false => false, | |
| 1252 | 669 | else => unreachable, |
| 1253 | 670 | }; |
| 1254 | 671 | } |
| 1255 | 672 | |
| 1256 | fn isDeclRef(val: Value) bool { | |
| 673 | fn isDeclRef(val: Value, mod: *Module) bool { | |
| 1257 | 674 | var check = val; |
| 1258 | while (true) switch (check.tag()) { | |
| 1259 | .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return true, | |
| 1260 | .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr, | |
| 1261 | .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr, | |
| 1262 | .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr, | |
| 675 | while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) { | |
| 676 | .ptr => |ptr| switch (ptr.addr) { | |
| 677 | .decl, .mut_decl, .comptime_field => return true, | |
| 678 | .eu_payload, .opt_payload => |base| check = base.toValue(), | |
| 679 | .elem, .field => |base_index| check = base_index.base.toValue(), | |
| 680 | else => return false, | |
| 681 | }, | |
| 1263 | 682 | else => return false, |
| 1264 | 683 | }; |
| 1265 | 684 | } |
| ... | ... | @@ -1272,62 +691,45 @@ pub const Value = extern union { |
| 1272 | 691 | ReinterpretDeclRef, |
| 1273 | 692 | IllDefinedMemoryLayout, |
| 1274 | 693 | Unimplemented, |
| 694 | OutOfMemory, | |
| 1275 | 695 | }!void { |
| 1276 | 696 | const target = mod.getTarget(); |
| 1277 | 697 | const endian = target.cpu.arch.endian(); |
| 1278 | if (val.isUndef()) { | |
| 1279 | const size = @intCast(usize, ty.abiSize(target)); | |
| 698 | if (val.isUndef(mod)) { | |
| 699 | const size = @intCast(usize, ty.abiSize(mod)); | |
| 1280 | 700 | @memset(buffer[0..size], 0xaa); |
| 1281 | 701 | return; |
| 1282 | 702 | } |
| 1283 | switch (ty.zigTypeTag()) { | |
| 703 | switch (ty.zigTypeTag(mod)) { | |
| 1284 | 704 | .Void => {}, |
| 1285 | 705 | .Bool => { |
| 1286 | 706 | buffer[0] = @boolToInt(val.toBool()); |
| 1287 | 707 | }, |
| 1288 | 708 | .Int, .Enum => { |
| 1289 | const int_info = ty.intInfo(target); | |
| 709 | const int_info = ty.intInfo(mod); | |
| 1290 | 710 | const bits = int_info.bits; |
| 1291 | 711 | const byte_count = (bits + 7) / 8; |
| 1292 | 712 | |
| 1293 | var enum_buffer: Payload.U64 = undefined; | |
| 1294 | const int_val = val.enumToInt(ty, &enum_buffer); | |
| 1295 | ||
| 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 | } | |
| 713 | var bigint_buffer: BigIntSpace = undefined; | |
| 714 | const bigint = val.toBigInt(&bigint_buffer, mod); | |
| 715 | bigint.writeTwosComplement(buffer[0..byte_count], endian); | |
| 1313 | 716 | }, |
| 1314 | 717 | .Float => switch (ty.floatBits(target)) { |
| 1315 | 16 => std.mem.writeInt(u16, buffer[0..2], @bitCast(u16, val.toFloat(f16)), endian), | |
| 1316 | 32 => std.mem.writeInt(u32, buffer[0..4], @bitCast(u32, val.toFloat(f32)), endian), | |
| 1317 | 64 => std.mem.writeInt(u64, buffer[0..8], @bitCast(u64, val.toFloat(f64)), endian), | |
| 1318 | 80 => std.mem.writeInt(u80, buffer[0..10], @bitCast(u80, val.toFloat(f80)), endian), | |
| 1319 | 128 => std.mem.writeInt(u128, buffer[0..16], @bitCast(u128, val.toFloat(f128)), endian), | |
| 718 | 16 => std.mem.writeInt(u16, buffer[0..2], @bitCast(u16, val.toFloat(f16, mod)), endian), | |
| 719 | 32 => std.mem.writeInt(u32, buffer[0..4], @bitCast(u32, val.toFloat(f32, mod)), endian), | |
| 720 | 64 => std.mem.writeInt(u64, buffer[0..8], @bitCast(u64, val.toFloat(f64, mod)), endian), | |
| 721 | 80 => std.mem.writeInt(u80, buffer[0..10], @bitCast(u80, val.toFloat(f80, mod)), endian), | |
| 722 | 128 => std.mem.writeInt(u128, buffer[0..16], @bitCast(u128, val.toFloat(f128, mod)), endian), | |
| 1320 | 723 | else => unreachable, |
| 1321 | 724 | }, |
| 1322 | 725 | .Array => { |
| 1323 | const len = ty.arrayLen(); | |
| 1324 | const elem_ty = ty.childType(); | |
| 1325 | const elem_size = @intCast(usize, elem_ty.abiSize(target)); | |
| 726 | const len = ty.arrayLen(mod); | |
| 727 | const elem_ty = ty.childType(mod); | |
| 728 | const elem_size = @intCast(usize, elem_ty.abiSize(mod)); | |
| 1326 | 729 | var elem_i: usize = 0; |
| 1327 | var elem_value_buf: ElemValueBuffer = undefined; | |
| 1328 | 730 | var buf_off: usize = 0; |
| 1329 | 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 | 733 | try elem_val.writeToMemory(elem_ty, mod, buffer[buf_off..]); |
| 1332 | 734 | buf_off += elem_size; |
| 1333 | 735 | } |
| ... | ... | @@ -1335,52 +737,63 @@ pub const Value = extern union { |
| 1335 | 737 | .Vector => { |
| 1336 | 738 | // We use byte_count instead of abi_size here, so that any padding bytes |
| 1337 | 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 | 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 | 744 | .Auto => return error.IllDefinedMemoryLayout, |
| 1343 | .Extern => { | |
| 1344 | const fields = ty.structFields().values(); | |
| 1345 | const field_vals = val.castTag(.aggregate).?.data; | |
| 1346 | for (fields, 0..) |field, i| { | |
| 1347 | const off = @intCast(usize, ty.structFieldOffset(i, target)); | |
| 1348 | try writeToMemory(field_vals[i], field.ty, mod, buffer[off..]); | |
| 1349 | } | |
| 745 | .Extern => for (ty.structFields(mod).values(), 0..) |field, i| { | |
| 746 | const off = @intCast(usize, ty.structFieldOffset(i, mod)); | |
| 747 | const field_val = switch (val.ip_index) { | |
| 748 | .none => val.castTag(.aggregate).?.data[i], | |
| 749 | else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) { | |
| 750 | .bytes => |bytes| { | |
| 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 | 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 | 762 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); |
| 1354 | 763 | }, |
| 1355 | 764 | }, |
| 1356 | 765 | .ErrorSet => { |
| 1357 | 766 | // TODO revisit this when we have the concept of the error tag type |
| 1358 | 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 | 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 | 777 | .Auto => return error.IllDefinedMemoryLayout, |
| 1364 | 778 | .Extern => return error.Unimplemented, |
| 1365 | 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 | 781 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); |
| 1368 | 782 | }, |
| 1369 | 783 | }, |
| 1370 | 784 | .Pointer => { |
| 1371 | if (ty.isSlice()) return error.IllDefinedMemoryLayout; | |
| 1372 | if (val.isDeclRef()) return error.ReinterpretDeclRef; | |
| 785 | if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout; | |
| 786 | if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; | |
| 1373 | 787 | return val.writeToMemory(Type.usize, mod, buffer); |
| 1374 | 788 | }, |
| 1375 | 789 | .Optional => { |
| 1376 | if (!ty.isPtrLikeOptional()) return error.IllDefinedMemoryLayout; | |
| 1377 | var buf: Type.Payload.ElemType = undefined; | |
| 1378 | const child = ty.optionalChild(&buf); | |
| 1379 | const opt_val = val.optionalValue(); | |
| 790 | if (!ty.isPtrLikeOptional(mod)) return error.IllDefinedMemoryLayout; | |
| 791 | const child = ty.optionalChild(mod); | |
| 792 | const opt_val = val.optionalValue(mod); | |
| 1380 | 793 | if (opt_val) |some| { |
| 1381 | 794 | return some.writeToMemory(child, mod, buffer); |
| 1382 | 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 | 799 | else => return error.Unimplemented, |
| ... | ... | @@ -1391,15 +804,21 @@ pub const Value = extern union { |
| 1391 | 804 | /// |
| 1392 | 805 | /// Both the start and the end of the provided buffer must be tight, since |
| 1393 | 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 | 814 | const target = mod.getTarget(); |
| 1396 | 815 | const endian = target.cpu.arch.endian(); |
| 1397 | if (val.isUndef()) { | |
| 1398 | const bit_size = @intCast(usize, ty.bitSize(target)); | |
| 816 | if (val.isUndef(mod)) { | |
| 817 | const bit_size = @intCast(usize, ty.bitSize(mod)); | |
| 1399 | 818 | std.mem.writeVarPackedInt(buffer, bit_offset, bit_size, @as(u1, 0), endian); |
| 1400 | 819 | return; |
| 1401 | 820 | } |
| 1402 | switch (ty.zigTypeTag()) { | |
| 821 | switch (ty.zigTypeTag(mod)) { | |
| 1403 | 822 | .Void => {}, |
| 1404 | 823 | .Bool => { |
| 1405 | 824 | const byte_index = switch (endian) { |
| ... | ... | @@ -1413,91 +832,82 @@ pub const Value = extern union { |
| 1413 | 832 | } |
| 1414 | 833 | }, |
| 1415 | 834 | .Int, .Enum => { |
| 1416 | const bits = ty.intInfo(target).bits; | |
| 1417 | const abi_size = @intCast(usize, ty.abiSize(target)); | |
| 1418 | ||
| 1419 | var enum_buffer: Payload.U64 = undefined; | |
| 1420 | const int_val = val.enumToInt(ty, &enum_buffer); | |
| 1421 | ||
| 1422 | if (abi_size == 0) return; | |
| 1423 | if (abi_size <= @sizeOf(u64)) { | |
| 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); | |
| 835 | if (buffer.len == 0) return; | |
| 836 | const bits = ty.intInfo(mod).bits; | |
| 837 | if (bits == 0) return; | |
| 838 | ||
| 839 | switch (mod.intern_pool.indexToKey((try val.enumToInt(ty, mod)).toIntern()).int.storage) { | |
| 840 | inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian), | |
| 841 | .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian), | |
| 842 | else => unreachable, | |
| 1436 | 843 | } |
| 1437 | 844 | }, |
| 1438 | 845 | .Float => switch (ty.floatBits(target)) { |
| 1439 | 16 => std.mem.writePackedInt(u16, buffer, bit_offset, @bitCast(u16, val.toFloat(f16)), endian), | |
| 1440 | 32 => std.mem.writePackedInt(u32, buffer, bit_offset, @bitCast(u32, val.toFloat(f32)), endian), | |
| 1441 | 64 => std.mem.writePackedInt(u64, buffer, bit_offset, @bitCast(u64, val.toFloat(f64)), endian), | |
| 1442 | 80 => std.mem.writePackedInt(u80, buffer, bit_offset, @bitCast(u80, val.toFloat(f80)), endian), | |
| 1443 | 128 => std.mem.writePackedInt(u128, buffer, bit_offset, @bitCast(u128, val.toFloat(f128)), endian), | |
| 846 | 16 => std.mem.writePackedInt(u16, buffer, bit_offset, @bitCast(u16, val.toFloat(f16, mod)), endian), | |
| 847 | 32 => std.mem.writePackedInt(u32, buffer, bit_offset, @bitCast(u32, val.toFloat(f32, mod)), endian), | |
| 848 | 64 => std.mem.writePackedInt(u64, buffer, bit_offset, @bitCast(u64, val.toFloat(f64, mod)), endian), | |
| 849 | 80 => std.mem.writePackedInt(u80, buffer, bit_offset, @bitCast(u80, val.toFloat(f80, mod)), endian), | |
| 850 | 128 => std.mem.writePackedInt(u128, buffer, bit_offset, @bitCast(u128, val.toFloat(f128, mod)), endian), | |
| 1444 | 851 | else => unreachable, |
| 1445 | 852 | }, |
| 1446 | 853 | .Vector => { |
| 1447 | const elem_ty = ty.childType(); | |
| 1448 | const elem_bit_size = @intCast(u16, elem_ty.bitSize(target)); | |
| 1449 | const len = @intCast(usize, ty.arrayLen()); | |
| 854 | const elem_ty = ty.childType(mod); | |
| 855 | const elem_bit_size = @intCast(u16, elem_ty.bitSize(mod)); | |
| 856 | const len = @intCast(usize, ty.arrayLen(mod)); | |
| 1450 | 857 | |
| 1451 | 858 | var bits: u16 = 0; |
| 1452 | 859 | var elem_i: usize = 0; |
| 1453 | var elem_value_buf: ElemValueBuffer = undefined; | |
| 1454 | 860 | while (elem_i < len) : (elem_i += 1) { |
| 1455 | 861 | // On big-endian systems, LLVM reverses the element order of vectors by default |
| 1456 | 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 | 864 | try elem_val.writeToPackedMemory(elem_ty, mod, buffer, bit_offset + bits); |
| 1459 | 865 | bits += elem_bit_size; |
| 1460 | 866 | } |
| 1461 | 867 | }, |
| 1462 | .Struct => switch (ty.containerLayout()) { | |
| 868 | .Struct => switch (ty.containerLayout(mod)) { | |
| 1463 | 869 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 1464 | 870 | .Extern => unreachable, // Handled in non-packed writeToMemory |
| 1465 | 871 | .Packed => { |
| 1466 | 872 | var bits: u16 = 0; |
| 1467 | const fields = ty.structFields().values(); | |
| 1468 | const field_vals = val.castTag(.aggregate).?.data; | |
| 873 | const fields = ty.structFields(mod).values(); | |
| 874 | const storage = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage; | |
| 1469 | 875 | for (fields, 0..) |field, i| { |
| 1470 | const field_bits = @intCast(u16, field.ty.bitSize(target)); | |
| 1471 | try field_vals[i].writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits); | |
| 876 | const field_bits = @intCast(u16, field.ty.bitSize(mod)); | |
| 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 | 883 | bits += field_bits; |
| 1473 | 884 | } |
| 1474 | 885 | }, |
| 1475 | 886 | }, |
| 1476 | .Union => switch (ty.containerLayout()) { | |
| 887 | .Union => switch (ty.containerLayout(mod)) { | |
| 1477 | 888 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 1478 | 889 | .Extern => unreachable, // Handled in non-packed writeToMemory |
| 1479 | 890 | .Packed => { |
| 1480 | const field_index = ty.unionTagFieldIndex(val.unionTag(), mod); | |
| 1481 | const field_type = ty.unionFields().values()[field_index.?].ty; | |
| 1482 | const field_val = val.fieldValue(field_type, field_index.?); | |
| 891 | const field_index = ty.unionTagFieldIndex(val.unionTag(mod), mod); | |
| 892 | const field_type = ty.unionFields(mod).values()[field_index.?].ty; | |
| 893 | const field_val = try val.fieldValue(mod, field_index.?); | |
| 1483 | 894 | |
| 1484 | 895 | return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset); |
| 1485 | 896 | }, |
| 1486 | 897 | }, |
| 1487 | 898 | .Pointer => { |
| 1488 | assert(!ty.isSlice()); // No well defined layout. | |
| 1489 | if (val.isDeclRef()) return error.ReinterpretDeclRef; | |
| 899 | assert(!ty.isSlice(mod)); // No well defined layout. | |
| 900 | if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; | |
| 1490 | 901 | return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset); |
| 1491 | 902 | }, |
| 1492 | 903 | .Optional => { |
| 1493 | assert(ty.isPtrLikeOptional()); | |
| 1494 | var buf: Type.Payload.ElemType = undefined; | |
| 1495 | const child = ty.optionalChild(&buf); | |
| 1496 | const opt_val = val.optionalValue(); | |
| 904 | assert(ty.isPtrLikeOptional(mod)); | |
| 905 | const child = ty.optionalChild(mod); | |
| 906 | const opt_val = val.optionalValue(mod); | |
| 1497 | 907 | if (opt_val) |some| { |
| 1498 | 908 | return some.writeToPackedMemory(child, mod, buffer, bit_offset); |
| 1499 | 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 | 913 | else => @panic("TODO implement writeToPackedMemory for more types"), |
| ... | ... | @@ -1516,7 +926,7 @@ pub const Value = extern union { |
| 1516 | 926 | ) Allocator.Error!Value { |
| 1517 | 927 | const target = mod.getTarget(); |
| 1518 | 928 | const endian = target.cpu.arch.endian(); |
| 1519 | switch (ty.zigTypeTag()) { | |
| 929 | switch (ty.zigTypeTag(mod)) { | |
| 1520 | 930 | .Void => return Value.void, |
| 1521 | 931 | .Bool => { |
| 1522 | 932 | if (buffer[0] == 0) { |
| ... | ... | @@ -1525,20 +935,27 @@ pub const Value = extern union { |
| 1525 | 935 | return Value.true; |
| 1526 | 936 | } |
| 1527 | 937 | }, |
| 1528 | .Int, .Enum => { | |
| 1529 | const int_info = ty.intInfo(target); | |
| 938 | .Int, .Enum => |ty_tag| { | |
| 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 | 945 | const bits = int_info.bits; |
| 1531 | 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 | 949 | if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u64 |
| 1535 | 950 | .signed => { |
| 1536 | 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 | 955 | .unsigned => { |
| 1540 | 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 | 960 | } else { // Slow path, we have to construct a big-int |
| 1544 | 961 | const Limb = std.math.big.Limb; |
| ... | ... | @@ -1547,48 +964,57 @@ pub const Value = extern union { |
| 1547 | 964 | |
| 1548 | 965 | var bigint = BigIntMutable.init(limbs_buffer, 0); |
| 1549 | 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)) { | |
| 1554 | 16 => return Value.Tag.float_16.create(arena, @bitCast(f16, std.mem.readInt(u16, buffer[0..2], endian))), | |
| 1555 | 32 => return Value.Tag.float_32.create(arena, @bitCast(f32, std.mem.readInt(u32, buffer[0..4], endian))), | |
| 1556 | 64 => return Value.Tag.float_64.create(arena, @bitCast(f64, std.mem.readInt(u64, buffer[0..8], endian))), | |
| 1557 | 80 => return Value.Tag.float_80.create(arena, @bitCast(f80, std.mem.readInt(u80, buffer[0..10], endian))), | |
| 1558 | 128 => return Value.Tag.float_128.create(arena, @bitCast(f128, std.mem.readInt(u128, buffer[0..16], endian))), | |
| 1559 | else => unreachable, | |
| 1560 | }, | |
| 970 | .Float => return (try mod.intern(.{ .float = .{ | |
| 971 | .ty = ty.toIntern(), | |
| 972 | .storage = switch (ty.floatBits(target)) { | |
| 973 | 16 => .{ .f16 = @bitCast(f16, std.mem.readInt(u16, buffer[0..2], endian)) }, | |
| 974 | 32 => .{ .f32 = @bitCast(f32, std.mem.readInt(u32, buffer[0..4], endian)) }, | |
| 975 | 64 => .{ .f64 = @bitCast(f64, std.mem.readInt(u64, buffer[0..8], endian)) }, | |
| 976 | 80 => .{ .f80 = @bitCast(f80, std.mem.readInt(u80, buffer[0..10], endian)) }, | |
| 977 | 128 => .{ .f128 = @bitCast(f128, std.mem.readInt(u128, buffer[0..16], endian)) }, | |
| 978 | else => unreachable, | |
| 979 | }, | |
| 980 | } })).toValue(), | |
| 1561 | 981 | .Array => { |
| 1562 | const elem_ty = ty.childType(); | |
| 1563 | const elem_size = elem_ty.abiSize(target); | |
| 1564 | const elems = try arena.alloc(Value, @intCast(usize, ty.arrayLen())); | |
| 982 | const elem_ty = ty.childType(mod); | |
| 983 | const elem_size = elem_ty.abiSize(mod); | |
| 984 | const elems = try arena.alloc(InternPool.Index, @intCast(usize, ty.arrayLen(mod))); | |
| 1565 | 985 | var offset: usize = 0; |
| 1566 | 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 | 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 | 995 | .Vector => { |
| 1573 | 996 | // We use byte_count instead of abi_size here, so that any padding bytes |
| 1574 | 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 | 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 | 1002 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 1580 | 1003 | .Extern => { |
| 1581 | const fields = ty.structFields().values(); | |
| 1582 | const field_vals = try arena.alloc(Value, fields.len); | |
| 1583 | for (fields, 0..) |field, i| { | |
| 1584 | const off = @intCast(usize, ty.structFieldOffset(i, target)); | |
| 1585 | const sz = @intCast(usize, ty.structFieldType(i).abiSize(target)); | |
| 1586 | field_vals[i] = try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena); | |
| 1004 | const fields = ty.structFields(mod).values(); | |
| 1005 | const field_vals = try arena.alloc(InternPool.Index, fields.len); | |
| 1006 | for (field_vals, fields, 0..) |*field_val, field, i| { | |
| 1007 | const off = @intCast(usize, ty.structFieldOffset(i, mod)); | |
| 1008 | const sz = @intCast(usize, field.ty.abiSize(mod)); | |
| 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 | 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 | 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 | 1022 | // TODO revisit this when we have the concept of the error tag type |
| 1597 | 1023 | const Int = u16; |
| 1598 | 1024 | const int = std.mem.readInt(Int, buffer[0..@sizeOf(Int)], endian); |
| 1599 | ||
| 1600 | const payload = try arena.create(Value.Payload.Error); | |
| 1601 | payload.* = .{ | |
| 1602 | .base = .{ .tag = .@"error" }, | |
| 1603 | .data = .{ .name = mod.error_name_list.items[@intCast(usize, int)] }, | |
| 1604 | }; | |
| 1605 | return Value.initPayload(&payload.base); | |
| 1025 | const name = mod.global_error_set.keys()[@intCast(usize, int)]; | |
| 1026 | return (try mod.intern(.{ .err = .{ | |
| 1027 | .ty = ty.toIntern(), | |
| 1028 | .name = name, | |
| 1029 | } })).toValue(); | |
| 1606 | 1030 | }, |
| 1607 | 1031 | .Pointer => { |
| 1608 | assert(!ty.isSlice()); // No well defined layout. | |
| 1032 | assert(!ty.isSlice(mod)); // No well defined layout. | |
| 1609 | 1033 | return readFromMemory(Type.usize, mod, buffer, arena); |
| 1610 | 1034 | }, |
| 1611 | 1035 | .Optional => { |
| 1612 | assert(ty.isPtrLikeOptional()); | |
| 1613 | var buf: Type.Payload.ElemType = undefined; | |
| 1614 | const child = ty.optionalChild(&buf); | |
| 1036 | assert(ty.isPtrLikeOptional(mod)); | |
| 1037 | const child = ty.optionalChild(mod); | |
| 1615 | 1038 | return readFromMemory(child, mod, buffer, arena); |
| 1616 | 1039 | }, |
| 1617 | 1040 | else => @panic("TODO implement readFromMemory for more types"), |
| ... | ... | @@ -1631,7 +1054,7 @@ pub const Value = extern union { |
| 1631 | 1054 | ) Allocator.Error!Value { |
| 1632 | 1055 | const target = mod.getTarget(); |
| 1633 | 1056 | const endian = target.cpu.arch.endian(); |
| 1634 | switch (ty.zigTypeTag()) { | |
| 1057 | switch (ty.zigTypeTag(mod)) { | |
| 1635 | 1058 | .Void => return Value.void, |
| 1636 | 1059 | .Bool => { |
| 1637 | 1060 | const byte = switch (endian) { |
| ... | ... | @@ -1644,71 +1067,94 @@ pub const Value = extern union { |
| 1644 | 1067 | return Value.true; |
| 1645 | 1068 | } |
| 1646 | 1069 | }, |
| 1647 | .Int, .Enum => { | |
| 1648 | if (buffer.len == 0) return Value.zero; | |
| 1649 | const int_info = ty.intInfo(target); | |
| 1650 | const abi_size = @intCast(usize, ty.abiSize(target)); | |
| 1651 | ||
| 1070 | .Int, .Enum => |ty_tag| { | |
| 1071 | if (buffer.len == 0) return mod.intValue(ty, 0); | |
| 1072 | const int_info = ty.intInfo(mod); | |
| 1652 | 1073 | const bits = int_info.bits; |
| 1653 | if (bits == 0) return Value.zero; | |
| 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); | |
| 1074 | if (bits == 0) return mod.intValue(ty, 0); | |
| 1661 | 1075 | |
| 1662 | var bigint = BigIntMutable.init(limbs_buffer, 0); | |
| 1663 | bigint.readPackedTwosComplement(buffer, bit_offset, bits, endian, int_info.signedness); | |
| 1664 | return fromBigInt(arena, bigint.toConst()); | |
| 1076 | // Fast path for integers <= u64 | |
| 1077 | if (bits <= 64) { | |
| 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 | }, | |
| 1667 | .Float => switch (ty.floatBits(target)) { | |
| 1668 | 16 => return Value.Tag.float_16.create(arena, @bitCast(f16, std.mem.readPackedInt(u16, buffer, bit_offset, endian))), | |
| 1669 | 32 => return Value.Tag.float_32.create(arena, @bitCast(f32, std.mem.readPackedInt(u32, buffer, bit_offset, endian))), | |
| 1670 | 64 => return Value.Tag.float_64.create(arena, @bitCast(f64, std.mem.readPackedInt(u64, buffer, bit_offset, endian))), | |
| 1671 | 80 => return Value.Tag.float_80.create(arena, @bitCast(f80, std.mem.readPackedInt(u80, buffer, bit_offset, endian))), | |
| 1672 | 128 => return Value.Tag.float_128.create(arena, @bitCast(f128, std.mem.readPackedInt(u128, buffer, bit_offset, endian))), | |
| 1673 | else => unreachable, | |
| 1674 | }, | |
| 1094 | ||
| 1095 | // Slow path, we have to construct a big-int | |
| 1096 | const abi_size = @intCast(usize, ty.abiSize(mod)); | |
| 1097 | const Limb = std.math.big.Limb; | |
| 1098 | const limb_count = (abi_size + @sizeOf(Limb) - 1) / @sizeOf(Limb); | |
| 1099 | const limbs_buffer = try arena.alloc(Limb, limb_count); | |
| 1100 | ||
| 1101 | var bigint = BigIntMutable.init(limbs_buffer, 0); | |
| 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 | 1116 | .Vector => { |
| 1676 | const elem_ty = ty.childType(); | |
| 1677 | const elems = try arena.alloc(Value, @intCast(usize, ty.arrayLen())); | |
| 1117 | const elem_ty = ty.childType(mod); | |
| 1118 | const elems = try arena.alloc(InternPool.Index, @intCast(usize, ty.arrayLen(mod))); | |
| 1678 | 1119 | |
| 1679 | 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 | 1122 | for (elems, 0..) |_, i| { |
| 1682 | 1123 | // On big-endian systems, LLVM reverses the element order of vectors by default |
| 1683 | 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 | 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 | 1134 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 1691 | 1135 | .Extern => unreachable, // Handled by non-packed readFromMemory |
| 1692 | 1136 | .Packed => { |
| 1693 | 1137 | var bits: u16 = 0; |
| 1694 | const fields = ty.structFields().values(); | |
| 1695 | const field_vals = try arena.alloc(Value, fields.len); | |
| 1138 | const fields = ty.structFields(mod).values(); | |
| 1139 | const field_vals = try arena.alloc(InternPool.Index, fields.len); | |
| 1696 | 1140 | for (fields, 0..) |field, i| { |
| 1697 | const field_bits = @intCast(u16, field.ty.bitSize(target)); | |
| 1698 | field_vals[i] = try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena); | |
| 1141 | const field_bits = @intCast(u16, field.ty.bitSize(mod)); | |
| 1142 | field_vals[i] = try (try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena)).intern(field.ty, mod); | |
| 1699 | 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 | 1151 | .Pointer => { |
| 1705 | assert(!ty.isSlice()); // No well defined layout. | |
| 1152 | assert(!ty.isSlice(mod)); // No well defined layout. | |
| 1706 | 1153 | return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena); |
| 1707 | 1154 | }, |
| 1708 | 1155 | .Optional => { |
| 1709 | assert(ty.isPtrLikeOptional()); | |
| 1710 | var buf: Type.Payload.ElemType = undefined; | |
| 1711 | const child = ty.optionalChild(&buf); | |
| 1156 | assert(ty.isPtrLikeOptional(mod)); | |
| 1157 | const child = ty.optionalChild(mod); | |
| 1712 | 1158 | return readFromPackedMemory(child, mod, buffer, bit_offset, arena); |
| 1713 | 1159 | }, |
| 1714 | 1160 | else => @panic("TODO implement readFromPackedMemory for more types"), |
| ... | ... | @@ -1716,31 +1162,22 @@ pub const Value = extern union { |
| 1716 | 1162 | } |
| 1717 | 1163 | |
| 1718 | 1164 | /// Asserts that the value is a float or an integer. |
| 1719 | pub fn toFloat(val: Value, comptime T: type) T { | |
| 1720 | return switch (val.tag()) { | |
| 1721 | .float_16 => @floatCast(T, val.castTag(.float_16).?.data), | |
| 1722 | .float_32 => @floatCast(T, val.castTag(.float_32).?.data), | |
| 1723 | .float_64 => @floatCast(T, val.castTag(.float_64).?.data), | |
| 1724 | .float_80 => @floatCast(T, val.castTag(.float_80).?.data), | |
| 1725 | .float_128 => @floatCast(T, val.castTag(.float_128).?.data), | |
| 1726 | ||
| 1727 | .zero => 0, | |
| 1728 | .one => 1, | |
| 1729 | .int_u64 => { | |
| 1730 | if (T == f80) { | |
| 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); | |
| 1165 | pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { | |
| 1166 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1167 | .int => |int| switch (int.storage) { | |
| 1168 | .big_int => |big_int| @floatCast(T, bigIntToFloat(big_int.limbs, big_int.positive)), | |
| 1169 | inline .u64, .i64 => |x| { | |
| 1170 | if (T == f80) { | |
| 1171 | @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); | |
| 1172 | } | |
| 1173 | return @intToFloat(T, x); | |
| 1174 | }, | |
| 1175 | .lazy_align => |ty| @intToFloat(T, ty.toType().abiAlignment(mod)), | |
| 1176 | .lazy_size => |ty| @intToFloat(T, ty.toType().abiSize(mod)), | |
| 1734 | 1177 | }, |
| 1735 | .int_i64 => { | |
| 1736 | if (T == f80) { | |
| 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); | |
| 1178 | .float => |float| switch (float.storage) { | |
| 1179 | inline else => |x| @floatCast(T, x), | |
| 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 | 1181 | else => unreachable, |
| 1745 | 1182 | }; |
| 1746 | 1183 | } |
| ... | ... | @@ -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 { | |
| 1768 | const ty_bits = ty.intInfo(target).bits; | |
| 1769 | switch (val.tag()) { | |
| 1770 | .zero, .bool_false => return ty_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 | } | |
| 1204 | pub fn clz(val: Value, ty: Type, mod: *Module) u64 { | |
| 1205 | var bigint_buf: BigIntSpace = undefined; | |
| 1206 | const bigint = val.toBigInt(&bigint_buf, mod); | |
| 1207 | return bigint.clz(ty.intInfo(mod).bits); | |
| 1801 | 1208 | } |
| 1802 | 1209 | |
| 1803 | pub fn ctz(val: Value, ty: Type, target: Target) u64 { | |
| 1804 | const ty_bits = ty.intInfo(target).bits; | |
| 1805 | switch (val.tag()) { | |
| 1806 | .zero, .bool_false => return ty_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 | } | |
| 1210 | pub fn ctz(val: Value, ty: Type, mod: *Module) u64 { | |
| 1211 | var bigint_buf: BigIntSpace = undefined; | |
| 1212 | const bigint = val.toBigInt(&bigint_buf, mod); | |
| 1213 | return bigint.ctz(ty.intInfo(mod).bits); | |
| 1837 | 1214 | } |
| 1838 | 1215 | |
| 1839 | pub fn popCount(val: Value, ty: Type, target: Target) u64 { | |
| 1840 | assert(!val.isUndef()); | |
| 1841 | switch (val.tag()) { | |
| 1842 | .zero, .bool_false => return 0, | |
| 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 | } | |
| 1216 | pub fn popCount(val: Value, ty: Type, mod: *Module) u64 { | |
| 1217 | var bigint_buf: BigIntSpace = undefined; | |
| 1218 | const bigint = val.toBigInt(&bigint_buf, mod); | |
| 1219 | return @intCast(u64, bigint.popCount(ty.intInfo(mod).bits)); | |
| 1855 | 1220 | } |
| 1856 | 1221 | |
| 1857 | pub fn bitReverse(val: Value, ty: Type, target: Target, arena: Allocator) !Value { | |
| 1858 | assert(!val.isUndef()); | |
| 1859 | ||
| 1860 | const info = ty.intInfo(target); | |
| 1222 | pub fn bitReverse(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value { | |
| 1223 | const info = ty.intInfo(mod); | |
| 1861 | 1224 | |
| 1862 | 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 | 1228 | const limbs = try arena.alloc( |
| 1866 | 1229 | std.math.big.Limb, |
| ... | ... | @@ -1869,19 +1232,17 @@ pub const Value = extern union { |
| 1869 | 1232 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 1870 | 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 { | |
| 1876 | assert(!val.isUndef()); | |
| 1877 | ||
| 1878 | const info = ty.intInfo(target); | |
| 1238 | pub fn byteSwap(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value { | |
| 1239 | const info = ty.intInfo(mod); | |
| 1879 | 1240 | |
| 1880 | 1241 | // Bit count must be evenly divisible by 8 |
| 1881 | 1242 | assert(info.bits % 8 == 0); |
| 1882 | 1243 | |
| 1883 | 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 | 1247 | const limbs = try arena.alloc( |
| 1887 | 1248 | std.math.big.Limb, |
| ... | ... | @@ -1890,176 +1251,98 @@ pub const Value = extern union { |
| 1890 | 1251 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 1891 | 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 | 1257 | /// Asserts the value is an integer and not undefined. |
| 1897 | 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 { | |
| 1899 | switch (self.tag()) { | |
| 1900 | .zero, | |
| 1901 | .bool_false, | |
| 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 | } | |
| 1259 | pub fn intBitCountTwosComp(self: Value, mod: *Module) usize { | |
| 1260 | var buffer: BigIntSpace = undefined; | |
| 1261 | const big_int = self.toBigInt(&buffer, mod); | |
| 1262 | return big_int.bitCountTwosComp(); | |
| 1932 | 1263 | } |
| 1933 | 1264 | |
| 1934 | 1265 | /// Converts an integer or a float to a float. May result in a loss of information. |
| 1935 | 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 { | |
| 1937 | switch (dest_ty.floatBits(target)) { | |
| 1938 | 16 => return Value.Tag.float_16.create(arena, self.toFloat(f16)), | |
| 1939 | 32 => return Value.Tag.float_32.create(arena, self.toFloat(f32)), | |
| 1940 | 64 => return Value.Tag.float_64.create(arena, self.toFloat(f64)), | |
| 1941 | 80 => return Value.Tag.float_80.create(arena, self.toFloat(f80)), | |
| 1942 | 128 => return Value.Tag.float_128.create(arena, self.toFloat(f128)), | |
| 1943 | else => unreachable, | |
| 1944 | } | |
| 1267 | pub fn floatCast(self: Value, dest_ty: Type, mod: *Module) !Value { | |
| 1268 | const target = mod.getTarget(); | |
| 1269 | return (try mod.intern(.{ .float = .{ | |
| 1270 | .ty = dest_ty.toIntern(), | |
| 1271 | .storage = switch (dest_ty.floatBits(target)) { | |
| 1272 | 16 => .{ .f16 = self.toFloat(f16, mod) }, | |
| 1273 | 32 => .{ .f32 = self.toFloat(f32, mod) }, | |
| 1274 | 64 => .{ .f64 = self.toFloat(f64, mod) }, | |
| 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 | 1282 | /// Asserts the value is a float |
| 1948 | pub fn floatHasFraction(self: Value) bool { | |
| 1949 | return switch (self.tag()) { | |
| 1950 | .zero, | |
| 1951 | .one, | |
| 1952 | => false, | |
| 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 | ||
| 1283 | pub fn floatHasFraction(self: Value, mod: *const Module) bool { | |
| 1284 | return switch (mod.intern_pool.indexToKey(self.toIntern())) { | |
| 1285 | .float => |float| switch (float.storage) { | |
| 1286 | inline else => |x| @rem(x, 1) != 0, | |
| 1287 | }, | |
| 1961 | 1288 | else => unreachable, |
| 1962 | 1289 | }; |
| 1963 | 1290 | } |
| 1964 | 1291 | |
| 1965 | pub fn orderAgainstZero(lhs: Value) std.math.Order { | |
| 1966 | return orderAgainstZeroAdvanced(lhs, null) catch unreachable; | |
| 1292 | pub fn orderAgainstZero(lhs: Value, mod: *Module) std.math.Order { | |
| 1293 | return orderAgainstZeroAdvanced(lhs, mod, null) catch unreachable; | |
| 1967 | 1294 | } |
| 1968 | 1295 | |
| 1969 | 1296 | pub fn orderAgainstZeroAdvanced( |
| 1970 | 1297 | lhs: Value, |
| 1298 | mod: *Module, | |
| 1971 | 1299 | opt_sema: ?*Sema, |
| 1972 | 1300 | ) Module.CompileError!std.math.Order { |
| 1973 | return switch (lhs.tag()) { | |
| 1974 | .zero, | |
| 1975 | .bool_false, | |
| 1976 | .the_only_possible_value, | |
| 1977 | => .eq, | |
| 1978 | ||
| 1979 | .one, | |
| 1980 | .bool_true, | |
| 1981 | .decl_ref, | |
| 1982 | .decl_ref_mut, | |
| 1983 | .comptime_field_ptr, | |
| 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 | } | |
| 1301 | return switch (lhs.toIntern()) { | |
| 1302 | .bool_false => .eq, | |
| 1303 | .bool_true => .gt, | |
| 1304 | else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) { | |
| 1305 | .ptr => |ptr| switch (ptr.addr) { | |
| 1306 | .decl, .mut_decl, .comptime_field => .gt, | |
| 1307 | .int => |int| int.toValue().orderAgainstZeroAdvanced(mod, opt_sema), | |
| 1308 | .elem => |elem| switch (try elem.base.toValue().orderAgainstZeroAdvanced(mod, opt_sema)) { | |
| 1309 | .lt => unreachable, | |
| 1310 | .gt => .gt, | |
| 1311 | .eq => if (elem.index == 0) .eq else .gt, | |
| 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 | 1336 | /// Asserts the value is comparable. |
| 2052 | pub fn order(lhs: Value, rhs: Value, target: Target) std.math.Order { | |
| 2053 | return orderAdvanced(lhs, rhs, target, null) catch unreachable; | |
| 1337 | pub fn order(lhs: Value, rhs: Value, mod: *Module) std.math.Order { | |
| 1338 | return orderAdvanced(lhs, rhs, mod, null) catch unreachable; | |
| 2054 | 1339 | } |
| 2055 | 1340 | |
| 2056 | 1341 | /// Asserts the value is comparable. |
| 2057 | 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 { | |
| 2059 | const lhs_tag = lhs.tag(); | |
| 2060 | const rhs_tag = rhs.tag(); | |
| 2061 | const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(opt_sema); | |
| 2062 | const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(opt_sema); | |
| 1343 | pub fn orderAdvanced(lhs: Value, rhs: Value, mod: *Module, opt_sema: ?*Sema) !std.math.Order { | |
| 1344 | const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(mod, opt_sema); | |
| 1345 | const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(mod, opt_sema); | |
| 2063 | 1346 | switch (lhs_against_zero) { |
| 2064 | 1347 | .lt => if (rhs_against_zero != .lt) return .lt, |
| 2065 | 1348 | .eq => return rhs_against_zero.invert(), |
| ... | ... | @@ -2071,48 +1354,34 @@ pub const Value = extern union { |
| 2071 | 1354 | .gt => {}, |
| 2072 | 1355 | } |
| 2073 | 1356 | |
| 2074 | const lhs_float = lhs.isFloat(); | |
| 2075 | const rhs_float = rhs.isFloat(); | |
| 2076 | if (lhs_float and rhs_float) { | |
| 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); | |
| 1357 | if (lhs.isFloat(mod) or rhs.isFloat(mod)) { | |
| 1358 | const lhs_f128 = lhs.toFloat(f128, mod); | |
| 1359 | const rhs_f128 = rhs.toFloat(f128, mod); | |
| 2091 | 1360 | return std.math.order(lhs_f128, rhs_f128); |
| 2092 | 1361 | } |
| 2093 | 1362 | |
| 2094 | 1363 | var lhs_bigint_space: BigIntSpace = undefined; |
| 2095 | 1364 | var rhs_bigint_space: BigIntSpace = undefined; |
| 2096 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, target, opt_sema); | |
| 2097 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, target, opt_sema); | |
| 1365 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, mod, opt_sema); | |
| 1366 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, mod, opt_sema); | |
| 2098 | 1367 | return lhs_bigint.order(rhs_bigint); |
| 2099 | 1368 | } |
| 2100 | 1369 | |
| 2101 | 1370 | /// Asserts the value is comparable. Does not take a type parameter because it supports |
| 2102 | 1371 | /// comparisons between heterogeneous types. |
| 2103 | pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, target: Target) bool { | |
| 2104 | return compareHeteroAdvanced(lhs, op, rhs, target, null) catch unreachable; | |
| 1372 | pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, mod: *Module) bool { | |
| 1373 | return compareHeteroAdvanced(lhs, op, rhs, mod, null) catch unreachable; | |
| 2105 | 1374 | } |
| 2106 | 1375 | |
| 2107 | 1376 | pub fn compareHeteroAdvanced( |
| 2108 | 1377 | lhs: Value, |
| 2109 | 1378 | op: std.math.CompareOperator, |
| 2110 | 1379 | rhs: Value, |
| 2111 | target: Target, | |
| 1380 | mod: *Module, | |
| 2112 | 1381 | opt_sema: ?*Sema, |
| 2113 | 1382 | ) !bool { |
| 2114 | if (lhs.pointerDecl()) |lhs_decl| { | |
| 2115 | if (rhs.pointerDecl()) |rhs_decl| { | |
| 1383 | if (lhs.pointerDecl(mod)) |lhs_decl| { | |
| 1384 | if (rhs.pointerDecl(mod)) |rhs_decl| { | |
| 2116 | 1385 | switch (op) { |
| 2117 | 1386 | .eq => return lhs_decl == rhs_decl, |
| 2118 | 1387 | .neq => return lhs_decl != rhs_decl, |
| ... | ... | @@ -2125,27 +1394,25 @@ pub const Value = extern union { |
| 2125 | 1394 | else => {}, |
| 2126 | 1395 | } |
| 2127 | 1396 | } |
| 2128 | } else if (rhs.pointerDecl()) |_| { | |
| 1397 | } else if (rhs.pointerDecl(mod)) |_| { | |
| 2129 | 1398 | switch (op) { |
| 2130 | 1399 | .eq => return false, |
| 2131 | 1400 | .neq => return true, |
| 2132 | 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 | 1407 | /// Asserts the values are comparable. Both operands have type `ty`. |
| 2139 | 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 { | |
| 2141 | if (ty.zigTypeTag() == .Vector) { | |
| 2142 | var i: usize = 0; | |
| 2143 | while (i < ty.vectorLen()) : (i += 1) { | |
| 2144 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 2145 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 2146 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 2147 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 2148 | if (!compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(), mod)) { | |
| 1409 | pub fn compareAll(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, mod: *Module) !bool { | |
| 1410 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 1411 | const scalar_ty = ty.scalarType(mod); | |
| 1412 | for (0..ty.vectorLen(mod)) |i| { | |
| 1413 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 1414 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 1415 | if (!compareScalar(lhs_elem, op, rhs_elem, scalar_ty, mod)) { | |
| 2149 | 1416 | return false; |
| 2150 | 1417 | } |
| 2151 | 1418 | } |
| ... | ... | @@ -2165,7 +1432,7 @@ pub const Value = extern union { |
| 2165 | 1432 | return switch (op) { |
| 2166 | 1433 | .eq => lhs.eql(rhs, ty, mod), |
| 2167 | 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 | 1458 | mod: *Module, |
| 2192 | 1459 | opt_sema: ?*Sema, |
| 2193 | 1460 | ) Module.CompileError!bool { |
| 2194 | if (lhs.isInf()) { | |
| 1461 | if (lhs.isInf(mod)) { | |
| 2195 | 1462 | switch (op) { |
| 2196 | 1463 | .neq => return true, |
| 2197 | 1464 | .eq => return false, |
| 2198 | .gt, .gte => return !lhs.isNegativeInf(), | |
| 2199 | .lt, .lte => return lhs.isNegativeInf(), | |
| 1465 | .gt, .gte => return !lhs.isNegativeInf(mod), | |
| 1466 | .lt, .lte => return lhs.isNegativeInf(mod), | |
| 2200 | 1467 | } |
| 2201 | 1468 | } |
| 2202 | 1469 | |
| 2203 | switch (lhs.tag()) { | |
| 2204 | .repeated => return lhs.castTag(.repeated).?.data.compareAllWithZeroAdvancedExtra(op, mod, opt_sema), | |
| 2205 | .aggregate => { | |
| 2206 | for (lhs.castTag(.aggregate).?.data) |elem_val| { | |
| 2207 | if (!(try elem_val.compareAllWithZeroAdvancedExtra(op, mod, opt_sema))) return false; | |
| 2208 | } | |
| 2209 | return true; | |
| 1470 | switch (mod.intern_pool.indexToKey(lhs.toIntern())) { | |
| 1471 | .float => |float| switch (float.storage) { | |
| 1472 | inline else => |x| if (std.math.isNan(x)) return op == .neq, | |
| 2210 | 1473 | }, |
| 2211 | .empty_array => return true, | |
| 2212 | .str_lit => { | |
| 2213 | const str_lit = lhs.castTag(.str_lit).?.data; | |
| 2214 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 2215 | for (bytes) |byte| { | |
| 2216 | if (!std.math.compare(byte, op, 0)) return false; | |
| 2217 | } | |
| 2218 | return true; | |
| 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; | |
| 1474 | .aggregate => |aggregate| return switch (aggregate.storage) { | |
| 1475 | .bytes => |bytes| for (bytes) |byte| { | |
| 1476 | if (!std.math.order(byte, 0).compare(op)) break false; | |
| 1477 | } else true, | |
| 1478 | .elems => |elems| for (elems) |elem| { | |
| 1479 | if (!try elem.toValue().compareAllWithZeroAdvancedExtra(op, mod, opt_sema)) break false; | |
| 1480 | } else true, | |
| 1481 | .repeated_elem => |elem| elem.toValue().compareAllWithZeroAdvancedExtra(op, mod, opt_sema), | |
| 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 | 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 | 1488 | pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { |
| ... | ... | @@ -2255,109 +1506,42 @@ pub const Value = extern union { |
| 2255 | 1506 | mod: *Module, |
| 2256 | 1507 | opt_sema: ?*Sema, |
| 2257 | 1508 | ) Module.CompileError!bool { |
| 1509 | if (a.ip_index != .none or b.ip_index != .none) return a.ip_index == b.ip_index; | |
| 1510 | ||
| 2258 | 1511 | const target = mod.getTarget(); |
| 2259 | 1512 | const a_tag = a.tag(); |
| 2260 | 1513 | const b_tag = b.tag(); |
| 2261 | 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 | 1515 | .aggregate => { |
| 2334 | 1516 | const a_field_vals = a.castTag(.aggregate).?.data; |
| 2335 | 1517 | const b_field_vals = b.castTag(.aggregate).?.data; |
| 2336 | 1518 | assert(a_field_vals.len == b_field_vals.len); |
| 2337 | 1519 | |
| 2338 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 2339 | const types = ty.tupleFields().types; | |
| 2340 | assert(types.len == a_field_vals.len); | |
| 2341 | for (types, 0..) |field_ty, i| { | |
| 2342 | if (!(try eqlAdvanced(a_field_vals[i], field_ty, b_field_vals[i], field_ty, mod, opt_sema))) { | |
| 2343 | return false; | |
| 1520 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 1521 | .anon_struct_type => |anon_struct| { | |
| 1522 | assert(anon_struct.types.len == a_field_vals.len); | |
| 1523 | for (anon_struct.types, 0..) |field_ty, i| { | |
| 1524 | if (!(try eqlAdvanced(a_field_vals[i], field_ty.toType(), b_field_vals[i], field_ty.toType(), mod, opt_sema))) { | |
| 1525 | return false; | |
| 1526 | } | |
| 2344 | 1527 | } |
| 2345 | } | |
| 2346 | return true; | |
| 2347 | } | |
| 2348 | ||
| 2349 | if (ty.zigTypeTag() == .Struct) { | |
| 2350 | const fields = ty.structFields().values(); | |
| 2351 | assert(fields.len == a_field_vals.len); | |
| 2352 | for (fields, 0..) |field, i| { | |
| 2353 | if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, opt_sema))) { | |
| 2354 | return false; | |
| 1528 | return true; | |
| 1529 | }, | |
| 1530 | .struct_type => |struct_type| { | |
| 1531 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 1532 | const fields = struct_obj.fields.values(); | |
| 1533 | assert(fields.len == a_field_vals.len); | |
| 1534 | for (fields, 0..) |field, i| { | |
| 1535 | if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, opt_sema))) { | |
| 1536 | return false; | |
| 1537 | } | |
| 2355 | 1538 | } |
| 2356 | } | |
| 2357 | return true; | |
| 1539 | return true; | |
| 1540 | }, | |
| 1541 | else => {}, | |
| 2358 | 1542 | } |
| 2359 | 1543 | |
| 2360 | const elem_ty = ty.childType(); | |
| 1544 | const elem_ty = ty.childType(mod); | |
| 2361 | 1545 | for (a_field_vals, 0..) |a_elem, i| { |
| 2362 | 1546 | const b_elem = b_field_vals[i]; |
| 2363 | 1547 | |
| ... | ... | @@ -2370,9 +1554,9 @@ pub const Value = extern union { |
| 2370 | 1554 | .@"union" => { |
| 2371 | 1555 | const a_union = a.castTag(.@"union").?.data; |
| 2372 | 1556 | const b_union = b.castTag(.@"union").?.data; |
| 2373 | switch (ty.containerLayout()) { | |
| 1557 | switch (ty.containerLayout(mod)) { | |
| 2374 | 1558 | .Packed, .Extern => { |
| 2375 | const tag_ty = ty.unionTagTypeHypothetical(); | |
| 1559 | const tag_ty = ty.unionTagTypeHypothetical(mod); | |
| 2376 | 1560 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) { |
| 2377 | 1561 | // In this case, we must disregard mismatching tags and compare |
| 2378 | 1562 | // based on the in-memory bytes of the payloads. |
| ... | ... | @@ -2380,7 +1564,7 @@ pub const Value = extern union { |
| 2380 | 1564 | } |
| 2381 | 1565 | }, |
| 2382 | 1566 | .Auto => { |
| 2383 | const tag_ty = ty.unionTagTypeHypothetical(); | |
| 1567 | const tag_ty = ty.unionTagTypeHypothetical(mod); | |
| 2384 | 1568 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) { |
| 2385 | 1569 | return false; |
| 2386 | 1570 | } |
| ... | ... | @@ -2390,122 +1574,91 @@ pub const Value = extern union { |
| 2390 | 1574 | return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, opt_sema); |
| 2391 | 1575 | }, |
| 2392 | 1576 | else => {}, |
| 2393 | } else if (b_tag == .null_value or b_tag == .@"error") { | |
| 2394 | return false; | |
| 2395 | } else if (a_tag == .undef or b_tag == .undef) { | |
| 2396 | return false; | |
| 2397 | } | |
| 1577 | }; | |
| 2398 | 1578 | |
| 2399 | if (a.pointerDecl()) |a_decl| { | |
| 2400 | if (b.pointerDecl()) |b_decl| { | |
| 1579 | if (a.pointerDecl(mod)) |a_decl| { | |
| 1580 | if (b.pointerDecl(mod)) |b_decl| { | |
| 2401 | 1581 | return a_decl == b_decl; |
| 2402 | 1582 | } else { |
| 2403 | 1583 | return false; |
| 2404 | 1584 | } |
| 2405 | } else if (b.pointerDecl()) |_| { | |
| 1585 | } else if (b.pointerDecl(mod)) |_| { | |
| 2406 | 1586 | return false; |
| 2407 | 1587 | } |
| 2408 | 1588 | |
| 2409 | switch (ty.zigTypeTag()) { | |
| 1589 | switch (ty.zigTypeTag(mod)) { | |
| 2410 | 1590 | .Type => { |
| 2411 | var buf_a: ToTypeBuffer = undefined; | |
| 2412 | var buf_b: ToTypeBuffer = undefined; | |
| 2413 | const a_type = a.toType(&buf_a); | |
| 2414 | const b_type = b.toType(&buf_b); | |
| 1591 | const a_type = a.toType(); | |
| 1592 | const b_type = b.toType(); | |
| 2415 | 1593 | return a_type.eql(b_type, mod); |
| 2416 | 1594 | }, |
| 2417 | 1595 | .Enum => { |
| 2418 | var buf_a: Payload.U64 = undefined; | |
| 2419 | var buf_b: Payload.U64 = undefined; | |
| 2420 | const a_val = a.enumToInt(ty, &buf_a); | |
| 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); | |
| 1596 | const a_val = try a.enumToInt(ty, mod); | |
| 1597 | const b_val = try b.enumToInt(ty, mod); | |
| 1598 | const int_ty = ty.intTagType(mod); | |
| 2424 | 1599 | return eqlAdvanced(a_val, int_ty, b_val, int_ty, mod, opt_sema); |
| 2425 | 1600 | }, |
| 2426 | 1601 | .Array, .Vector => { |
| 2427 | const len = ty.arrayLen(); | |
| 2428 | const elem_ty = ty.childType(); | |
| 1602 | const len = ty.arrayLen(mod); | |
| 1603 | const elem_ty = ty.childType(mod); | |
| 2429 | 1604 | var i: usize = 0; |
| 2430 | var a_buf: ElemValueBuffer = undefined; | |
| 2431 | var b_buf: ElemValueBuffer = undefined; | |
| 2432 | 1605 | while (i < len) : (i += 1) { |
| 2433 | const a_elem = elemValueBuffer(a, mod, i, &a_buf); | |
| 2434 | const b_elem = elemValueBuffer(b, mod, i, &b_buf); | |
| 1606 | const a_elem = try elemValue(a, mod, i); | |
| 1607 | const b_elem = try elemValue(b, mod, i); | |
| 2435 | 1608 | if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, opt_sema))) { |
| 2436 | 1609 | return false; |
| 2437 | 1610 | } |
| 2438 | 1611 | } |
| 2439 | 1612 | return true; |
| 2440 | 1613 | }, |
| 2441 | .Pointer => switch (ty.ptrSize()) { | |
| 1614 | .Pointer => switch (ty.ptrSize(mod)) { | |
| 2442 | 1615 | .Slice => { |
| 2443 | const a_len = switch (a_ty.ptrSize()) { | |
| 1616 | const a_len = switch (a_ty.ptrSize(mod)) { | |
| 2444 | 1617 | .Slice => a.sliceLen(mod), |
| 2445 | .One => a_ty.childType().arrayLen(), | |
| 1618 | .One => a_ty.childType(mod).arrayLen(mod), | |
| 2446 | 1619 | else => unreachable, |
| 2447 | 1620 | }; |
| 2448 | 1621 | if (a_len != b.sliceLen(mod)) { |
| 2449 | 1622 | return false; |
| 2450 | 1623 | } |
| 2451 | 1624 | |
| 2452 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 2453 | const ptr_ty = ty.slicePtrFieldType(&ptr_buf); | |
| 2454 | const a_ptr = switch (a_ty.ptrSize()) { | |
| 2455 | .Slice => a.slicePtr(), | |
| 1625 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 1626 | const a_ptr = switch (a_ty.ptrSize(mod)) { | |
| 1627 | .Slice => a.slicePtr(mod), | |
| 2456 | 1628 | .One => a, |
| 2457 | 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 | 1633 | .Many, .C, .One => {}, |
| 2462 | 1634 | }, |
| 2463 | 1635 | .Struct => { |
| 2464 | 1636 | // A struct can be represented with one of: |
| 2465 | // .empty_struct_value, | |
| 2466 | 1637 | // .the_one_possible_value, |
| 2467 | 1638 | // .aggregate, |
| 2468 | 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 | 1642 | .Union => { |
| 2472 | 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 | 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 | 1647 | return false; |
| 2495 | 1648 | }, |
| 2496 | 1649 | .Float => { |
| 2497 | 1650 | switch (ty.floatBits(target)) { |
| 2498 | 16 => return @bitCast(u16, a.toFloat(f16)) == @bitCast(u16, b.toFloat(f16)), | |
| 2499 | 32 => return @bitCast(u32, a.toFloat(f32)) == @bitCast(u32, b.toFloat(f32)), | |
| 2500 | 64 => return @bitCast(u64, a.toFloat(f64)) == @bitCast(u64, b.toFloat(f64)), | |
| 2501 | 80 => return @bitCast(u80, a.toFloat(f80)) == @bitCast(u80, b.toFloat(f80)), | |
| 2502 | 128 => return @bitCast(u128, a.toFloat(f128)) == @bitCast(u128, b.toFloat(f128)), | |
| 1651 | 16 => return @bitCast(u16, a.toFloat(f16, mod)) == @bitCast(u16, b.toFloat(f16, mod)), | |
| 1652 | 32 => return @bitCast(u32, a.toFloat(f32, mod)) == @bitCast(u32, b.toFloat(f32, mod)), | |
| 1653 | 64 => return @bitCast(u64, a.toFloat(f64, mod)) == @bitCast(u64, b.toFloat(f64, mod)), | |
| 1654 | 80 => return @bitCast(u80, a.toFloat(f80, mod)) == @bitCast(u80, b.toFloat(f80, mod)), | |
| 1655 | 128 => return @bitCast(u128, a.toFloat(f128, mod)) == @bitCast(u128, b.toFloat(f128, mod)), | |
| 2503 | 1656 | else => unreachable, |
| 2504 | 1657 | } |
| 2505 | 1658 | }, |
| 2506 | 1659 | .ComptimeFloat => { |
| 2507 | const a_float = a.toFloat(f128); | |
| 2508 | const b_float = b.toFloat(f128); | |
| 1660 | const a_float = a.toFloat(f128, mod); | |
| 1661 | const b_float = b.toFloat(f128, mod); | |
| 2509 | 1662 | |
| 2510 | 1663 | const a_nan = std.math.isNan(a_float); |
| 2511 | 1664 | const b_nan = std.math.isNan(b_float); |
| ... | ... | @@ -2514,570 +1667,215 @@ pub const Value = extern union { |
| 2514 | 1667 | if (a_nan) return true; |
| 2515 | 1668 | return a_float == b_float; |
| 2516 | 1669 | }, |
| 2517 | .Optional => if (a_tag != .null_value and b_tag == .opt_payload) { | |
| 2518 | var sub_pl: Payload.SubValue = .{ | |
| 2519 | .base = .{ .tag = b.tag() }, | |
| 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 | }, | |
| 1670 | .Optional, | |
| 1671 | .ErrorUnion, | |
| 1672 | => unreachable, // handled by InternPool | |
| 2533 | 1673 | else => {}, |
| 2534 | 1674 | } |
| 2535 | if (a_tag == .null_value or a_tag == .@"error") return false; | |
| 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 | } | |
| 1675 | return (try orderAdvanced(a, b, mod, opt_sema)).compare(.eq); | |
| 2683 | 1676 | } |
| 2684 | 1677 | |
| 2685 | /// This is a more conservative hash function that produces equal hashes for values | |
| 2686 | /// that can coerce into each other. | |
| 2687 | /// This function is used by hash maps and so treats floating-point NaNs as equal | |
| 2688 | /// to each other, and not equal to other floating-point values. | |
| 2689 | pub fn hashUncoerced(val: Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void { | |
| 2690 | if (val.isUndef()) return; | |
| 2691 | // The value is runtime-known and shouldn't affect the hash. | |
| 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); | |
| 1678 | pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool { | |
| 1679 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1680 | .ptr => |ptr| switch (ptr.addr) { | |
| 1681 | .mut_decl, .comptime_field => true, | |
| 1682 | .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isComptimeMutablePtr(mod), | |
| 1683 | .elem, .field => |base_index| base_index.base.toValue().isComptimeMutablePtr(mod), | |
| 1684 | else => false, | |
| 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 | 1686 | else => false, |
| 2786 | 1687 | }; |
| 2787 | 1688 | } |
| 2788 | 1689 | |
| 2789 | pub fn canMutateComptimeVarState(val: Value) bool { | |
| 2790 | if (val.isComptimeMutablePtr()) return true; | |
| 2791 | switch (val.tag()) { | |
| 2792 | .repeated => return val.castTag(.repeated).?.data.canMutateComptimeVarState(), | |
| 2793 | .eu_payload => return val.castTag(.eu_payload).?.data.canMutateComptimeVarState(), | |
| 2794 | .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(), | |
| 2795 | .opt_payload => return val.castTag(.opt_payload).?.data.canMutateComptimeVarState(), | |
| 2796 | .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(), | |
| 2797 | .aggregate => { | |
| 2798 | const fields = val.castTag(.aggregate).?.data; | |
| 2799 | for (fields) |field| { | |
| 2800 | if (field.canMutateComptimeVarState()) return true; | |
| 2801 | } | |
| 2802 | return false; | |
| 1690 | pub fn canMutateComptimeVarState(val: Value, mod: *Module) bool { | |
| 1691 | return val.isComptimeMutablePtr(mod) or switch (val.toIntern()) { | |
| 1692 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1693 | .error_union => |error_union| switch (error_union.val) { | |
| 1694 | .err_name => false, | |
| 1695 | .payload => |payload| payload.toValue().canMutateComptimeVarState(mod), | |
| 1696 | }, | |
| 1697 | .ptr => |ptr| switch (ptr.addr) { | |
| 1698 | .eu_payload, .opt_payload => |base| base.toValue().canMutateComptimeVarState(mod), | |
| 1699 | else => false, | |
| 1700 | }, | |
| 1701 | .opt => |opt| switch (opt.val) { | |
| 1702 | .none => 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(), | |
| 2805 | .slice => return val.castTag(.slice).?.data.ptr.canMutateComptimeVarState(), | |
| 2806 | else => return false, | |
| 2807 | } | |
| 1711 | }; | |
| 2808 | 1712 | } |
| 2809 | 1713 | |
| 2810 | 1714 | /// Gets the decl referenced by this pointer. If the pointer does not point |
| 2811 | 1715 | /// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr), |
| 2812 | 1716 | /// this function returns null. |
| 2813 | pub fn pointerDecl(val: Value) ?Module.Decl.Index { | |
| 2814 | return switch (val.tag()) { | |
| 2815 | .decl_ref_mut => val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 2816 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, | |
| 2817 | .function => val.castTag(.function).?.data.owner_decl, | |
| 2818 | .variable => val.castTag(.variable).?.data.owner_decl, | |
| 2819 | .decl_ref => val.cast(Payload.Decl).?.data, | |
| 1717 | pub fn pointerDecl(val: Value, mod: *Module) ?Module.Decl.Index { | |
| 1718 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1719 | .variable => |variable| variable.decl, | |
| 1720 | .extern_func => |extern_func| extern_func.decl, | |
| 1721 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 1722 | .ptr => |ptr| switch (ptr.addr) { | |
| 1723 | .decl => |decl| decl, | |
| 1724 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 1725 | else => null, | |
| 1726 | }, | |
| 2820 | 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 | 1732 | var buffer: BigIntSpace = undefined; |
| 2826 | const big = int_val.toBigInt(&buffer, target); | |
| 1733 | const big = int_val.toBigInt(&buffer, mod); | |
| 2827 | 1734 | std.hash.autoHash(hasher, big.positive); |
| 2828 | 1735 | for (big.limbs) |limb| { |
| 2829 | 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 { | |
| 2834 | switch (ptr_val.tag()) { | |
| 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), | |
| 1740 | pub const slice_ptr_index = 0; | |
| 1741 | pub const slice_len_index = 1; | |
| 2884 | 1742 | |
| 2885 | else => unreachable, | |
| 2886 | } | |
| 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 | }; | |
| 1743 | pub fn slicePtr(val: Value, mod: *Module) Value { | |
| 1744 | return mod.intern_pool.slicePtr(val.toIntern()).toValue(); | |
| 2896 | 1745 | } |
| 2897 | 1746 | |
| 2898 | 1747 | pub fn sliceLen(val: Value, mod: *Module) u64 { |
| 2899 | return switch (val.tag()) { | |
| 2900 | .slice => val.castTag(.slice).?.data.len.toUnsignedInt(mod.getTarget()), | |
| 2901 | .decl_ref => { | |
| 2902 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 2903 | const decl = mod.declPtr(decl_index); | |
| 2904 | if (decl.ty.zigTypeTag() == .Array) { | |
| 2905 | return decl.ty.arrayLen(); | |
| 2906 | } else { | |
| 2907 | return 1; | |
| 2908 | } | |
| 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 | } | |
| 1748 | const ptr = mod.intern_pool.indexToKey(val.toIntern()).ptr; | |
| 1749 | return switch (ptr.len) { | |
| 1750 | .none => switch (mod.intern_pool.indexToKey(switch (ptr.addr) { | |
| 1751 | .decl => |decl| mod.declPtr(decl).ty.toIntern(), | |
| 1752 | .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(), | |
| 1753 | .comptime_field => |comptime_field| mod.intern_pool.typeOf(comptime_field), | |
| 1754 | else => unreachable, | |
| 1755 | })) { | |
| 1756 | .array_type => |array_type| array_type.len, | |
| 1757 | else => 1, | |
| 2926 | 1758 | }, |
| 2927 | else => unreachable, | |
| 1759 | else => ptr.len.toValue().toUnsignedInt(mod), | |
| 2928 | 1760 | }; |
| 2929 | 1761 | } |
| 2930 | 1762 | |
| 2931 | 1763 | /// Asserts the value is a single-item pointer to an array, or an array, |
| 2932 | 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 { | |
| 2934 | return elemValueAdvanced(val, mod, index, arena, undefined); | |
| 2935 | } | |
| 2936 | ||
| 2937 | pub const ElemValueBuffer = Payload.U64; | |
| 2938 | ||
| 2939 | pub fn elemValueBuffer(val: Value, mod: *Module, index: usize, buffer: *ElemValueBuffer) Value { | |
| 2940 | return elemValueAdvanced(val, mod, index, null, buffer) catch 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); | |
| 1765 | pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value { | |
| 1766 | return switch (val.ip_index) { | |
| 1767 | .none => switch (val.tag()) { | |
| 1768 | .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]), | |
| 1769 | .repeated => val.castTag(.repeated).?.data, | |
| 1770 | .aggregate => val.castTag(.aggregate).?.data[index], | |
| 1771 | .slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index), | |
| 1772 | else => unreachable, | |
| 3000 | 1773 | }, |
| 3001 | .field_ptr => { | |
| 3002 | const data = val.castTag(.field_ptr).?.data; | |
| 3003 | if (data.container_ptr.pointerDecl()) |decl_index| { | |
| 3004 | const container_decl = mod.declPtr(decl_index); | |
| 3005 | const field_type = data.container_ty.structFieldType(data.field_index); | |
| 3006 | const field_val = container_decl.val.fieldValue(field_type, data.field_index); | |
| 3007 | return field_val.elemValueAdvanced(mod, index, arena, buffer); | |
| 3008 | } else unreachable; | |
| 1774 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1775 | .undef => |ty| (try mod.intern(.{ | |
| 1776 | .undef = ty.toType().elemType2(mod).toIntern(), | |
| 1777 | })).toValue(), | |
| 1778 | .ptr => |ptr| switch (ptr.addr) { | |
| 1779 | .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), | |
| 1780 | .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)) | |
| 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 | |
| 3012 | // to have only one possible value itself. | |
| 3013 | .the_only_possible_value => return val, | |
| 3014 | ||
| 3015 | .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), | |
| 3016 | .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), | |
| 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), | |
| 1811 | pub fn isLazyAlign(val: Value, mod: *Module) bool { | |
| 1812 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1813 | .int => |int| int.storage == .lazy_align, | |
| 1814 | else => false, | |
| 1815 | }; | |
| 1816 | } | |
| 3020 | 1817 | |
| 3021 | // These values will implicitly be treated as `repeated`. | |
| 3022 | .zero, | |
| 3023 | .one, | |
| 3024 | .bool_false, | |
| 3025 | .bool_true, | |
| 3026 | .int_i64, | |
| 3027 | .int_u64, | |
| 3028 | => return val, | |
| 1818 | pub fn isLazySize(val: Value, mod: *Module) bool { | |
| 1819 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1820 | .int => |int| int.storage == .lazy_size, | |
| 1821 | else => false, | |
| 1822 | }; | |
| 1823 | } | |
| 3029 | 1824 | |
| 3030 | else => unreachable, | |
| 3031 | } | |
| 1825 | pub fn isRuntimeValue(val: Value, mod: *Module) bool { | |
| 1826 | return mod.intern_pool.indexToKey(val.toIntern()) == .runtime_value; | |
| 3032 | 1827 | } |
| 3033 | 1828 | |
| 3034 | 1829 | /// Returns true if a Value is backed by a variable |
| 3035 | pub fn isVariable( | |
| 3036 | val: Value, | |
| 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 | ||
| 1830 | pub fn isVariable(val: Value, mod: *Module) bool { | |
| 1831 | return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 3057 | 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 | 1849 | else => false, |
| 3059 | 1850 | }; |
| 3060 | 1851 | } |
| 3061 | 1852 | |
| 3062 | 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 | 1855 | .variable => false, |
| 3065 | 1856 | else => val.isPtrToThreadLocalInner(mod), |
| 3066 | 1857 | }; |
| 3067 | 1858 | } |
| 3068 | 1859 | |
| 3069 | fn isPtrToThreadLocalInner(val: Value, mod: *Module) bool { | |
| 3070 | return switch (val.tag()) { | |
| 3071 | .slice => val.castTag(.slice).?.data.ptr.isPtrToThreadLocalInner(mod), | |
| 3072 | .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isPtrToThreadLocalInner(mod), | |
| 3073 | .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isPtrToThreadLocalInner(mod), | |
| 3074 | .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | |
| 3075 | .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | |
| 3076 | .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | |
| 3077 | .decl_ref => mod.declPtr(val.castTag(.decl_ref).?.data).val.isPtrToThreadLocalInner(mod), | |
| 3078 | .decl_ref_mut => mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.isPtrToThreadLocalInner(mod), | |
| 3079 | ||
| 3080 | .variable => val.castTag(.variable).?.data.is_threadlocal, | |
| 1860 | pub fn isPtrToThreadLocalInner(val: Value, mod: *Module) bool { | |
| 1861 | return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1862 | .variable => |variable| variable.is_threadlocal, | |
| 1863 | .ptr => |ptr| switch (ptr.addr) { | |
| 1864 | .decl => |decl_index| { | |
| 1865 | const decl = mod.declPtr(decl_index); | |
| 1866 | assert(decl.has_tv); | |
| 1867 | return decl.val.isPtrToThreadLocalInner(mod); | |
| 1868 | }, | |
| 1869 | .mut_decl => |mut_decl| { | |
| 1870 | const decl = mod.declPtr(mut_decl.decl); | |
| 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 | 1879 | else => false, |
| 3082 | 1880 | }; |
| 3083 | 1881 | } |
| ... | ... | @@ -3090,238 +1888,239 @@ pub const Value = extern union { |
| 3090 | 1888 | start: usize, |
| 3091 | 1889 | end: usize, |
| 3092 | 1890 | ) error{OutOfMemory}!Value { |
| 3093 | return switch (val.tag()) { | |
| 3094 | .empty_array_sentinel => if (start == 0 and end == 1) val else Value.initTag(.empty_array), | |
| 3095 | .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]), | |
| 3096 | .str_lit => { | |
| 3097 | const str_lit = val.castTag(.str_lit).?.data; | |
| 3098 | return Tag.str_lit.create(arena, .{ | |
| 3099 | .index = @intCast(u32, str_lit.index + start), | |
| 3100 | .len = @intCast(u32, end - start), | |
| 3101 | }); | |
| 1891 | // TODO: write something like getCoercedInts to avoid needing to dupe | |
| 1892 | return switch (val.ip_index) { | |
| 1893 | .none => switch (val.tag()) { | |
| 1894 | .slice => val.castTag(.slice).?.data.ptr.sliceArray(mod, arena, start, end), | |
| 1895 | .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]), | |
| 1896 | .repeated => val, | |
| 1897 | .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]), | |
| 1898 | else => unreachable, | |
| 3102 | 1899 | }, |
| 3103 | .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]), | |
| 3104 | .slice => sliceArray(val.castTag(.slice).?.data.ptr, mod, arena, start, end), | |
| 3105 | ||
| 3106 | .decl_ref => sliceArray(mod.declPtr(val.castTag(.decl_ref).?.data).val, mod, arena, start, end), | |
| 3107 | .decl_ref_mut => sliceArray(mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val, mod, arena, start, end), | |
| 3108 | .comptime_field_ptr => sliceArray(val.castTag(.comptime_field_ptr).?.data.field_val, mod, arena, start, end), | |
| 3109 | .elem_ptr => blk: { | |
| 3110 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 3111 | break :blk sliceArray(elem_ptr.array_ptr, mod, arena, start + elem_ptr.index, end + elem_ptr.index); | |
| 1900 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1901 | .ptr => |ptr| switch (ptr.addr) { | |
| 1902 | .decl => |decl| try mod.declPtr(decl).val.sliceArray(mod, arena, start, end), | |
| 1903 | .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)).toValue() | |
| 1904 | .sliceArray(mod, arena, start, end), | |
| 1905 | .comptime_field => |comptime_field| comptime_field.toValue() | |
| 1906 | .sliceArray(mod, arena, start, end), | |
| 1907 | .elem => |elem| elem.base.toValue() | |
| 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 { | |
| 3123 | switch (val.tag()) { | |
| 3124 | .aggregate => { | |
| 3125 | const field_values = val.castTag(.aggregate).?.data; | |
| 3126 | return field_values[index]; | |
| 1935 | pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value { | |
| 1936 | return switch (val.ip_index) { | |
| 1937 | .none => switch (val.tag()) { | |
| 1938 | .aggregate => { | |
| 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" => { | |
| 3129 | const payload = val.castTag(.@"union").?.data; | |
| 1949 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 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 | 1961 | // TODO assert the tag is correct |
| 3131 | return payload.val; | |
| 3132 | }, | |
| 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; | |
| 1962 | .un => |un| un.val.toValue(), | |
| 1963 | else => unreachable, | |
| 3145 | 1964 | }, |
| 3146 | .undef => return Value.undef, | |
| 3147 | ||
| 3148 | else => unreachable, | |
| 3149 | } | |
| 1965 | }; | |
| 3150 | 1966 | } |
| 3151 | 1967 | |
| 3152 | pub fn unionTag(val: Value) Value { | |
| 3153 | switch (val.tag()) { | |
| 3154 | .undef, .enum_field_index => return val, | |
| 3155 | .@"union" => return val.castTag(.@"union").?.data.tag, | |
| 1968 | pub fn unionTag(val: Value, mod: *Module) Value { | |
| 1969 | if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag; | |
| 1970 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1971 | .undef, .enum_tag => val, | |
| 1972 | .un => |un| un.tag.toValue(), | |
| 3156 | 1973 | else => unreachable, |
| 3157 | } | |
| 1974 | }; | |
| 3158 | 1975 | } |
| 3159 | 1976 | |
| 3160 | 1977 | /// Returns a pointer to the element value at the index. |
| 3161 | 1978 | pub fn elemPtr( |
| 3162 | 1979 | val: Value, |
| 3163 | ty: Type, | |
| 3164 | arena: Allocator, | |
| 1980 | elem_ptr_ty: Type, | |
| 3165 | 1981 | index: usize, |
| 3166 | 1982 | mod: *Module, |
| 3167 | 1983 | ) Allocator.Error!Value { |
| 3168 | const elem_ty = ty.elemType2(); | |
| 3169 | const ptr_val = switch (val.tag()) { | |
| 3170 | .slice => val.castTag(.slice).?.data.ptr, | |
| 1984 | const elem_ty = elem_ptr_ty.childType(mod); | |
| 1985 | const ptr_val = switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 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 | 2003 | else => val, |
| 3172 | 2004 | }; |
| 3173 | ||
| 3174 | if (ptr_val.tag() == .elem_ptr) { | |
| 3175 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 3176 | if (elem_ptr.elem_ty.eql(elem_ty, mod)) { | |
| 3177 | return Tag.elem_ptr.create(arena, .{ | |
| 3178 | .array_ptr = elem_ptr.array_ptr, | |
| 3179 | .elem_ty = elem_ptr.elem_ty, | |
| 3180 | .index = elem_ptr.index + index, | |
| 3181 | }); | |
| 3182 | } | |
| 3183 | } | |
| 3184 | return Tag.elem_ptr.create(arena, .{ | |
| 3185 | .array_ptr = ptr_val, | |
| 3186 | .elem_ty = elem_ty, | |
| 3187 | .index = index, | |
| 3188 | }); | |
| 3189 | } | |
| 3190 | ||
| 3191 | pub fn isUndef(self: Value) bool { | |
| 3192 | return self.tag() == .undef; | |
| 2005 | var ptr_ty_key = mod.intern_pool.indexToKey(elem_ptr_ty.toIntern()).ptr_type; | |
| 2006 | assert(ptr_ty_key.flags.size != .Slice); | |
| 2007 | ptr_ty_key.flags.size = .Many; | |
| 2008 | return (try mod.intern(.{ .ptr = .{ | |
| 2009 | .ty = elem_ptr_ty.toIntern(), | |
| 2010 | .addr = .{ .elem = .{ | |
| 2011 | .base = (try mod.getCoerced(ptr_val, try mod.ptrType(ptr_ty_key))).toIntern(), | |
| 2012 | .index = index, | |
| 2013 | } }, | |
| 2014 | } })).toValue(); | |
| 2015 | } | |
| 2016 | ||
| 2017 | pub fn isUndef(val: Value, mod: *Module) bool { | |
| 2018 | if (val.ip_index == .none) return false; | |
| 2019 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2020 | .undef => true, | |
| 2021 | .simple_value => |v| v == .undefined, | |
| 2022 | else => false, | |
| 2023 | }; | |
| 3193 | 2024 | } |
| 3194 | 2025 | |
| 3195 | 2026 | /// TODO: check for cases such as array that is not marked undef but all the element |
| 3196 | 2027 | /// values are marked undef, or struct that is not marked undef but all fields are marked |
| 3197 | 2028 | /// undef, etc. |
| 3198 | pub fn isUndefDeep(self: Value) bool { | |
| 3199 | return self.isUndef(); | |
| 2029 | pub fn isUndefDeep(val: Value, mod: *Module) bool { | |
| 2030 | return val.isUndef(mod); | |
| 3200 | 2031 | } |
| 3201 | 2032 | |
| 3202 | 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 | |
| 3204 | /// values are marked undef, or struct that is not marked undef but all fields are marked | |
| 3205 | /// undef, etc. | |
| 3206 | pub fn anyUndef(self: Value, mod: *Module) bool { | |
| 3207 | switch (self.tag()) { | |
| 3208 | .slice => { | |
| 3209 | const payload = self.castTag(.slice).?; | |
| 3210 | const len = payload.data.len.toUnsignedInt(mod.getTarget()); | |
| 3211 | ||
| 3212 | var elem_value_buf: ElemValueBuffer = undefined; | |
| 3213 | var i: usize = 0; | |
| 3214 | while (i < len) : (i += 1) { | |
| 3215 | const elem_val = payload.data.ptr.elemValueBuffer(mod, i, &elem_value_buf); | |
| 3216 | if (elem_val.anyUndef(mod)) return true; | |
| 3217 | } | |
| 3218 | }, | |
| 3219 | ||
| 3220 | .aggregate => { | |
| 3221 | const payload = self.castTag(.aggregate).?; | |
| 3222 | for (payload.data) |val| { | |
| 3223 | if (val.anyUndef(mod)) return true; | |
| 3224 | } | |
| 2034 | pub fn anyUndef(val: Value, mod: *Module) !bool { | |
| 2035 | if (val.ip_index == .none) return false; | |
| 2036 | return switch (val.toIntern()) { | |
| 2037 | .undef => true, | |
| 2038 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2039 | .undef => true, | |
| 2040 | .simple_value => |v| v == .undefined, | |
| 2041 | .ptr => |ptr| switch (ptr.len) { | |
| 2042 | .none => false, | |
| 2043 | else => for (0..@intCast(usize, ptr.len.toValue().toUnsignedInt(mod))) |index| { | |
| 2044 | if (try (try val.elemValue(mod, index)).anyUndef(mod)) break true; | |
| 2045 | } else false, | |
| 2046 | }, | |
| 2047 | .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { | |
| 2048 | const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; | |
| 2049 | if (try anyUndef(elem.toValue(), mod)) break true; | |
| 2050 | } else false, | |
| 2051 | else => false, | |
| 3225 | 2052 | }, |
| 3226 | ||
| 3227 | .undef => return true, | |
| 3228 | else => {}, | |
| 3229 | } | |
| 3230 | ||
| 3231 | return false; | |
| 2053 | }; | |
| 3232 | 2054 | } |
| 3233 | 2055 | |
| 3234 | 2056 | /// Asserts the value is not undefined and not unreachable. |
| 3235 | /// Integer value 0 is considered null because of C pointers. | |
| 3236 | pub fn isNull(self: Value) bool { | |
| 3237 | return switch (self.tag()) { | |
| 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 | ||
| 2057 | /// C pointers with an integer value of 0 are also considered null. | |
| 2058 | pub fn isNull(val: Value, mod: *Module) bool { | |
| 2059 | return switch (val.toIntern()) { | |
| 3259 | 2060 | .undef => unreachable, |
| 3260 | 2061 | .unreachable_value => unreachable, |
| 3261 | .inferred_alloc => unreachable, | |
| 3262 | .inferred_alloc_comptime => unreachable, | |
| 3263 | ||
| 3264 | else => false, | |
| 2062 | .null_value => true, | |
| 2063 | else => return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2064 | .undef => unreachable, | |
| 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 | |
| 3269 | /// unreachable. For error unions, prefer `errorUnionIsPayload` to find out whether | |
| 3270 | /// something is an error or not because it works without having to figure out the | |
| 3271 | /// string. | |
| 3272 | pub fn getError(self: Value) ?[]const u8 { | |
| 3273 | return switch (self.tag()) { | |
| 3274 | .@"error" => self.castTag(.@"error").?.data.name, | |
| 3275 | .int_u64 => @panic("TODO"), | |
| 3276 | .int_i64 => @panic("TODO"), | |
| 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, | |
| 2078 | /// Valid only for error (union) types. Asserts the value is not undefined and not unreachable. | |
| 2079 | pub fn getErrorName(val: Value, mod: *const Module) InternPool.OptionalNullTerminatedString { | |
| 2080 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2081 | .err => |err| err.name.toOptional(), | |
| 2082 | .error_union => |error_union| switch (error_union.val) { | |
| 2083 | .err_name => |err_name| err_name.toOptional(), | |
| 2084 | .payload => .none, | |
| 2085 | }, | |
| 2086 | else => unreachable, | |
| 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 | 2097 | /// Assumes the type is an error union. Returns true if and only if the value is |
| 3290 | 2098 | /// the error union payload, not an error. |
| 3291 | pub fn errorUnionIsPayload(val: Value) bool { | |
| 3292 | return switch (val.tag()) { | |
| 3293 | .eu_payload => true, | |
| 3294 | else => false, | |
| 3295 | ||
| 3296 | .undef => unreachable, | |
| 3297 | .inferred_alloc => unreachable, | |
| 3298 | .inferred_alloc_comptime => unreachable, | |
| 3299 | }; | |
| 2099 | pub fn errorUnionIsPayload(val: Value, mod: *const Module) bool { | |
| 2100 | return mod.intern_pool.indexToKey(val.toIntern()).error_union.val == .payload; | |
| 3300 | 2101 | } |
| 3301 | 2102 | |
| 3302 | 2103 | /// Value of the optional, null if optional has no payload. |
| 3303 | pub fn optionalValue(val: Value) ?Value { | |
| 3304 | if (val.isNull()) return null; | |
| 3305 | ||
| 3306 | // Valid for optional representation to be the direct value | |
| 3307 | // and not use opt_payload. | |
| 3308 | return if (val.castTag(.opt_payload)) |p| p.data else val; | |
| 2104 | pub fn optionalValue(val: Value, mod: *const Module) ?Value { | |
| 2105 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2106 | .opt => |opt| switch (opt.val) { | |
| 2107 | .none => null, | |
| 2108 | else => |payload| payload.toValue(), | |
| 2109 | }, | |
| 2110 | .ptr => val, | |
| 2111 | else => unreachable, | |
| 2112 | }; | |
| 3309 | 2113 | } |
| 3310 | 2114 | |
| 3311 | 2115 | /// Valid for all types. Asserts the value is not undefined. |
| 3312 | pub fn isFloat(self: Value) bool { | |
| 3313 | return switch (self.tag()) { | |
| 2116 | pub fn isFloat(self: Value, mod: *const Module) bool { | |
| 2117 | return switch (self.toIntern()) { | |
| 3314 | 2118 | .undef => unreachable, |
| 3315 | .inferred_alloc => unreachable, | |
| 3316 | .inferred_alloc_comptime => unreachable, | |
| 3317 | ||
| 3318 | .float_16, | |
| 3319 | .float_32, | |
| 3320 | .float_64, | |
| 3321 | .float_80, | |
| 3322 | .float_128, | |
| 3323 | => true, | |
| 3324 | else => false, | |
| 2119 | else => switch (mod.intern_pool.indexToKey(self.toIntern())) { | |
| 2120 | .undef => unreachable, | |
| 2121 | .float => true, | |
| 2122 | else => false, | |
| 2123 | }, | |
| 3325 | 2124 | }; |
| 3326 | 2125 | } |
| 3327 | 2126 | |
| ... | ... | @@ -3333,79 +2132,59 @@ pub const Value = extern union { |
| 3333 | 2132 | } |
| 3334 | 2133 | |
| 3335 | 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(); | |
| 3337 | if (int_ty.zigTypeTag() == .Vector) { | |
| 3338 | const result_data = try arena.alloc(Value, int_ty.vectorLen()); | |
| 2135 | if (int_ty.zigTypeTag(mod) == .Vector) { | |
| 2136 | const result_data = try arena.alloc(InternPool.Index, int_ty.vectorLen(mod)); | |
| 2137 | const scalar_ty = float_ty.scalarType(mod); | |
| 3339 | 2138 | for (result_data, 0..) |*scalar, i| { |
| 3340 | var buf: Value.ElemValueBuffer = undefined; | |
| 3341 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 3342 | scalar.* = try intToFloatScalar(elem_val, arena, float_ty.scalarType(), target, opt_sema); | |
| 2139 | const elem_val = try val.elemValue(mod, i); | |
| 2140 | scalar.* = try (try intToFloatScalar(elem_val, scalar_ty, mod, opt_sema)).intern(scalar_ty, mod); | |
| 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 { | |
| 3350 | switch (val.tag()) { | |
| 3351 | .undef, .zero, .one => return val, | |
| 3352 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 | |
| 3353 | .int_u64 => { | |
| 3354 | return intToFloatInner(val.castTag(.int_u64).?.data, arena, float_ty, target); | |
| 3355 | }, | |
| 3356 | .int_i64 => { | |
| 3357 | return intToFloatInner(val.castTag(.int_i64).?.data, arena, float_ty, target); | |
| 3358 | }, | |
| 3359 | .int_big_positive => { | |
| 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); | |
| 2150 | pub fn intToFloatScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { | |
| 2151 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2152 | .undef => (try mod.intern(.{ .undef = float_ty.toIntern() })).toValue(), | |
| 2153 | .int => |int| switch (int.storage) { | |
| 2154 | .big_int => |big_int| { | |
| 2155 | const float = bigIntToFloat(big_int.limbs, big_int.positive); | |
| 2156 | return mod.floatValue(float_ty, float); | |
| 2157 | }, | |
| 2158 | inline .u64, .i64 => |x| intToFloatInner(x, float_ty, mod), | |
| 2159 | .lazy_align => |ty| if (opt_sema) |sema| { | |
| 2160 | return intToFloatInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); | |
| 3373 | 2161 | } else { |
| 3374 | return intToFloatInner(ty.abiAlignment(target), arena, float_ty, target); | |
| 3375 | } | |
| 3376 | }, | |
| 3377 | .lazy_size => { | |
| 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); | |
| 2162 | return intToFloatInner(ty.toType().abiAlignment(mod), float_ty, mod); | |
| 2163 | }, | |
| 2164 | .lazy_size => |ty| if (opt_sema) |sema| { | |
| 2165 | return intToFloatInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); | |
| 3381 | 2166 | } else { |
| 3382 | return intToFloatInner(ty.abiSize(target), arena, float_ty, target); | |
| 3383 | } | |
| 2167 | return intToFloatInner(ty.toType().abiSize(mod), float_ty, mod); | |
| 2168 | }, | |
| 3384 | 2169 | }, |
| 3385 | 2170 | else => unreachable, |
| 3386 | } | |
| 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 | } | |
| 2171 | }; | |
| 3398 | 2172 | } |
| 3399 | 2173 | |
| 3400 | pub fn floatToValue(float: f128, arena: Allocator, dest_ty: Type, target: Target) !Value { | |
| 3401 | switch (dest_ty.floatBits(target)) { | |
| 3402 | 16 => return Value.Tag.float_16.create(arena, @floatCast(f16, float)), | |
| 3403 | 32 => return Value.Tag.float_32.create(arena, @floatCast(f32, float)), | |
| 3404 | 64 => return Value.Tag.float_64.create(arena, @floatCast(f64, float)), | |
| 3405 | 80 => return Value.Tag.float_80.create(arena, @floatCast(f80, float)), | |
| 3406 | 128 => return Value.Tag.float_128.create(arena, float), | |
| 2174 | fn intToFloatInner(x: anytype, dest_ty: Type, mod: *Module) !Value { | |
| 2175 | const target = mod.getTarget(); | |
| 2176 | const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) { | |
| 2177 | 16 => .{ .f16 = @intToFloat(f16, x) }, | |
| 2178 | 32 => .{ .f32 = @intToFloat(f32, x) }, | |
| 2179 | 64 => .{ .f64 = @intToFloat(f64, x) }, | |
| 2180 | 80 => .{ .f80 = @intToFloat(f80, x) }, | |
| 2181 | 128 => .{ .f128 = @intToFloat(f128, x) }, | |
| 3407 | 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 | 2190 | fn calcLimbLenFloat(scalar: anytype) usize { |
| ... | ... | @@ -3422,22 +2201,6 @@ pub const Value = extern union { |
| 3422 | 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 | 2204 | /// Supports (vectors of) integers only; asserts neither operand is undefined. |
| 3442 | 2205 | pub fn intAddSat( |
| 3443 | 2206 | lhs: Value, |
| ... | ... | @@ -3446,19 +2209,20 @@ pub const Value = extern union { |
| 3446 | 2209 | arena: Allocator, |
| 3447 | 2210 | mod: *Module, |
| 3448 | 2211 | ) !Value { |
| 3449 | const target = mod.getTarget(); | |
| 3450 | if (ty.zigTypeTag() == .Vector) { | |
| 3451 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 2212 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2213 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2214 | const scalar_ty = ty.scalarType(mod); | |
| 3452 | 2215 | for (result_data, 0..) |*scalar, i| { |
| 3453 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3454 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3455 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3456 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3457 | scalar.* = try intAddSatScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | |
| 2216 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2217 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2218 | scalar.* = try (try intAddSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); | |
| 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 | 2228 | /// Supports integers only; asserts neither operand is undefined. |
| ... | ... | @@ -3467,24 +2231,24 @@ pub const Value = extern union { |
| 3467 | 2231 | rhs: Value, |
| 3468 | 2232 | ty: Type, |
| 3469 | 2233 | arena: Allocator, |
| 3470 | target: Target, | |
| 2234 | mod: *Module, | |
| 3471 | 2235 | ) !Value { |
| 3472 | assert(!lhs.isUndef()); | |
| 3473 | assert(!rhs.isUndef()); | |
| 2236 | assert(!lhs.isUndef(mod)); | |
| 2237 | assert(!rhs.isUndef(mod)); | |
| 3474 | 2238 | |
| 3475 | const info = ty.intInfo(target); | |
| 2239 | const info = ty.intInfo(mod); | |
| 3476 | 2240 | |
| 3477 | 2241 | var lhs_space: Value.BigIntSpace = undefined; |
| 3478 | 2242 | var rhs_space: Value.BigIntSpace = undefined; |
| 3479 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3480 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2243 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2244 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3481 | 2245 | const limbs = try arena.alloc( |
| 3482 | 2246 | std.math.big.Limb, |
| 3483 | 2247 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 3484 | 2248 | ); |
| 3485 | 2249 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3486 | 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 | 2254 | /// Supports (vectors of) integers only; asserts neither operand is undefined. |
| ... | ... | @@ -3495,19 +2259,20 @@ pub const Value = extern union { |
| 3495 | 2259 | arena: Allocator, |
| 3496 | 2260 | mod: *Module, |
| 3497 | 2261 | ) !Value { |
| 3498 | const target = mod.getTarget(); | |
| 3499 | if (ty.zigTypeTag() == .Vector) { | |
| 3500 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 2262 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2263 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2264 | const scalar_ty = ty.scalarType(mod); | |
| 3501 | 2265 | for (result_data, 0..) |*scalar, i| { |
| 3502 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3503 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3504 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3505 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3506 | scalar.* = try intSubSatScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | |
| 2266 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2267 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2268 | scalar.* = try (try intSubSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); | |
| 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 | 2278 | /// Supports integers only; asserts neither operand is undefined. |
| ... | ... | @@ -3516,24 +2281,24 @@ pub const Value = extern union { |
| 3516 | 2281 | rhs: Value, |
| 3517 | 2282 | ty: Type, |
| 3518 | 2283 | arena: Allocator, |
| 3519 | target: Target, | |
| 2284 | mod: *Module, | |
| 3520 | 2285 | ) !Value { |
| 3521 | assert(!lhs.isUndef()); | |
| 3522 | assert(!rhs.isUndef()); | |
| 2286 | assert(!lhs.isUndef(mod)); | |
| 2287 | assert(!rhs.isUndef(mod)); | |
| 3523 | 2288 | |
| 3524 | const info = ty.intInfo(target); | |
| 2289 | const info = ty.intInfo(mod); | |
| 3525 | 2290 | |
| 3526 | 2291 | var lhs_space: Value.BigIntSpace = undefined; |
| 3527 | 2292 | var rhs_space: Value.BigIntSpace = undefined; |
| 3528 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3529 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2293 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2294 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3530 | 2295 | const limbs = try arena.alloc( |
| 3531 | 2296 | std.math.big.Limb, |
| 3532 | 2297 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 3533 | 2298 | ); |
| 3534 | 2299 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3535 | 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 | 2304 | pub fn intMulWithOverflow( |
| ... | ... | @@ -3543,25 +2308,30 @@ pub const Value = extern union { |
| 3543 | 2308 | arena: Allocator, |
| 3544 | 2309 | mod: *Module, |
| 3545 | 2310 | ) !OverflowArithmeticResult { |
| 3546 | const target = mod.getTarget(); | |
| 3547 | if (ty.zigTypeTag() == .Vector) { | |
| 3548 | const overflowed_data = try arena.alloc(Value, ty.vectorLen()); | |
| 3549 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 3550 | for (result_data, 0..) |*scalar, i| { | |
| 3551 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3552 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3553 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3554 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3555 | const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | |
| 3556 | overflowed_data[i] = of_math_result.overflow_bit; | |
| 3557 | scalar.* = of_math_result.wrapped_result; | |
| 2311 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2312 | const vec_len = ty.vectorLen(mod); | |
| 2313 | const overflowed_data = try arena.alloc(InternPool.Index, vec_len); | |
| 2314 | const result_data = try arena.alloc(InternPool.Index, vec_len); | |
| 2315 | const scalar_ty = ty.scalarType(mod); | |
| 2316 | for (overflowed_data, result_data, 0..) |*of, *scalar, i| { | |
| 2317 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2318 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2319 | const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod); | |
| 2320 | of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); | |
| 2321 | scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); | |
| 3558 | 2322 | } |
| 3559 | 2323 | return OverflowArithmeticResult{ |
| 3560 | .overflow_bit = try Value.Tag.aggregate.create(arena, overflowed_data), | |
| 3561 | .wrapped_result = try Value.Tag.aggregate.create(arena, result_data), | |
| 2324 | .overflow_bit = (try mod.intern(.{ .aggregate = .{ | |
| 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 | 2337 | pub fn intMulWithOverflowScalar( |
| ... | ... | @@ -3569,14 +2339,14 @@ pub const Value = extern union { |
| 3569 | 2339 | rhs: Value, |
| 3570 | 2340 | ty: Type, |
| 3571 | 2341 | arena: Allocator, |
| 3572 | target: Target, | |
| 2342 | mod: *Module, | |
| 3573 | 2343 | ) !OverflowArithmeticResult { |
| 3574 | const info = ty.intInfo(target); | |
| 2344 | const info = ty.intInfo(mod); | |
| 3575 | 2345 | |
| 3576 | 2346 | var lhs_space: Value.BigIntSpace = undefined; |
| 3577 | 2347 | var rhs_space: Value.BigIntSpace = undefined; |
| 3578 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3579 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2348 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2349 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3580 | 2350 | const limbs = try arena.alloc( |
| 3581 | 2351 | std.math.big.Limb, |
| 3582 | 2352 | lhs_bigint.limbs.len + rhs_bigint.limbs.len, |
| ... | ... | @@ -3594,8 +2364,8 @@ pub const Value = extern union { |
| 3594 | 2364 | } |
| 3595 | 2365 | |
| 3596 | 2366 | return OverflowArithmeticResult{ |
| 3597 | .overflow_bit = boolToInt(overflowed), | |
| 3598 | .wrapped_result = try fromBigInt(arena, result_bigint.toConst()), | |
| 2367 | .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), | |
| 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 | 2377 | arena: Allocator, |
| 3608 | 2378 | mod: *Module, |
| 3609 | 2379 | ) !Value { |
| 3610 | if (ty.zigTypeTag() == .Vector) { | |
| 3611 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 2380 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2381 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2382 | const scalar_ty = ty.scalarType(mod); | |
| 3612 | 2383 | for (result_data, 0..) |*scalar, i| { |
| 3613 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3614 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3615 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3616 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3617 | scalar.* = try numberMulWrapScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, mod); | |
| 2384 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2385 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2386 | scalar.* = try (try numberMulWrapScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, 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 | 2393 | return numberMulWrapScalar(lhs, rhs, ty, arena, mod); |
| 3622 | 2394 | } |
| ... | ... | @@ -3629,10 +2401,10 @@ pub const Value = extern union { |
| 3629 | 2401 | arena: Allocator, |
| 3630 | 2402 | mod: *Module, |
| 3631 | 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) { | |
| 3635 | return intMul(lhs, rhs, ty, arena, mod); | |
| 2406 | if (ty.zigTypeTag(mod) == .ComptimeInt) { | |
| 2407 | return intMul(lhs, rhs, ty, undefined, arena, mod); | |
| 3636 | 2408 | } |
| 3637 | 2409 | |
| 3638 | 2410 | if (ty.isAnyFloat()) { |
| ... | ... | @@ -3651,19 +2423,20 @@ pub const Value = extern union { |
| 3651 | 2423 | arena: Allocator, |
| 3652 | 2424 | mod: *Module, |
| 3653 | 2425 | ) !Value { |
| 3654 | const target = mod.getTarget(); | |
| 3655 | if (ty.zigTypeTag() == .Vector) { | |
| 3656 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 2426 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2427 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2428 | const scalar_ty = ty.scalarType(mod); | |
| 3657 | 2429 | for (result_data, 0..) |*scalar, i| { |
| 3658 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3659 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3660 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3661 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3662 | scalar.* = try intMulSatScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | |
| 2430 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2431 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2432 | scalar.* = try (try intMulSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); | |
| 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 | 2442 | /// Supports (vectors of) integers only; asserts neither operand is undefined. |
| ... | ... | @@ -3672,17 +2445,17 @@ pub const Value = extern union { |
| 3672 | 2445 | rhs: Value, |
| 3673 | 2446 | ty: Type, |
| 3674 | 2447 | arena: Allocator, |
| 3675 | target: Target, | |
| 2448 | mod: *Module, | |
| 3676 | 2449 | ) !Value { |
| 3677 | assert(!lhs.isUndef()); | |
| 3678 | assert(!rhs.isUndef()); | |
| 2450 | assert(!lhs.isUndef(mod)); | |
| 2451 | assert(!rhs.isUndef(mod)); | |
| 3679 | 2452 | |
| 3680 | const info = ty.intInfo(target); | |
| 2453 | const info = ty.intInfo(mod); | |
| 3681 | 2454 | |
| 3682 | 2455 | var lhs_space: Value.BigIntSpace = undefined; |
| 3683 | 2456 | var rhs_space: Value.BigIntSpace = undefined; |
| 3684 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3685 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2457 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2458 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3686 | 2459 | const limbs = try arena.alloc( |
| 3687 | 2460 | std.math.big.Limb, |
| 3688 | 2461 | std.math.max( |
| ... | ... | @@ -3698,28 +2471,28 @@ pub const Value = extern union { |
| 3698 | 2471 | ); |
| 3699 | 2472 | result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena); |
| 3700 | 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 | 2477 | /// Supports both floats and ints; handles undefined. |
| 3705 | pub fn numberMax(lhs: Value, rhs: Value, target: Target) Value { | |
| 3706 | if (lhs.isUndef() or rhs.isUndef()) return undef; | |
| 3707 | if (lhs.isNan()) return rhs; | |
| 3708 | if (rhs.isNan()) return lhs; | |
| 2478 | pub fn numberMax(lhs: Value, rhs: Value, mod: *Module) Value { | |
| 2479 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return undef; | |
| 2480 | if (lhs.isNan(mod)) return rhs; | |
| 2481 | if (rhs.isNan(mod)) return lhs; | |
| 3709 | 2482 | |
| 3710 | return switch (order(lhs, rhs, target)) { | |
| 2483 | return switch (order(lhs, rhs, mod)) { | |
| 3711 | 2484 | .lt => rhs, |
| 3712 | 2485 | .gt, .eq => lhs, |
| 3713 | 2486 | }; |
| 3714 | 2487 | } |
| 3715 | 2488 | |
| 3716 | 2489 | /// Supports both floats and ints; handles undefined. |
| 3717 | pub fn numberMin(lhs: Value, rhs: Value, target: Target) Value { | |
| 3718 | if (lhs.isUndef() or rhs.isUndef()) return undef; | |
| 3719 | if (lhs.isNan()) return rhs; | |
| 3720 | if (rhs.isNan()) return lhs; | |
| 2490 | pub fn numberMin(lhs: Value, rhs: Value, mod: *Module) Value { | |
| 2491 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return undef; | |
| 2492 | if (lhs.isNan(mod)) return rhs; | |
| 2493 | if (rhs.isNan(mod)) return lhs; | |
| 3721 | 2494 | |
| 3722 | return switch (order(lhs, rhs, target)) { | |
| 2495 | return switch (order(lhs, rhs, mod)) { | |
| 3723 | 2496 | .lt => lhs, |
| 3724 | 2497 | .gt, .eq => rhs, |
| 3725 | 2498 | }; |
| ... | ... | @@ -3727,24 +2500,27 @@ pub const Value = extern union { |
| 3727 | 2500 | |
| 3728 | 2501 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3729 | 2502 | pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3730 | const target = mod.getTarget(); | |
| 3731 | if (ty.zigTypeTag() == .Vector) { | |
| 3732 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 2503 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2504 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2505 | const scalar_ty = ty.scalarType(mod); | |
| 3733 | 2506 | for (result_data, 0..) |*scalar, i| { |
| 3734 | var buf: Value.ElemValueBuffer = undefined; | |
| 3735 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 3736 | scalar.* = try bitwiseNotScalar(elem_val, ty.scalarType(), arena, target); | |
| 2507 | const elem_val = try val.elemValue(mod, i); | |
| 2508 | scalar.* = try (try bitwiseNotScalar(elem_val, scalar_ty, arena, mod)).intern(scalar_ty, mod); | |
| 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 | 2518 | /// operands must be integers; handles undefined. |
| 3744 | pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, target: Target) !Value { | |
| 3745 | if (val.isUndef()) return Value.initTag(.undef); | |
| 2519 | pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | |
| 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 | 2525 | if (info.bits == 0) { |
| 3750 | 2526 | return val; |
| ... | ... | @@ -3753,7 +2529,7 @@ pub const Value = extern union { |
| 3753 | 2529 | // TODO is this a performance issue? maybe we should try the operation without |
| 3754 | 2530 | // resorting to BigInt first. |
| 3755 | 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 | 2533 | const limbs = try arena.alloc( |
| 3758 | 2534 | std.math.big.Limb, |
| 3759 | 2535 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| ... | ... | @@ -3761,36 +2537,38 @@ pub const Value = extern union { |
| 3761 | 2537 | |
| 3762 | 2538 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3763 | 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 | 2543 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3768 | 2544 | pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3769 | const target = mod.getTarget(); | |
| 3770 | if (ty.zigTypeTag() == .Vector) { | |
| 3771 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 2545 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2546 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2547 | const scalar_ty = ty.scalarType(mod); | |
| 3772 | 2548 | for (result_data, 0..) |*scalar, i| { |
| 3773 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3774 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3775 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3776 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3777 | scalar.* = try bitwiseAndScalar(lhs_elem, rhs_elem, allocator, target); | |
| 2549 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2550 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2551 | scalar.* = try (try bitwiseAndScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); | |
| 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 | 2561 | /// operands must be integers; handles undefined. |
| 3785 | pub fn bitwiseAndScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { | |
| 3786 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 2562 | pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | |
| 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 | 2566 | // TODO is this a performance issue? maybe we should try the operation without |
| 3789 | 2567 | // resorting to BigInt first. |
| 3790 | 2568 | var lhs_space: Value.BigIntSpace = undefined; |
| 3791 | 2569 | var rhs_space: Value.BigIntSpace = undefined; |
| 3792 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3793 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2570 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2571 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3794 | 2572 | const limbs = try arena.alloc( |
| 3795 | 2573 | std.math.big.Limb, |
| 3796 | 2574 | // + 1 for negatives |
| ... | ... | @@ -3798,102 +2576,104 @@ pub const Value = extern union { |
| 3798 | 2576 | ); |
| 3799 | 2577 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3800 | 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 | 2582 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3805 | 2583 | pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3806 | if (ty.zigTypeTag() == .Vector) { | |
| 3807 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 2584 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2585 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2586 | const scalar_ty = ty.scalarType(mod); | |
| 3808 | 2587 | for (result_data, 0..) |*scalar, i| { |
| 3809 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3810 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3811 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3812 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3813 | scalar.* = try bitwiseNandScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, mod); | |
| 2588 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2589 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2590 | scalar.* = try (try bitwiseNandScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, 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 | 2597 | return bitwiseNandScalar(lhs, rhs, ty, arena, mod); |
| 3818 | 2598 | } |
| 3819 | 2599 | |
| 3820 | 2600 | /// operands must be integers; handles undefined. |
| 3821 | 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 | 2605 | const anded = try bitwiseAnd(lhs, rhs, ty, arena, mod); |
| 3825 | ||
| 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 | ||
| 2606 | const all_ones = if (ty.isSignedInt(mod)) try mod.intValue(ty, -1) else try ty.maxIntScalar(mod, ty); | |
| 3831 | 2607 | return bitwiseXor(anded, all_ones, ty, arena, mod); |
| 3832 | 2608 | } |
| 3833 | 2609 | |
| 3834 | 2610 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3835 | 2611 | pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3836 | const target = mod.getTarget(); | |
| 3837 | if (ty.zigTypeTag() == .Vector) { | |
| 3838 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 2612 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2613 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2614 | const scalar_ty = ty.scalarType(mod); | |
| 3839 | 2615 | for (result_data, 0..) |*scalar, i| { |
| 3840 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3841 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3842 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3843 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3844 | scalar.* = try bitwiseOrScalar(lhs_elem, rhs_elem, allocator, target); | |
| 2616 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2617 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2618 | scalar.* = try (try bitwiseOrScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); | |
| 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 | 2628 | /// operands must be integers; handles undefined. |
| 3852 | pub fn bitwiseOrScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { | |
| 3853 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 2629 | pub fn bitwiseOrScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | |
| 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 | 2633 | // TODO is this a performance issue? maybe we should try the operation without |
| 3856 | 2634 | // resorting to BigInt first. |
| 3857 | 2635 | var lhs_space: Value.BigIntSpace = undefined; |
| 3858 | 2636 | var rhs_space: Value.BigIntSpace = undefined; |
| 3859 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3860 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2637 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2638 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3861 | 2639 | const limbs = try arena.alloc( |
| 3862 | 2640 | std.math.big.Limb, |
| 3863 | 2641 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len), |
| 3864 | 2642 | ); |
| 3865 | 2643 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3866 | 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 | 2648 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3871 | 2649 | pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3872 | const target = mod.getTarget(); | |
| 3873 | if (ty.zigTypeTag() == .Vector) { | |
| 3874 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 2650 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2651 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2652 | const scalar_ty = ty.scalarType(mod); | |
| 3875 | 2653 | for (result_data, 0..) |*scalar, i| { |
| 3876 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3877 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3878 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3879 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3880 | scalar.* = try bitwiseXorScalar(lhs_elem, rhs_elem, allocator, target); | |
| 2654 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2655 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2656 | scalar.* = try (try bitwiseXorScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); | |
| 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 | 2666 | /// operands must be integers; handles undefined. |
| 3888 | pub fn bitwiseXorScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { | |
| 3889 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 2667 | pub fn bitwiseXorScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | |
| 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 | 2671 | // TODO is this a performance issue? maybe we should try the operation without |
| 3892 | 2672 | // resorting to BigInt first. |
| 3893 | 2673 | var lhs_space: Value.BigIntSpace = undefined; |
| 3894 | 2674 | var rhs_space: Value.BigIntSpace = undefined; |
| 3895 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3896 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2675 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2676 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3897 | 2677 | const limbs = try arena.alloc( |
| 3898 | 2678 | std.math.big.Limb, |
| 3899 | 2679 | // + 1 for negatives |
| ... | ... | @@ -3901,32 +2681,61 @@ pub const Value = extern union { |
| 3901 | 2681 | ); |
| 3902 | 2682 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3903 | 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 { | |
| 3908 | const target = mod.getTarget(); | |
| 3909 | if (ty.zigTypeTag() == .Vector) { | |
| 3910 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 2708 | fn intDivInner(lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize, allocator: Allocator, mod: *Module) !Value { | |
| 2709 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2710 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2711 | const scalar_ty = ty.scalarType(mod); | |
| 3911 | 2712 | for (result_data, 0..) |*scalar, i| { |
| 3912 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3913 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3914 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3915 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3916 | scalar.* = try intDivScalar(lhs_elem, rhs_elem, allocator, target); | |
| 2713 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2714 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2715 | const val = intDivScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod) catch |err| switch (err) { | |
| 2716 | error.Overflow => { | |
| 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 | 2733 | // TODO is this a performance issue? maybe we should try the operation without |
| 3925 | 2734 | // resorting to BigInt first. |
| 3926 | 2735 | var lhs_space: Value.BigIntSpace = undefined; |
| 3927 | 2736 | var rhs_space: Value.BigIntSpace = undefined; |
| 3928 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3929 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2737 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2738 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3930 | 2739 | const limbs_q = try allocator.alloc( |
| 3931 | 2740 | std.math.big.Limb, |
| 3932 | 2741 | lhs_bigint.limbs.len, |
| ... | ... | @@ -3942,32 +2751,39 @@ pub const Value = extern union { |
| 3942 | 2751 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; |
| 3943 | 2752 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; |
| 3944 | 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 | 2763 | pub fn intDivFloor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3949 | const target = mod.getTarget(); | |
| 3950 | if (ty.zigTypeTag() == .Vector) { | |
| 3951 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 2764 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2765 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2766 | const scalar_ty = ty.scalarType(mod); | |
| 3952 | 2767 | for (result_data, 0..) |*scalar, i| { |
| 3953 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3954 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3955 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3956 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3957 | scalar.* = try intDivFloorScalar(lhs_elem, rhs_elem, allocator, target); | |
| 2768 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2769 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2770 | scalar.* = try (try intDivFloorScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); | |
| 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 | 2781 | // TODO is this a performance issue? maybe we should try the operation without |
| 3966 | 2782 | // resorting to BigInt first. |
| 3967 | 2783 | var lhs_space: Value.BigIntSpace = undefined; |
| 3968 | 2784 | var rhs_space: Value.BigIntSpace = undefined; |
| 3969 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 3970 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2785 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2786 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 3971 | 2787 | const limbs_q = try allocator.alloc( |
| 3972 | 2788 | std.math.big.Limb, |
| 3973 | 2789 | lhs_bigint.limbs.len, |
| ... | ... | @@ -3983,32 +2799,33 @@ pub const Value = extern union { |
| 3983 | 2799 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; |
| 3984 | 2800 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; |
| 3985 | 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 | 2805 | pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3990 | const target = mod.getTarget(); | |
| 3991 | if (ty.zigTypeTag() == .Vector) { | |
| 3992 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 2806 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2807 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2808 | const scalar_ty = ty.scalarType(mod); | |
| 3993 | 2809 | for (result_data, 0..) |*scalar, i| { |
| 3994 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 3995 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 3996 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 3997 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 3998 | scalar.* = try intModScalar(lhs_elem, rhs_elem, allocator, target); | |
| 2810 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2811 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2812 | scalar.* = try (try intModScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); | |
| 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 | 2823 | // TODO is this a performance issue? maybe we should try the operation without |
| 4007 | 2824 | // resorting to BigInt first. |
| 4008 | 2825 | var lhs_space: Value.BigIntSpace = undefined; |
| 4009 | 2826 | var rhs_space: Value.BigIntSpace = undefined; |
| 4010 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 4011 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 2827 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 2828 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 4012 | 2829 | const limbs_q = try allocator.alloc( |
| 4013 | 2830 | std.math.big.Limb, |
| 4014 | 2831 | lhs_bigint.limbs.len, |
| ... | ... | @@ -4024,161 +2841,164 @@ pub const Value = extern union { |
| 4024 | 2841 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; |
| 4025 | 2842 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; |
| 4026 | 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 | 2847 | /// Returns true if the value is a floating point type and is NaN. Returns false otherwise. |
| 4031 | pub fn isNan(val: Value) bool { | |
| 4032 | return switch (val.tag()) { | |
| 4033 | .float_16 => std.math.isNan(val.castTag(.float_16).?.data), | |
| 4034 | .float_32 => std.math.isNan(val.castTag(.float_32).?.data), | |
| 4035 | .float_64 => std.math.isNan(val.castTag(.float_64).?.data), | |
| 4036 | .float_80 => std.math.isNan(val.castTag(.float_80).?.data), | |
| 4037 | .float_128 => std.math.isNan(val.castTag(.float_128).?.data), | |
| 2848 | pub fn isNan(val: Value, mod: *const Module) bool { | |
| 2849 | if (val.ip_index == .none) return false; | |
| 2850 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2851 | .float => |float| switch (float.storage) { | |
| 2852 | inline else => |x| std.math.isNan(x), | |
| 2853 | }, | |
| 4038 | 2854 | else => false, |
| 4039 | 2855 | }; |
| 4040 | 2856 | } |
| 4041 | 2857 | |
| 4042 | 2858 | /// Returns true if the value is a floating point type and is infinite. Returns false otherwise. |
| 4043 | pub fn isInf(val: Value) bool { | |
| 4044 | return switch (val.tag()) { | |
| 4045 | .float_16 => std.math.isInf(val.castTag(.float_16).?.data), | |
| 4046 | .float_32 => std.math.isInf(val.castTag(.float_32).?.data), | |
| 4047 | .float_64 => std.math.isInf(val.castTag(.float_64).?.data), | |
| 4048 | .float_80 => std.math.isInf(val.castTag(.float_80).?.data), | |
| 4049 | .float_128 => std.math.isInf(val.castTag(.float_128).?.data), | |
| 2859 | pub fn isInf(val: Value, mod: *const Module) bool { | |
| 2860 | if (val.ip_index == .none) return false; | |
| 2861 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2862 | .float => |float| switch (float.storage) { | |
| 2863 | inline else => |x| std.math.isInf(x), | |
| 2864 | }, | |
| 4050 | 2865 | else => false, |
| 4051 | 2866 | }; |
| 4052 | 2867 | } |
| 4053 | 2868 | |
| 4054 | pub fn isNegativeInf(val: Value) bool { | |
| 4055 | return switch (val.tag()) { | |
| 4056 | .float_16 => std.math.isNegativeInf(val.castTag(.float_16).?.data), | |
| 4057 | .float_32 => std.math.isNegativeInf(val.castTag(.float_32).?.data), | |
| 4058 | .float_64 => std.math.isNegativeInf(val.castTag(.float_64).?.data), | |
| 4059 | .float_80 => std.math.isNegativeInf(val.castTag(.float_80).?.data), | |
| 4060 | .float_128 => std.math.isNegativeInf(val.castTag(.float_128).?.data), | |
| 2869 | pub fn isNegativeInf(val: Value, mod: *const Module) bool { | |
| 2870 | if (val.ip_index == .none) return false; | |
| 2871 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 2872 | .float => |float| switch (float.storage) { | |
| 2873 | inline else => |x| std.math.isNegativeInf(x), | |
| 2874 | }, | |
| 4061 | 2875 | else => false, |
| 4062 | 2876 | }; |
| 4063 | 2877 | } |
| 4064 | 2878 | |
| 4065 | 2879 | pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4066 | const target = mod.getTarget(); | |
| 4067 | if (float_type.zigTypeTag() == .Vector) { | |
| 4068 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 2880 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 2881 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 2882 | const scalar_ty = float_type.scalarType(mod); | |
| 4069 | 2883 | for (result_data, 0..) |*scalar, i| { |
| 4070 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4071 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4072 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4073 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4074 | scalar.* = try floatRemScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | |
| 2884 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2885 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2886 | scalar.* = try (try floatRemScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4082 | switch (float_type.floatBits(target)) { | |
| 4083 | 16 => { | |
| 4084 | const lhs_val = lhs.toFloat(f16); | |
| 4085 | const rhs_val = rhs.toFloat(f16); | |
| 4086 | return Value.Tag.float_16.create(arena, @rem(lhs_val, rhs_val)); | |
| 4087 | }, | |
| 4088 | 32 => { | |
| 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 | }, | |
| 2896 | pub fn floatRemScalar(lhs: Value, rhs: Value, float_type: Type, mod: *Module) !Value { | |
| 2897 | const target = mod.getTarget(); | |
| 2898 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 2899 | 16 => .{ .f16 = @rem(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, | |
| 2900 | 32 => .{ .f32 = @rem(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, | |
| 2901 | 64 => .{ .f64 = @rem(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, | |
| 2902 | 80 => .{ .f80 = @rem(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, | |
| 2903 | 128 => .{ .f128 = @rem(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, | |
| 4108 | 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 | 2912 | pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4113 | const target = mod.getTarget(); | |
| 4114 | if (float_type.zigTypeTag() == .Vector) { | |
| 4115 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 2913 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 2914 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 2915 | const scalar_ty = float_type.scalarType(mod); | |
| 4116 | 2916 | for (result_data, 0..) |*scalar, i| { |
| 4117 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4118 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4119 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4120 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4121 | scalar.* = try floatModScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | |
| 2917 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2918 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2919 | scalar.* = try (try floatModScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4129 | switch (float_type.floatBits(target)) { | |
| 4130 | 16 => { | |
| 4131 | const lhs_val = lhs.toFloat(f16); | |
| 4132 | const rhs_val = rhs.toFloat(f16); | |
| 4133 | return Value.Tag.float_16.create(arena, @mod(lhs_val, rhs_val)); | |
| 4134 | }, | |
| 4135 | 32 => { | |
| 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 | }, | |
| 2929 | pub fn floatModScalar(lhs: Value, rhs: Value, float_type: Type, mod: *Module) !Value { | |
| 2930 | const target = mod.getTarget(); | |
| 2931 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 2932 | 16 => .{ .f16 = @mod(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, | |
| 2933 | 32 => .{ .f32 = @mod(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, | |
| 2934 | 64 => .{ .f64 = @mod(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, | |
| 2935 | 80 => .{ .f80 = @mod(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, | |
| 2936 | 128 => .{ .f128 = @mod(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, | |
| 4155 | 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 { | |
| 4160 | const target = mod.getTarget(); | |
| 4161 | if (ty.zigTypeTag() == .Vector) { | |
| 4162 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 2966 | fn intMulInner(lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize, allocator: Allocator, mod: *Module) !Value { | |
| 2967 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 2968 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 2969 | const scalar_ty = ty.scalarType(mod); | |
| 4163 | 2970 | for (result_data, 0..) |*scalar, i| { |
| 4164 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4165 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4166 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4167 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4168 | scalar.* = try intMulScalar(lhs_elem, rhs_elem, allocator, target); | |
| 2971 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 2972 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 2973 | const val = intMulScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod) catch |err| switch (err) { | |
| 2974 | error.Overflow => { | |
| 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 | 2996 | // TODO is this a performance issue? maybe we should try the operation without |
| 4177 | 2997 | // resorting to BigInt first. |
| 4178 | 2998 | var lhs_space: Value.BigIntSpace = undefined; |
| 4179 | 2999 | var rhs_space: Value.BigIntSpace = undefined; |
| 4180 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 4181 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | |
| 3000 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 3001 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); | |
| 4182 | 3002 | const limbs = try allocator.alloc( |
| 4183 | 3003 | std.math.big.Limb, |
| 4184 | 3004 | lhs_bigint.limbs.len + rhs_bigint.limbs.len, |
| ... | ... | @@ -4190,21 +3010,23 @@ pub const Value = extern union { |
| 4190 | 3010 | ); |
| 4191 | 3011 | defer allocator.free(limbs_buffer); |
| 4192 | 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 | 3016 | pub fn intTrunc(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16, mod: *Module) !Value { |
| 4197 | const target = mod.getTarget(); | |
| 4198 | if (ty.zigTypeTag() == .Vector) { | |
| 4199 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 3017 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 3018 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 3019 | const scalar_ty = ty.scalarType(mod); | |
| 4200 | 3020 | for (result_data, 0..) |*scalar, i| { |
| 4201 | var buf: Value.ElemValueBuffer = undefined; | |
| 4202 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4203 | scalar.* = try intTruncScalar(elem_val, allocator, signedness, bits, target); | |
| 3021 | const elem_val = try val.elemValue(mod, i); | |
| 3022 | scalar.* = try (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, bits, mod)).intern(scalar_ty, mod); | |
| 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 | 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 | 3038 | bits: Value, |
| 4217 | 3039 | mod: *Module, |
| 4218 | 3040 | ) !Value { |
| 4219 | const target = mod.getTarget(); | |
| 4220 | if (ty.zigTypeTag() == .Vector) { | |
| 4221 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 3041 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 3042 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 3043 | const scalar_ty = ty.scalarType(mod); | |
| 4222 | 3044 | for (result_data, 0..) |*scalar, i| { |
| 4223 | var buf: Value.ElemValueBuffer = undefined; | |
| 4224 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4225 | var bits_buf: Value.ElemValueBuffer = undefined; | |
| 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); | |
| 3045 | const elem_val = try val.elemValue(mod, i); | |
| 3046 | const bits_elem = try bits.elemValue(mod, i); | |
| 3047 | scalar.* = try (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, @intCast(u16, bits_elem.toUnsignedInt(mod)), mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4235 | if (bits == 0) return Value.zero; | |
| 3057 | pub fn intTruncScalar( | |
| 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 | 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 | 3070 | const limbs = try allocator.alloc( |
| 4241 | 3071 | std.math.big.Limb, |
| ... | ... | @@ -4244,31 +3074,32 @@ pub const Value = extern union { |
| 4244 | 3074 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 4245 | 3075 | |
| 4246 | 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 | 3080 | pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 4251 | const target = mod.getTarget(); | |
| 4252 | if (ty.zigTypeTag() == .Vector) { | |
| 4253 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 3081 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 3082 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 3083 | const scalar_ty = ty.scalarType(mod); | |
| 4254 | 3084 | for (result_data, 0..) |*scalar, i| { |
| 4255 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4256 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4257 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4258 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4259 | scalar.* = try shlScalar(lhs_elem, rhs_elem, allocator, target); | |
| 3085 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3086 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3087 | scalar.* = try (try shlScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); | |
| 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 | 3098 | // TODO is this a performance issue? maybe we should try the operation without |
| 4268 | 3099 | // resorting to BigInt first. |
| 4269 | 3100 | var lhs_space: Value.BigIntSpace = undefined; |
| 4270 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 4271 | const shift = @intCast(usize, rhs.toUnsignedInt(target)); | |
| 3101 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 3102 | const shift = @intCast(usize, rhs.toUnsignedInt(mod)); | |
| 4272 | 3103 | const limbs = try allocator.alloc( |
| 4273 | 3104 | std.math.big.Limb, |
| 4274 | 3105 | lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, |
| ... | ... | @@ -4279,7 +3110,12 @@ pub const Value = extern union { |
| 4279 | 3110 | .len = undefined, |
| 4280 | 3111 | }; |
| 4281 | 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 | 3121 | pub fn shlWithOverflow( |
| ... | ... | @@ -4289,25 +3125,30 @@ pub const Value = extern union { |
| 4289 | 3125 | allocator: Allocator, |
| 4290 | 3126 | mod: *Module, |
| 4291 | 3127 | ) !OverflowArithmeticResult { |
| 4292 | const target = mod.getTarget(); | |
| 4293 | if (ty.zigTypeTag() == .Vector) { | |
| 4294 | const overflowed_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 4295 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 4296 | for (result_data, 0..) |*scalar, i| { | |
| 4297 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4298 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4299 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4300 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4301 | const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), allocator, target); | |
| 4302 | overflowed_data[i] = of_math_result.overflow_bit; | |
| 4303 | scalar.* = of_math_result.wrapped_result; | |
| 3128 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 3129 | const vec_len = ty.vectorLen(mod); | |
| 3130 | const overflowed_data = try allocator.alloc(InternPool.Index, vec_len); | |
| 3131 | const result_data = try allocator.alloc(InternPool.Index, vec_len); | |
| 3132 | const scalar_ty = ty.scalarType(mod); | |
| 3133 | for (overflowed_data, result_data, 0..) |*of, *scalar, i| { | |
| 3134 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3135 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3136 | const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod); | |
| 3137 | of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); | |
| 3138 | scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); | |
| 4304 | 3139 | } |
| 4305 | 3140 | return OverflowArithmeticResult{ |
| 4306 | .overflow_bit = try Value.Tag.aggregate.create(allocator, overflowed_data), | |
| 4307 | .wrapped_result = try Value.Tag.aggregate.create(allocator, result_data), | |
| 3141 | .overflow_bit = (try mod.intern(.{ .aggregate = .{ | |
| 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 | 3154 | pub fn shlWithOverflowScalar( |
| ... | ... | @@ -4315,12 +3156,12 @@ pub const Value = extern union { |
| 4315 | 3156 | rhs: Value, |
| 4316 | 3157 | ty: Type, |
| 4317 | 3158 | allocator: Allocator, |
| 4318 | target: Target, | |
| 3159 | mod: *Module, | |
| 4319 | 3160 | ) !OverflowArithmeticResult { |
| 4320 | const info = ty.intInfo(target); | |
| 3161 | const info = ty.intInfo(mod); | |
| 4321 | 3162 | var lhs_space: Value.BigIntSpace = undefined; |
| 4322 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 4323 | const shift = @intCast(usize, rhs.toUnsignedInt(target)); | |
| 3163 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 3164 | const shift = @intCast(usize, rhs.toUnsignedInt(mod)); | |
| 4324 | 3165 | const limbs = try allocator.alloc( |
| 4325 | 3166 | std.math.big.Limb, |
| 4326 | 3167 | lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, |
| ... | ... | @@ -4336,8 +3177,8 @@ pub const Value = extern union { |
| 4336 | 3177 | result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); |
| 4337 | 3178 | } |
| 4338 | 3179 | return OverflowArithmeticResult{ |
| 4339 | .overflow_bit = boolToInt(overflowed), | |
| 4340 | .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()), | |
| 3180 | .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), | |
| 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 | 3189 | arena: Allocator, |
| 4349 | 3190 | mod: *Module, |
| 4350 | 3191 | ) !Value { |
| 4351 | const target = mod.getTarget(); | |
| 4352 | if (ty.zigTypeTag() == .Vector) { | |
| 4353 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 3192 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 3193 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 3194 | const scalar_ty = ty.scalarType(mod); | |
| 4354 | 3195 | for (result_data, 0..) |*scalar, i| { |
| 4355 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4356 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4357 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4358 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4359 | scalar.* = try shlSatScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | |
| 3196 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3197 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3198 | scalar.* = try (try shlSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); | |
| 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 | 3208 | pub fn shlSatScalar( |
| ... | ... | @@ -4368,15 +3210,15 @@ pub const Value = extern union { |
| 4368 | 3210 | rhs: Value, |
| 4369 | 3211 | ty: Type, |
| 4370 | 3212 | arena: Allocator, |
| 4371 | target: Target, | |
| 3213 | mod: *Module, | |
| 4372 | 3214 | ) !Value { |
| 4373 | 3215 | // TODO is this a performance issue? maybe we should try the operation without |
| 4374 | 3216 | // resorting to BigInt first. |
| 4375 | const info = ty.intInfo(target); | |
| 3217 | const info = ty.intInfo(mod); | |
| 4376 | 3218 | |
| 4377 | 3219 | var lhs_space: Value.BigIntSpace = undefined; |
| 4378 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 4379 | const shift = @intCast(usize, rhs.toUnsignedInt(target)); | |
| 3220 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 3221 | const shift = @intCast(usize, rhs.toUnsignedInt(mod)); | |
| 4380 | 3222 | const limbs = try arena.alloc( |
| 4381 | 3223 | std.math.big.Limb, |
| 4382 | 3224 | std.math.big.int.calcTwosCompLimbCount(info.bits) + 1, |
| ... | ... | @@ -4387,7 +3229,7 @@ pub const Value = extern union { |
| 4387 | 3229 | .len = undefined, |
| 4388 | 3230 | }; |
| 4389 | 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 | 3235 | pub fn shlTrunc( |
| ... | ... | @@ -4397,16 +3239,18 @@ pub const Value = extern union { |
| 4397 | 3239 | arena: Allocator, |
| 4398 | 3240 | mod: *Module, |
| 4399 | 3241 | ) !Value { |
| 4400 | if (ty.zigTypeTag() == .Vector) { | |
| 4401 | const result_data = try arena.alloc(Value, ty.vectorLen()); | |
| 3242 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 3243 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 3244 | const scalar_ty = ty.scalarType(mod); | |
| 4402 | 3245 | for (result_data, 0..) |*scalar, i| { |
| 4403 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4404 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4405 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4406 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4407 | scalar.* = try shlTruncScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, mod); | |
| 3246 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3247 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3248 | scalar.* = try (try shlTruncScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, 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 | 3255 | return shlTruncScalar(lhs, rhs, ty, arena, mod); |
| 4412 | 3256 | } |
| ... | ... | @@ -4419,42 +3263,43 @@ pub const Value = extern union { |
| 4419 | 3263 | mod: *Module, |
| 4420 | 3264 | ) !Value { |
| 4421 | 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 | 3267 | const truncated = try shifted.intTrunc(ty, arena, int_info.signedness, int_info.bits, mod); |
| 4424 | 3268 | return truncated; |
| 4425 | 3269 | } |
| 4426 | 3270 | |
| 4427 | 3271 | pub fn shr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 4428 | const target = mod.getTarget(); | |
| 4429 | if (ty.zigTypeTag() == .Vector) { | |
| 4430 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | |
| 3272 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 3273 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 3274 | const scalar_ty = ty.scalarType(mod); | |
| 4431 | 3275 | for (result_data, 0..) |*scalar, i| { |
| 4432 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4433 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4434 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4435 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4436 | scalar.* = try shrScalar(lhs_elem, rhs_elem, allocator, target); | |
| 3276 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3277 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3278 | scalar.* = try (try shrScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); | |
| 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 | 3289 | // TODO is this a performance issue? maybe we should try the operation without |
| 4445 | 3290 | // resorting to BigInt first. |
| 4446 | 3291 | var lhs_space: Value.BigIntSpace = undefined; |
| 4447 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | |
| 4448 | const shift = @intCast(usize, rhs.toUnsignedInt(target)); | |
| 3292 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | |
| 3293 | const shift = @intCast(usize, rhs.toUnsignedInt(mod)); | |
| 4449 | 3294 | |
| 4450 | 3295 | const result_limbs = lhs_bigint.limbs.len -| (shift / (@sizeOf(std.math.big.Limb) * 8)); |
| 4451 | 3296 | if (result_limbs == 0) { |
| 4452 | 3297 | // The shift is enough to remove all the bits from the number, which means the |
| 4453 | 3298 | // result is 0 or -1 depending on the sign. |
| 4454 | 3299 | if (lhs_bigint.positive) { |
| 4455 | return Value.zero; | |
| 3300 | return mod.intValue(ty, 0); | |
| 4456 | 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 | 3313 | .len = undefined, |
| 4469 | 3314 | }; |
| 4470 | 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 | 3319 | pub fn floatNeg( |
| ... | ... | @@ -4477,33 +3322,127 @@ pub const Value = extern union { |
| 4477 | 3322 | arena: Allocator, |
| 4478 | 3323 | mod: *Module, |
| 4479 | 3324 | ) !Value { |
| 4480 | const target = mod.getTarget(); | |
| 4481 | if (float_type.zigTypeTag() == .Vector) { | |
| 4482 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3325 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3326 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3327 | const scalar_ty = float_type.scalarType(mod); | |
| 4483 | 3328 | for (result_data, 0..) |*scalar, i| { |
| 4484 | var buf: Value.ElemValueBuffer = undefined; | |
| 4485 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4486 | scalar.* = try floatNegScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3329 | const elem_val = try val.elemValue(mod, i); | |
| 3330 | scalar.* = try (try floatNegScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 | 3340 | pub fn floatNegScalar( |
| 4494 | 3341 | val: Value, |
| 4495 | 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 | 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 | 3388 | ) !Value { |
| 4499 | switch (float_type.floatBits(target)) { | |
| 4500 | 16 => return Value.Tag.float_16.create(arena, -val.toFloat(f16)), | |
| 4501 | 32 => return Value.Tag.float_32.create(arena, -val.toFloat(f32)), | |
| 4502 | 64 => return Value.Tag.float_64.create(arena, -val.toFloat(f64)), | |
| 4503 | 80 => return Value.Tag.float_80.create(arena, -val.toFloat(f80)), | |
| 4504 | 128 => return Value.Tag.float_128.create(arena, -val.toFloat(f128)), | |
| 3389 | const target = mod.getTarget(); | |
| 3390 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3391 | 16 => .{ .f16 = lhs.toFloat(f16, mod) + rhs.toFloat(f16, mod) }, | |
| 3392 | 32 => .{ .f32 = lhs.toFloat(f32, mod) + rhs.toFloat(f32, mod) }, | |
| 3393 | 64 => .{ .f64 = lhs.toFloat(f64, mod) + rhs.toFloat(f64, mod) }, | |
| 3394 | 80 => .{ .f80 = lhs.toFloat(f80, mod) + rhs.toFloat(f80, mod) }, | |
| 3395 | 128 => .{ .f128 = lhs.toFloat(f128, mod) + rhs.toFloat(f128, mod) }, | |
| 4505 | 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 | 3448 | pub fn floatDiv( |
| ... | ... | @@ -4513,56 +3452,41 @@ pub const Value = extern union { |
| 4513 | 3452 | arena: Allocator, |
| 4514 | 3453 | mod: *Module, |
| 4515 | 3454 | ) !Value { |
| 4516 | const target = mod.getTarget(); | |
| 4517 | if (float_type.zigTypeTag() == .Vector) { | |
| 4518 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3455 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3456 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3457 | const scalar_ty = float_type.scalarType(mod); | |
| 4519 | 3458 | for (result_data, 0..) |*scalar, i| { |
| 4520 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4521 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4522 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4523 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4524 | scalar.* = try floatDivScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | |
| 3459 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3460 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3461 | scalar.* = try (try floatDivScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 | 3471 | pub fn floatDivScalar( |
| 4532 | 3472 | lhs: Value, |
| 4533 | 3473 | rhs: Value, |
| 4534 | 3474 | float_type: Type, |
| 4535 | arena: Allocator, | |
| 4536 | target: Target, | |
| 3475 | mod: *Module, | |
| 4537 | 3476 | ) !Value { |
| 4538 | switch (float_type.floatBits(target)) { | |
| 4539 | 16 => { | |
| 4540 | const lhs_val = lhs.toFloat(f16); | |
| 4541 | const rhs_val = rhs.toFloat(f16); | |
| 4542 | return Value.Tag.float_16.create(arena, lhs_val / rhs_val); | |
| 4543 | }, | |
| 4544 | 32 => { | |
| 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 | }, | |
| 3477 | const target = mod.getTarget(); | |
| 3478 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3479 | 16 => .{ .f16 = lhs.toFloat(f16, mod) / rhs.toFloat(f16, mod) }, | |
| 3480 | 32 => .{ .f32 = lhs.toFloat(f32, mod) / rhs.toFloat(f32, mod) }, | |
| 3481 | 64 => .{ .f64 = lhs.toFloat(f64, mod) / rhs.toFloat(f64, mod) }, | |
| 3482 | 80 => .{ .f80 = lhs.toFloat(f80, mod) / rhs.toFloat(f80, mod) }, | |
| 3483 | 128 => .{ .f128 = lhs.toFloat(f128, mod) / rhs.toFloat(f128, mod) }, | |
| 4564 | 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 | 3492 | pub fn floatDivFloor( |
| ... | ... | @@ -4572,56 +3496,41 @@ pub const Value = extern union { |
| 4572 | 3496 | arena: Allocator, |
| 4573 | 3497 | mod: *Module, |
| 4574 | 3498 | ) !Value { |
| 4575 | const target = mod.getTarget(); | |
| 4576 | if (float_type.zigTypeTag() == .Vector) { | |
| 4577 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3499 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3500 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3501 | const scalar_ty = float_type.scalarType(mod); | |
| 4578 | 3502 | for (result_data, 0..) |*scalar, i| { |
| 4579 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4580 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4581 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4582 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4583 | scalar.* = try floatDivFloorScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | |
| 3503 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3504 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3505 | scalar.* = try (try floatDivFloorScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 | 3515 | pub fn floatDivFloorScalar( |
| 4591 | 3516 | lhs: Value, |
| 4592 | 3517 | rhs: Value, |
| 4593 | 3518 | float_type: Type, |
| 4594 | arena: Allocator, | |
| 4595 | target: Target, | |
| 3519 | mod: *Module, | |
| 4596 | 3520 | ) !Value { |
| 4597 | switch (float_type.floatBits(target)) { | |
| 4598 | 16 => { | |
| 4599 | const lhs_val = lhs.toFloat(f16); | |
| 4600 | const rhs_val = rhs.toFloat(f16); | |
| 4601 | return Value.Tag.float_16.create(arena, @divFloor(lhs_val, rhs_val)); | |
| 4602 | }, | |
| 4603 | 32 => { | |
| 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 | }, | |
| 3521 | const target = mod.getTarget(); | |
| 3522 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3523 | 16 => .{ .f16 = @divFloor(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, | |
| 3524 | 32 => .{ .f32 = @divFloor(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, | |
| 3525 | 64 => .{ .f64 = @divFloor(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, | |
| 3526 | 80 => .{ .f80 = @divFloor(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, | |
| 3527 | 128 => .{ .f128 = @divFloor(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, | |
| 4623 | 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 | 3536 | pub fn floatDivTrunc( |
| ... | ... | @@ -4631,56 +3540,41 @@ pub const Value = extern union { |
| 4631 | 3540 | arena: Allocator, |
| 4632 | 3541 | mod: *Module, |
| 4633 | 3542 | ) !Value { |
| 4634 | const target = mod.getTarget(); | |
| 4635 | if (float_type.zigTypeTag() == .Vector) { | |
| 4636 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3543 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3544 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3545 | const scalar_ty = float_type.scalarType(mod); | |
| 4637 | 3546 | for (result_data, 0..) |*scalar, i| { |
| 4638 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4639 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4640 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4641 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4642 | scalar.* = try floatDivTruncScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | |
| 3547 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3548 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3549 | scalar.* = try (try floatDivTruncScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 | 3559 | pub fn floatDivTruncScalar( |
| 4650 | 3560 | lhs: Value, |
| 4651 | 3561 | rhs: Value, |
| 4652 | 3562 | float_type: Type, |
| 4653 | arena: Allocator, | |
| 4654 | target: Target, | |
| 3563 | mod: *Module, | |
| 4655 | 3564 | ) !Value { |
| 4656 | switch (float_type.floatBits(target)) { | |
| 4657 | 16 => { | |
| 4658 | const lhs_val = lhs.toFloat(f16); | |
| 4659 | const rhs_val = rhs.toFloat(f16); | |
| 4660 | return Value.Tag.float_16.create(arena, @divTrunc(lhs_val, rhs_val)); | |
| 4661 | }, | |
| 4662 | 32 => { | |
| 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 | }, | |
| 3565 | const target = mod.getTarget(); | |
| 3566 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3567 | 16 => .{ .f16 = @divTrunc(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, | |
| 3568 | 32 => .{ .f32 = @divTrunc(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, | |
| 3569 | 64 => .{ .f64 = @divTrunc(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, | |
| 3570 | 80 => .{ .f80 = @divTrunc(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, | |
| 3571 | 128 => .{ .f128 = @divTrunc(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, | |
| 4682 | 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 | 3580 | pub fn floatMul( |
| ... | ... | @@ -4690,616 +3584,489 @@ pub const Value = extern union { |
| 4690 | 3584 | arena: Allocator, |
| 4691 | 3585 | mod: *Module, |
| 4692 | 3586 | ) !Value { |
| 4693 | const target = mod.getTarget(); | |
| 4694 | if (float_type.zigTypeTag() == .Vector) { | |
| 4695 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3587 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3588 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3589 | const scalar_ty = float_type.scalarType(mod); | |
| 4696 | 3590 | for (result_data, 0..) |*scalar, i| { |
| 4697 | var lhs_buf: Value.ElemValueBuffer = undefined; | |
| 4698 | var rhs_buf: Value.ElemValueBuffer = undefined; | |
| 4699 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | |
| 4700 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | |
| 4701 | scalar.* = try floatMulScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | |
| 3591 | const lhs_elem = try lhs.elemValue(mod, i); | |
| 3592 | const rhs_elem = try rhs.elemValue(mod, i); | |
| 3593 | scalar.* = try (try floatMulScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 | 3603 | pub fn floatMulScalar( |
| 4709 | 3604 | lhs: Value, |
| 4710 | 3605 | rhs: Value, |
| 4711 | 3606 | float_type: Type, |
| 4712 | arena: Allocator, | |
| 4713 | target: Target, | |
| 3607 | mod: *Module, | |
| 4714 | 3608 | ) !Value { |
| 4715 | switch (float_type.floatBits(target)) { | |
| 4716 | 16 => { | |
| 4717 | const lhs_val = lhs.toFloat(f16); | |
| 4718 | const rhs_val = rhs.toFloat(f16); | |
| 4719 | return Value.Tag.float_16.create(arena, lhs_val * rhs_val); | |
| 4720 | }, | |
| 4721 | 32 => { | |
| 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 | }, | |
| 3609 | const target = mod.getTarget(); | |
| 3610 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3611 | 16 => .{ .f16 = lhs.toFloat(f16, mod) * rhs.toFloat(f16, mod) }, | |
| 3612 | 32 => .{ .f32 = lhs.toFloat(f32, mod) * rhs.toFloat(f32, mod) }, | |
| 3613 | 64 => .{ .f64 = lhs.toFloat(f64, mod) * rhs.toFloat(f64, mod) }, | |
| 3614 | 80 => .{ .f80 = lhs.toFloat(f80, mod) * rhs.toFloat(f80, mod) }, | |
| 3615 | 128 => .{ .f128 = lhs.toFloat(f128, mod) * rhs.toFloat(f128, mod) }, | |
| 4741 | 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 | 3624 | pub fn sqrt(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4746 | const target = mod.getTarget(); | |
| 4747 | if (float_type.zigTypeTag() == .Vector) { | |
| 4748 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3625 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3626 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3627 | const scalar_ty = float_type.scalarType(mod); | |
| 4749 | 3628 | for (result_data, 0..) |*scalar, i| { |
| 4750 | var buf: Value.ElemValueBuffer = undefined; | |
| 4751 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4752 | scalar.* = try sqrtScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3629 | const elem_val = try val.elemValue(mod, i); | |
| 3630 | scalar.* = try (try sqrtScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4760 | switch (float_type.floatBits(target)) { | |
| 4761 | 16 => { | |
| 4762 | const f = val.toFloat(f16); | |
| 4763 | return Value.Tag.float_16.create(arena, @sqrt(f)); | |
| 4764 | }, | |
| 4765 | 32 => { | |
| 4766 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3640 | pub fn sqrtScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3641 | const target = mod.getTarget(); | |
| 3642 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3643 | 16 => .{ .f16 = @sqrt(val.toFloat(f16, mod)) }, | |
| 3644 | 32 => .{ .f32 = @sqrt(val.toFloat(f32, mod)) }, | |
| 3645 | 64 => .{ .f64 = @sqrt(val.toFloat(f64, mod)) }, | |
| 3646 | 80 => .{ .f80 = @sqrt(val.toFloat(f80, mod)) }, | |
| 3647 | 128 => .{ .f128 = @sqrt(val.toFloat(f128, mod)) }, | |
| 4781 | 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 | 3656 | pub fn sin(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4786 | const target = mod.getTarget(); | |
| 4787 | if (float_type.zigTypeTag() == .Vector) { | |
| 4788 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3657 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3658 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3659 | const scalar_ty = float_type.scalarType(mod); | |
| 4789 | 3660 | for (result_data, 0..) |*scalar, i| { |
| 4790 | var buf: Value.ElemValueBuffer = undefined; | |
| 4791 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4792 | scalar.* = try sinScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3661 | const elem_val = try val.elemValue(mod, i); | |
| 3662 | scalar.* = try (try sinScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4800 | switch (float_type.floatBits(target)) { | |
| 4801 | 16 => { | |
| 4802 | const f = val.toFloat(f16); | |
| 4803 | return Value.Tag.float_16.create(arena, @sin(f)); | |
| 4804 | }, | |
| 4805 | 32 => { | |
| 4806 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3672 | pub fn sinScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3673 | const target = mod.getTarget(); | |
| 3674 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3675 | 16 => .{ .f16 = @sin(val.toFloat(f16, mod)) }, | |
| 3676 | 32 => .{ .f32 = @sin(val.toFloat(f32, mod)) }, | |
| 3677 | 64 => .{ .f64 = @sin(val.toFloat(f64, mod)) }, | |
| 3678 | 80 => .{ .f80 = @sin(val.toFloat(f80, mod)) }, | |
| 3679 | 128 => .{ .f128 = @sin(val.toFloat(f128, mod)) }, | |
| 4821 | 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 | 3688 | pub fn cos(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4826 | const target = mod.getTarget(); | |
| 4827 | if (float_type.zigTypeTag() == .Vector) { | |
| 4828 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3689 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3690 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3691 | const scalar_ty = float_type.scalarType(mod); | |
| 4829 | 3692 | for (result_data, 0..) |*scalar, i| { |
| 4830 | var buf: Value.ElemValueBuffer = undefined; | |
| 4831 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4832 | scalar.* = try cosScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3693 | const elem_val = try val.elemValue(mod, i); | |
| 3694 | scalar.* = try (try cosScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4840 | switch (float_type.floatBits(target)) { | |
| 4841 | 16 => { | |
| 4842 | const f = val.toFloat(f16); | |
| 4843 | return Value.Tag.float_16.create(arena, @cos(f)); | |
| 4844 | }, | |
| 4845 | 32 => { | |
| 4846 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3704 | pub fn cosScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3705 | const target = mod.getTarget(); | |
| 3706 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3707 | 16 => .{ .f16 = @cos(val.toFloat(f16, mod)) }, | |
| 3708 | 32 => .{ .f32 = @cos(val.toFloat(f32, mod)) }, | |
| 3709 | 64 => .{ .f64 = @cos(val.toFloat(f64, mod)) }, | |
| 3710 | 80 => .{ .f80 = @cos(val.toFloat(f80, mod)) }, | |
| 3711 | 128 => .{ .f128 = @cos(val.toFloat(f128, mod)) }, | |
| 4861 | 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 | 3720 | pub fn tan(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4866 | const target = mod.getTarget(); | |
| 4867 | if (float_type.zigTypeTag() == .Vector) { | |
| 4868 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3721 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3722 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3723 | const scalar_ty = float_type.scalarType(mod); | |
| 4869 | 3724 | for (result_data, 0..) |*scalar, i| { |
| 4870 | var buf: Value.ElemValueBuffer = undefined; | |
| 4871 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4872 | scalar.* = try tanScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3725 | const elem_val = try val.elemValue(mod, i); | |
| 3726 | scalar.* = try (try tanScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4880 | switch (float_type.floatBits(target)) { | |
| 4881 | 16 => { | |
| 4882 | const f = val.toFloat(f16); | |
| 4883 | return Value.Tag.float_16.create(arena, @tan(f)); | |
| 4884 | }, | |
| 4885 | 32 => { | |
| 4886 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3736 | pub fn tanScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3737 | const target = mod.getTarget(); | |
| 3738 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3739 | 16 => .{ .f16 = @tan(val.toFloat(f16, mod)) }, | |
| 3740 | 32 => .{ .f32 = @tan(val.toFloat(f32, mod)) }, | |
| 3741 | 64 => .{ .f64 = @tan(val.toFloat(f64, mod)) }, | |
| 3742 | 80 => .{ .f80 = @tan(val.toFloat(f80, mod)) }, | |
| 3743 | 128 => .{ .f128 = @tan(val.toFloat(f128, mod)) }, | |
| 4901 | 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 | 3752 | pub fn exp(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4906 | const target = mod.getTarget(); | |
| 4907 | if (float_type.zigTypeTag() == .Vector) { | |
| 4908 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3753 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3754 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3755 | const scalar_ty = float_type.scalarType(mod); | |
| 4909 | 3756 | for (result_data, 0..) |*scalar, i| { |
| 4910 | var buf: Value.ElemValueBuffer = undefined; | |
| 4911 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4912 | scalar.* = try expScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3757 | const elem_val = try val.elemValue(mod, i); | |
| 3758 | scalar.* = try (try expScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4920 | switch (float_type.floatBits(target)) { | |
| 4921 | 16 => { | |
| 4922 | const f = val.toFloat(f16); | |
| 4923 | return Value.Tag.float_16.create(arena, @exp(f)); | |
| 4924 | }, | |
| 4925 | 32 => { | |
| 4926 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3768 | pub fn expScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3769 | const target = mod.getTarget(); | |
| 3770 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3771 | 16 => .{ .f16 = @exp(val.toFloat(f16, mod)) }, | |
| 3772 | 32 => .{ .f32 = @exp(val.toFloat(f32, mod)) }, | |
| 3773 | 64 => .{ .f64 = @exp(val.toFloat(f64, mod)) }, | |
| 3774 | 80 => .{ .f80 = @exp(val.toFloat(f80, mod)) }, | |
| 3775 | 128 => .{ .f128 = @exp(val.toFloat(f128, mod)) }, | |
| 4941 | 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 | 3784 | pub fn exp2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4946 | const target = mod.getTarget(); | |
| 4947 | if (float_type.zigTypeTag() == .Vector) { | |
| 4948 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3785 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3786 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3787 | const scalar_ty = float_type.scalarType(mod); | |
| 4949 | 3788 | for (result_data, 0..) |*scalar, i| { |
| 4950 | var buf: Value.ElemValueBuffer = undefined; | |
| 4951 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4952 | scalar.* = try exp2Scalar(elem_val, float_type.scalarType(), arena, target); | |
| 3789 | const elem_val = try val.elemValue(mod, i); | |
| 3790 | scalar.* = try (try exp2Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 4960 | switch (float_type.floatBits(target)) { | |
| 4961 | 16 => { | |
| 4962 | const f = val.toFloat(f16); | |
| 4963 | return Value.Tag.float_16.create(arena, @exp2(f)); | |
| 4964 | }, | |
| 4965 | 32 => { | |
| 4966 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3800 | pub fn exp2Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3801 | const target = mod.getTarget(); | |
| 3802 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3803 | 16 => .{ .f16 = @exp2(val.toFloat(f16, mod)) }, | |
| 3804 | 32 => .{ .f32 = @exp2(val.toFloat(f32, mod)) }, | |
| 3805 | 64 => .{ .f64 = @exp2(val.toFloat(f64, mod)) }, | |
| 3806 | 80 => .{ .f80 = @exp2(val.toFloat(f80, mod)) }, | |
| 3807 | 128 => .{ .f128 = @exp2(val.toFloat(f128, mod)) }, | |
| 4981 | 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 | 3816 | pub fn log(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4986 | const target = mod.getTarget(); | |
| 4987 | if (float_type.zigTypeTag() == .Vector) { | |
| 4988 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3817 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3818 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3819 | const scalar_ty = float_type.scalarType(mod); | |
| 4989 | 3820 | for (result_data, 0..) |*scalar, i| { |
| 4990 | var buf: Value.ElemValueBuffer = undefined; | |
| 4991 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 4992 | scalar.* = try logScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3821 | const elem_val = try val.elemValue(mod, i); | |
| 3822 | scalar.* = try (try logScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 5000 | switch (float_type.floatBits(target)) { | |
| 5001 | 16 => { | |
| 5002 | const f = val.toFloat(f16); | |
| 5003 | return Value.Tag.float_16.create(arena, @log(f)); | |
| 5004 | }, | |
| 5005 | 32 => { | |
| 5006 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3832 | pub fn logScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3833 | const target = mod.getTarget(); | |
| 3834 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3835 | 16 => .{ .f16 = @log(val.toFloat(f16, mod)) }, | |
| 3836 | 32 => .{ .f32 = @log(val.toFloat(f32, mod)) }, | |
| 3837 | 64 => .{ .f64 = @log(val.toFloat(f64, mod)) }, | |
| 3838 | 80 => .{ .f80 = @log(val.toFloat(f80, mod)) }, | |
| 3839 | 128 => .{ .f128 = @log(val.toFloat(f128, mod)) }, | |
| 5021 | 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 | 3848 | pub fn log2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5026 | const target = mod.getTarget(); | |
| 5027 | if (float_type.zigTypeTag() == .Vector) { | |
| 5028 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3849 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3850 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3851 | const scalar_ty = float_type.scalarType(mod); | |
| 5029 | 3852 | for (result_data, 0..) |*scalar, i| { |
| 5030 | var buf: Value.ElemValueBuffer = undefined; | |
| 5031 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 5032 | scalar.* = try log2Scalar(elem_val, float_type.scalarType(), arena, target); | |
| 3853 | const elem_val = try val.elemValue(mod, i); | |
| 3854 | scalar.* = try (try log2Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 5040 | switch (float_type.floatBits(target)) { | |
| 5041 | 16 => { | |
| 5042 | const f = val.toFloat(f16); | |
| 5043 | return Value.Tag.float_16.create(arena, @log2(f)); | |
| 5044 | }, | |
| 5045 | 32 => { | |
| 5046 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3864 | pub fn log2Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3865 | const target = mod.getTarget(); | |
| 3866 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3867 | 16 => .{ .f16 = @log2(val.toFloat(f16, mod)) }, | |
| 3868 | 32 => .{ .f32 = @log2(val.toFloat(f32, mod)) }, | |
| 3869 | 64 => .{ .f64 = @log2(val.toFloat(f64, mod)) }, | |
| 3870 | 80 => .{ .f80 = @log2(val.toFloat(f80, mod)) }, | |
| 3871 | 128 => .{ .f128 = @log2(val.toFloat(f128, mod)) }, | |
| 5061 | 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 | 3880 | pub fn log10(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5066 | const target = mod.getTarget(); | |
| 5067 | if (float_type.zigTypeTag() == .Vector) { | |
| 5068 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3881 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3882 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3883 | const scalar_ty = float_type.scalarType(mod); | |
| 5069 | 3884 | for (result_data, 0..) |*scalar, i| { |
| 5070 | var buf: Value.ElemValueBuffer = undefined; | |
| 5071 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 5072 | scalar.* = try log10Scalar(elem_val, float_type.scalarType(), arena, target); | |
| 3885 | const elem_val = try val.elemValue(mod, i); | |
| 3886 | scalar.* = try (try log10Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 5080 | switch (float_type.floatBits(target)) { | |
| 5081 | 16 => { | |
| 5082 | const f = val.toFloat(f16); | |
| 5083 | return Value.Tag.float_16.create(arena, @log10(f)); | |
| 5084 | }, | |
| 5085 | 32 => { | |
| 5086 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3896 | pub fn log10Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3897 | const target = mod.getTarget(); | |
| 3898 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3899 | 16 => .{ .f16 = @log10(val.toFloat(f16, mod)) }, | |
| 3900 | 32 => .{ .f32 = @log10(val.toFloat(f32, mod)) }, | |
| 3901 | 64 => .{ .f64 = @log10(val.toFloat(f64, mod)) }, | |
| 3902 | 80 => .{ .f80 = @log10(val.toFloat(f80, mod)) }, | |
| 3903 | 128 => .{ .f128 = @log10(val.toFloat(f128, mod)) }, | |
| 5101 | 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 | 3912 | pub fn fabs(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5106 | const target = mod.getTarget(); | |
| 5107 | if (float_type.zigTypeTag() == .Vector) { | |
| 5108 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3913 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3914 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3915 | const scalar_ty = float_type.scalarType(mod); | |
| 5109 | 3916 | for (result_data, 0..) |*scalar, i| { |
| 5110 | var buf: Value.ElemValueBuffer = undefined; | |
| 5111 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 5112 | scalar.* = try fabsScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3917 | const elem_val = try val.elemValue(mod, i); | |
| 3918 | scalar.* = try (try fabsScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 5120 | switch (float_type.floatBits(target)) { | |
| 5121 | 16 => { | |
| 5122 | const f = val.toFloat(f16); | |
| 5123 | return Value.Tag.float_16.create(arena, @fabs(f)); | |
| 5124 | }, | |
| 5125 | 32 => { | |
| 5126 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3928 | pub fn fabsScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3929 | const target = mod.getTarget(); | |
| 3930 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3931 | 16 => .{ .f16 = @fabs(val.toFloat(f16, mod)) }, | |
| 3932 | 32 => .{ .f32 = @fabs(val.toFloat(f32, mod)) }, | |
| 3933 | 64 => .{ .f64 = @fabs(val.toFloat(f64, mod)) }, | |
| 3934 | 80 => .{ .f80 = @fabs(val.toFloat(f80, mod)) }, | |
| 3935 | 128 => .{ .f128 = @fabs(val.toFloat(f128, mod)) }, | |
| 5141 | 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 | 3944 | pub fn floor(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5146 | const target = mod.getTarget(); | |
| 5147 | if (float_type.zigTypeTag() == .Vector) { | |
| 5148 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3945 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3946 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3947 | const scalar_ty = float_type.scalarType(mod); | |
| 5149 | 3948 | for (result_data, 0..) |*scalar, i| { |
| 5150 | var buf: Value.ElemValueBuffer = undefined; | |
| 5151 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 5152 | scalar.* = try floorScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3949 | const elem_val = try val.elemValue(mod, i); | |
| 3950 | scalar.* = try (try floorScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 5160 | switch (float_type.floatBits(target)) { | |
| 5161 | 16 => { | |
| 5162 | const f = val.toFloat(f16); | |
| 5163 | return Value.Tag.float_16.create(arena, @floor(f)); | |
| 5164 | }, | |
| 5165 | 32 => { | |
| 5166 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3960 | pub fn floorScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3961 | const target = mod.getTarget(); | |
| 3962 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3963 | 16 => .{ .f16 = @floor(val.toFloat(f16, mod)) }, | |
| 3964 | 32 => .{ .f32 = @floor(val.toFloat(f32, mod)) }, | |
| 3965 | 64 => .{ .f64 = @floor(val.toFloat(f64, mod)) }, | |
| 3966 | 80 => .{ .f80 = @floor(val.toFloat(f80, mod)) }, | |
| 3967 | 128 => .{ .f128 = @floor(val.toFloat(f128, mod)) }, | |
| 5181 | 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 | 3976 | pub fn ceil(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5186 | const target = mod.getTarget(); | |
| 5187 | if (float_type.zigTypeTag() == .Vector) { | |
| 5188 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 3977 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3978 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3979 | const scalar_ty = float_type.scalarType(mod); | |
| 5189 | 3980 | for (result_data, 0..) |*scalar, i| { |
| 5190 | var buf: Value.ElemValueBuffer = undefined; | |
| 5191 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 5192 | scalar.* = try ceilScalar(elem_val, float_type.scalarType(), arena, target); | |
| 3981 | const elem_val = try val.elemValue(mod, i); | |
| 3982 | scalar.* = try (try ceilScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 5200 | switch (float_type.floatBits(target)) { | |
| 5201 | 16 => { | |
| 5202 | const f = val.toFloat(f16); | |
| 5203 | return Value.Tag.float_16.create(arena, @ceil(f)); | |
| 5204 | }, | |
| 5205 | 32 => { | |
| 5206 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 3992 | pub fn ceilScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3993 | const target = mod.getTarget(); | |
| 3994 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3995 | 16 => .{ .f16 = @ceil(val.toFloat(f16, mod)) }, | |
| 3996 | 32 => .{ .f32 = @ceil(val.toFloat(f32, mod)) }, | |
| 3997 | 64 => .{ .f64 = @ceil(val.toFloat(f64, mod)) }, | |
| 3998 | 80 => .{ .f80 = @ceil(val.toFloat(f80, mod)) }, | |
| 3999 | 128 => .{ .f128 = @ceil(val.toFloat(f128, mod)) }, | |
| 5221 | 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 | 4008 | pub fn round(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5226 | const target = mod.getTarget(); | |
| 5227 | if (float_type.zigTypeTag() == .Vector) { | |
| 5228 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 4009 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 4010 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 4011 | const scalar_ty = float_type.scalarType(mod); | |
| 5229 | 4012 | for (result_data, 0..) |*scalar, i| { |
| 5230 | var buf: Value.ElemValueBuffer = undefined; | |
| 5231 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 5232 | scalar.* = try roundScalar(elem_val, float_type.scalarType(), arena, target); | |
| 4013 | const elem_val = try val.elemValue(mod, i); | |
| 4014 | scalar.* = try (try roundScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 5240 | switch (float_type.floatBits(target)) { | |
| 5241 | 16 => { | |
| 5242 | const f = val.toFloat(f16); | |
| 5243 | return Value.Tag.float_16.create(arena, @round(f)); | |
| 5244 | }, | |
| 5245 | 32 => { | |
| 5246 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 4024 | pub fn roundScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 4025 | const target = mod.getTarget(); | |
| 4026 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 4027 | 16 => .{ .f16 = @round(val.toFloat(f16, mod)) }, | |
| 4028 | 32 => .{ .f32 = @round(val.toFloat(f32, mod)) }, | |
| 4029 | 64 => .{ .f64 = @round(val.toFloat(f64, mod)) }, | |
| 4030 | 80 => .{ .f80 = @round(val.toFloat(f80, mod)) }, | |
| 4031 | 128 => .{ .f128 = @round(val.toFloat(f128, mod)) }, | |
| 5261 | 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 | 4040 | pub fn trunc(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5266 | const target = mod.getTarget(); | |
| 5267 | if (float_type.zigTypeTag() == .Vector) { | |
| 5268 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 4041 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 4042 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 4043 | const scalar_ty = float_type.scalarType(mod); | |
| 5269 | 4044 | for (result_data, 0..) |*scalar, i| { |
| 5270 | var buf: Value.ElemValueBuffer = undefined; | |
| 5271 | const elem_val = val.elemValueBuffer(mod, i, &buf); | |
| 5272 | scalar.* = try truncScalar(elem_val, float_type.scalarType(), arena, target); | |
| 4045 | const elem_val = try val.elemValue(mod, i); | |
| 4046 | scalar.* = try (try truncScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); | |
| 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 { | |
| 5280 | switch (float_type.floatBits(target)) { | |
| 5281 | 16 => { | |
| 5282 | const f = val.toFloat(f16); | |
| 5283 | return Value.Tag.float_16.create(arena, @trunc(f)); | |
| 5284 | }, | |
| 5285 | 32 => { | |
| 5286 | const f = val.toFloat(f32); | |
| 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 | }, | |
| 4056 | pub fn truncScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 4057 | const target = mod.getTarget(); | |
| 4058 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 4059 | 16 => .{ .f16 = @trunc(val.toFloat(f16, mod)) }, | |
| 4060 | 32 => .{ .f32 = @trunc(val.toFloat(f32, mod)) }, | |
| 4061 | 64 => .{ .f64 = @trunc(val.toFloat(f64, mod)) }, | |
| 4062 | 80 => .{ .f80 = @trunc(val.toFloat(f80, mod)) }, | |
| 4063 | 128 => .{ .f128 = @trunc(val.toFloat(f128, mod)) }, | |
| 5301 | 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 | 4072 | pub fn mulAdd( |
| ... | ... | @@ -5310,28 +4077,21 @@ pub const Value = extern union { |
| 5310 | 4077 | arena: Allocator, |
| 5311 | 4078 | mod: *Module, |
| 5312 | 4079 | ) !Value { |
| 5313 | const target = mod.getTarget(); | |
| 5314 | if (float_type.zigTypeTag() == .Vector) { | |
| 5315 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | |
| 4080 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 4081 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 4082 | const scalar_ty = float_type.scalarType(mod); | |
| 5316 | 4083 | for (result_data, 0..) |*scalar, i| { |
| 5317 | var mulend1_buf: Value.ElemValueBuffer = undefined; | |
| 5318 | const mulend1_elem = mulend1.elemValueBuffer(mod, i, &mulend1_buf); | |
| 5319 | var mulend2_buf: Value.ElemValueBuffer = undefined; | |
| 5320 | const mulend2_elem = mulend2.elemValueBuffer(mod, i, &mulend2_buf); | |
| 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 | ); | |
| 4084 | const mulend1_elem = try mulend1.elemValue(mod, i); | |
| 4085 | const mulend2_elem = try mulend2.elemValue(mod, i); | |
| 4086 | const addend_elem = try addend.elemValue(mod, i); | |
| 4087 | scalar.* = try (try mulAddScalar(scalar_ty, mulend1_elem, mulend2_elem, addend_elem, mod)).intern(scalar_ty, mod); | |
| 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 | 4097 | pub fn mulAddScalar( |
| ... | ... | @@ -5339,54 +4099,33 @@ pub const Value = extern union { |
| 5339 | 4099 | mulend1: Value, |
| 5340 | 4100 | mulend2: Value, |
| 5341 | 4101 | addend: Value, |
| 5342 | arena: Allocator, | |
| 5343 | target: Target, | |
| 4102 | mod: *Module, | |
| 5344 | 4103 | ) Allocator.Error!Value { |
| 5345 | switch (float_type.floatBits(target)) { | |
| 5346 | 16 => { | |
| 5347 | const m1 = mulend1.toFloat(f16); | |
| 5348 | const m2 = mulend2.toFloat(f16); | |
| 5349 | const a = addend.toFloat(f16); | |
| 5350 | return Value.Tag.float_16.create(arena, @mulAdd(f16, m1, m2, a)); | |
| 5351 | }, | |
| 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 | }, | |
| 4104 | const target = mod.getTarget(); | |
| 4105 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 4106 | 16 => .{ .f16 = @mulAdd(f16, mulend1.toFloat(f16, mod), mulend2.toFloat(f16, mod), addend.toFloat(f16, mod)) }, | |
| 4107 | 32 => .{ .f32 = @mulAdd(f32, mulend1.toFloat(f32, mod), mulend2.toFloat(f32, mod), addend.toFloat(f32, mod)) }, | |
| 4108 | 64 => .{ .f64 = @mulAdd(f64, mulend1.toFloat(f64, mod), mulend2.toFloat(f64, mod), addend.toFloat(f64, mod)) }, | |
| 4109 | 80 => .{ .f80 = @mulAdd(f80, mulend1.toFloat(f80, mod), mulend2.toFloat(f80, mod), addend.toFloat(f80, mod)) }, | |
| 4110 | 128 => .{ .f128 = @mulAdd(f128, mulend1.toFloat(f128, mod), mulend2.toFloat(f128, mod), addend.toFloat(f128, mod)) }, | |
| 5376 | 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 | 4119 | /// If the value is represented in-memory as a series of bytes that all |
| 5381 | 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 { | |
| 5383 | const target = mod.getTarget(); | |
| 5384 | const abi_size = std.math.cast(usize, ty.abiSize(target)) orelse return null; | |
| 4121 | pub fn hasRepeatedByteRepr(val: Value, ty: Type, mod: *Module) !?Value { | |
| 4122 | const abi_size = std.math.cast(usize, ty.abiSize(mod)) orelse return null; | |
| 5385 | 4123 | assert(abi_size >= 1); |
| 5386 | 4124 | const byte_buffer = try mod.gpa.alloc(u8, abi_size); |
| 5387 | 4125 | defer mod.gpa.free(byte_buffer); |
| 5388 | 4126 | |
| 5389 | 4127 | writeToMemory(val, ty, mod, byte_buffer) catch |err| switch (err) { |
| 4128 | error.OutOfMemory => return error.OutOfMemory, | |
| 5390 | 4129 | error.ReinterpretDeclRef => return null, |
| 5391 | 4130 | // TODO: The writeToMemory function was originally created for the purpose |
| 5392 | 4131 | // of comptime pointer casting. However, it is now additionally being used |
| ... | ... | @@ -5400,118 +4139,22 @@ pub const Value = extern union { |
| 5400 | 4139 | for (byte_buffer[1..]) |byte| { |
| 5401 | 4140 | if (byte != first_byte) return null; |
| 5402 | 4141 | } |
| 5403 | value_buffer.* = .{ | |
| 5404 | .base = .{ .tag = .int_u64 }, | |
| 5405 | .data = first_byte, | |
| 5406 | }; | |
| 5407 | return initPayload(&value_buffer.base); | |
| 4142 | return try mod.intValue(Type.u8, first_byte); | |
| 4143 | } | |
| 4144 | ||
| 4145 | pub fn isGenericPoison(val: Value) bool { | |
| 4146 | return val.toIntern() == .generic_poison; | |
| 5408 | 4147 | } |
| 5409 | 4148 | |
| 5410 | 4149 | /// This type is not copyable since it may contain pointers to its inner data. |
| 5411 | 4150 | pub const Payload = struct { |
| 5412 | 4151 | tag: Tag, |
| 5413 | 4152 | |
| 5414 | pub const U32 = 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 { | |
| 4153 | pub const Slice = struct { | |
| 5489 | 4154 | base: Payload, |
| 5490 | 4155 | data: struct { |
| 5491 | field_val: Value, | |
| 5492 | field_ty: Type, | |
| 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, | |
| 4156 | ptr: Value, | |
| 4157 | len: Value, | |
| 5515 | 4158 | }, |
| 5516 | 4159 | }; |
| 5517 | 4160 | |
| ... | ... | @@ -5521,9 +4164,9 @@ pub const Value = extern union { |
| 5521 | 4164 | data: []const u8, |
| 5522 | 4165 | }; |
| 5523 | 4166 | |
| 5524 | pub const StrLit = struct { | |
| 4167 | pub const SubValue = struct { | |
| 5525 | 4168 | base: Payload, |
| 5526 | data: Module.StringLiteralContext.Key, | |
| 4169 | data: Value, | |
| 5527 | 4170 | }; |
| 5528 | 4171 | |
| 5529 | 4172 | pub const Aggregate = struct { |
| ... | ... | @@ -5533,156 +4176,42 @@ pub const Value = extern union { |
| 5533 | 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 | 4179 | pub const Union = struct { |
| 5643 | 4180 | pub const base_tag = Tag.@"union"; |
| 5644 | 4181 | |
| 5645 | 4182 | base: Payload = .{ .tag = base_tag }, |
| 5646 | data: struct { | |
| 4183 | data: Data, | |
| 4184 | ||
| 4185 | pub const Data = struct { | |
| 5647 | 4186 | tag: Value, |
| 5648 | 4187 | val: Value, |
| 5649 | }, | |
| 4188 | }; | |
| 5650 | 4189 | }; |
| 5651 | 4190 | }; |
| 5652 | 4191 | |
| 5653 | /// Big enough to fit any non-BigInt value | |
| 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 | }; | |
| 4192 | pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace; | |
| 5659 | 4193 | |
| 5660 | pub const zero = initTag(.zero); | |
| 5661 | pub const one = initTag(.one); | |
| 5662 | pub const negative_one: Value = .{ .ptr_otherwise = &negative_one_payload.base }; | |
| 5663 | pub const undef = initTag(.undef); | |
| 5664 | pub const @"void" = initTag(.void_value); | |
| 5665 | pub const @"null" = initTag(.null_value); | |
| 5666 | pub const @"false" = initTag(.bool_false); | |
| 5667 | pub const @"true" = initTag(.bool_true); | |
| 4194 | pub const zero_usize: Value = .{ .ip_index = .zero_usize, .legacy = undefined }; | |
| 4195 | pub const zero_u8: Value = .{ .ip_index = .zero_u8, .legacy = undefined }; | |
| 4196 | pub const zero_comptime_int: Value = .{ .ip_index = .zero, .legacy = undefined }; | |
| 4197 | pub const one_comptime_int: Value = .{ .ip_index = .one, .legacy = undefined }; | |
| 4198 | pub const negative_one_comptime_int: Value = .{ .ip_index = .negative_one, .legacy = undefined }; | |
| 4199 | pub const undef: Value = .{ .ip_index = .undef, .legacy = undefined }; | |
| 4200 | pub const @"void": Value = .{ .ip_index = .void_value, .legacy = undefined }; | |
| 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 | 4210 | pub fn makeBool(x: bool) Value { |
| 5670 | 4211 | return if (x) Value.true else Value.false; |
| 5671 | 4212 | } |
| 5672 | 4213 | |
| 5673 | pub fn boolToInt(x: bool) Value { | |
| 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 | }; | |
| 4214 | pub const RuntimeIndex = InternPool.RuntimeIndex; | |
| 5686 | 4215 | |
| 5687 | 4216 | /// This function is used in the debugger pretty formatters in tools/ to fetch the |
| 5688 | 4217 | /// Tag to Payload mapping to facilitate fancy debug printing for this type. |
| ... | ... | @@ -5691,7 +4220,7 @@ pub const Value = extern union { |
| 5691 | 4220 | var fields: [tags.len]std.builtin.Type.StructField = undefined; |
| 5692 | 4221 | for (&fields, tags) |*field, t| field.* = .{ |
| 5693 | 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 | 4224 | .default_value = null, |
| 5696 | 4225 | .is_comptime = false, |
| 5697 | 4226 | .alignment = 0, |
| ... | ... | @@ -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 | 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 18 | 18 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 19 | 19 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 20 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 20 | 21 | |
| 21 | 22 | var as = [_]A{ |
| 22 | 23 | A{ .B = B{ .D = 1 } }, |
test/behavior/bugs/6456.zig+1-1| ... | ... | @@ -24,7 +24,7 @@ test "issue 6456" { |
| 24 | 24 | .alignment = 0, |
| 25 | 25 | .name = name, |
| 26 | 26 | .type = usize, |
| 27 | .default_value = &@as(?usize, null), | |
| 27 | .default_value = null, | |
| 28 | 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 | 746 | try expect(error_set_info == .ErrorSet); |
| 747 | 747 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 748 | 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")); | |
| 750 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | |
| 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, "Three")); | |
| 751 | 751 | } |
| 752 | 752 | |
| 753 | 753 | { |
| ... | ... | @@ -756,8 +756,8 @@ test "peer type resolution: disjoint error sets" { |
| 756 | 756 | try expect(error_set_info == .ErrorSet); |
| 757 | 757 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 758 | 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")); | |
| 760 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | |
| 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, "Three")); | |
| 761 | 761 | } |
| 762 | 762 | } |
| 763 | 763 | |
| ... | ... | @@ -778,8 +778,8 @@ test "peer type resolution: error union and error set" { |
| 778 | 778 | const error_set_info = @typeInfo(info.ErrorUnion.error_set); |
| 779 | 779 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 780 | 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")); | |
| 782 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | |
| 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, "Three")); | |
| 783 | 783 | } |
| 784 | 784 | |
| 785 | 785 | { |
| ... | ... | @@ -790,8 +790,8 @@ test "peer type resolution: error union and error set" { |
| 790 | 790 | const error_set_info = @typeInfo(info.ErrorUnion.error_set); |
| 791 | 791 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 792 | 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")); | |
| 794 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | |
| 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, "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 | 214 | try expect(error_set_info == .ErrorSet); |
| 215 | 215 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 216 | 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")); | |
| 218 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | |
| 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, "Three")); | |
| 219 | 219 | } |
| 220 | 220 | |
| 221 | 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 | 9 | // target=native |
| 10 | 10 | // |
| 11 | 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 | 14 | // :2:5: error: found compile log statement |
| 15 | 15 | // |
| 16 | 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 | const Set1 = error {A, B}; | |
| 2 | const Set2 = error {A, C}; | |
| 1 | const Set1 = error{ A, B }; | |
| 2 | const Set2 = error{ A, C }; | |
| 3 | 3 | comptime { |
| 4 | 4 | var x = Set1.B; |
| 5 | 5 | var y = @errSetCast(Set2, x); |
| ... | ... | @@ -10,5 +10,4 @@ comptime { |
| 10 | 10 | // backend=stage2 |
| 11 | 11 | // target=native |
| 12 | 12 | // |
| 13 | // :5:13: error: 'error.B' not a member of error set 'error{A,C}' | |
| 14 | // :2:14: note: error set declared here | |
| 13 | // :5:13: error: 'error.B' not a member of error set 'error{C,A}' |
test/cases/compile_errors/implicit_cast_of_error_set_not_a_subset.zig+3-3| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | const Set1 = error{A, B}; | |
| 2 | const Set2 = error{A, C}; | |
| 1 | const Set1 = error{ A, B }; | |
| 2 | const Set2 = error{ A, C }; | |
| 3 | 3 | export fn entry() void { |
| 4 | 4 | foo(Set1.B); |
| 5 | 5 | } |
| ... | ... | @@ -12,5 +12,5 @@ fn foo(set1: Set1) void { |
| 12 | 12 | // backend=stage2 |
| 13 | 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 | 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 | 16 | // backend=llvm |
| 17 | 17 | // target=native |
| 18 | 18 | // |
| 19 | // :11:13: error: 'error.B' not a member of error set 'error{A,C}' | |
| 20 | // :5:14: note: error set declared here | |
| 19 | // :11:13: error: 'error.B' not a member of error set 'error{C,A}' |
test/cases/compile_errors/invalid_non-exhaustive_enum_to_union.zig+1-1| ... | ... | @@ -24,5 +24,5 @@ export fn bar() void { |
| 24 | 24 | // |
| 25 | 25 | // :12:16: error: runtime coercion to union 'tmp.U' from non-exhaustive enum |
| 26 | 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 | 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 | 16 | // backend=stage2 |
| 17 | 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 | 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 | 22 | // :6:31: note: cast discards const qualifier |
| 23 | 23 | // :11:19: error: expected type '*tmp.S', found '*const struct{comptime a: comptime_int = 2}' |
| 24 | 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 | test "example" { return 1; } | |
| 1 | test "example" { | |
| 2 | return 1; | |
| 3 | } | |
| 2 | 4 | |
| 3 | 5 | // error |
| 4 | 6 | // backend=stage2 |
| 5 | 7 | // target=native |
| 6 | 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 | 1 | test "enum" { |
| 2 | const E = enum(u8) {A, B, _}; | |
| 2 | const E = enum(u8) { A, B, _ }; | |
| 3 | 3 | _ = @tagName(@intToEnum(E, 5)); |
| 4 | 4 | } |
| 5 | 5 | |
| ... | ... | @@ -8,5 +8,5 @@ test "enum" { |
| 8 | 8 | // target=native |
| 9 | 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 | 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 | 41 | // :12:14: error: missing tuple field with index 1 |
| 42 | 42 | // :17:14: error: missing tuple field with index 1 |
| 43 | 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 | 7 | // backend=stage2 |
| 8 | 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 | 115 | try: return int(name.removeprefix('[').removesuffix(']')) |
| 116 | 116 | except: return -1 |
| 117 | 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 | 119 | try: return self.ptr.CreateChildAtOffset('[%d]' % index, index * self.elem_size, self.elem_type) |
| 120 | 120 | except: return None |
| 121 | 121 | |
| ... | ... | @@ -176,7 +176,7 @@ class zig_TaggedUnion_SynthProvider: |
| 176 | 176 | def get_child_index(self, name): |
| 177 | 177 | try: return ('tag', 'payload').index(name) |
| 178 | 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 | 181 | # Define Zig Standard Library |
| 182 | 182 | |
| ... | ... | @@ -196,7 +196,7 @@ class std_SegmentedList_SynthProvider: |
| 196 | 196 | except: return -1 |
| 197 | 197 | def get_child_at_index(self, index): |
| 198 | 198 | try: |
| 199 | if index < 0 or index >= self.len: return None | |
| 199 | if index not in range(self.len): return None | |
| 200 | 200 | prealloc_item_count = len(self.prealloc_segment) |
| 201 | 201 | if index < prealloc_item_count: return self.prealloc_segment.child[index] |
| 202 | 202 | prealloc_exp = prealloc_item_count.bit_length() - 1 |
| ... | ... | @@ -231,7 +231,7 @@ class std_MultiArrayList_SynthProvider: |
| 231 | 231 | except: return -1 |
| 232 | 232 | def get_child_at_index(self, index): |
| 233 | 233 | try: |
| 234 | if index < 0 or index >= self.len: return None | |
| 234 | if index not in range(self.len): return None | |
| 235 | 235 | offset = 0 |
| 236 | 236 | data = lldb.SBData() |
| 237 | 237 | for field in self.entry_type.fields: |
| ... | ... | @@ -266,7 +266,7 @@ class std_MultiArrayList_Slice_SynthProvider: |
| 266 | 266 | except: return -1 |
| 267 | 267 | def get_child_at_index(self, index): |
| 268 | 268 | try: |
| 269 | if index < 0 or index >= self.len: return None | |
| 269 | if index not in range(self.len): return None | |
| 270 | 270 | data = lldb.SBData() |
| 271 | 271 | for field in self.entry_type.fields: |
| 272 | 272 | field_type = field.type.GetPointeeType() |
| ... | ... | @@ -328,7 +328,7 @@ class std_Entry_SynthProvider: |
| 328 | 328 | def has_children(self): return self.num_children() != 0 |
| 329 | 329 | def num_children(self): return len(self.children) |
| 330 | 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 | 333 | # Define Zig Stage2 Compiler |
| 334 | 334 | |
| ... | ... | @@ -345,11 +345,17 @@ class TagAndPayload_SynthProvider: |
| 345 | 345 | def get_child_index(self, name): |
| 346 | 346 | try: return ('tag', 'payload').index(name) |
| 347 | 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 | 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 | 360 | class Module_Decl__Module_Decl_Index_SynthProvider: |
| 355 | 361 | def __init__(self, value, _=None): self.value = value |
| ... | ... | @@ -359,7 +365,7 @@ class Module_Decl__Module_Decl_Index_SynthProvider: |
| 359 | 365 | mod = frame.FindVariable('mod') or frame.FindVariable('module') |
| 360 | 366 | if mod: break |
| 361 | 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 | 369 | except: pass |
| 364 | 370 | def has_children(self): return True |
| 365 | 371 | def num_children(self): return 1 |
| ... | ... | @@ -392,7 +398,7 @@ class TagOrPayloadPtr_SynthProvider: |
| 392 | 398 | def get_child_index(self, name): |
| 393 | 399 | try: return ('tag', 'payload').index(name) |
| 394 | 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 | 403 | def Module_Decl_name(decl): |
| 398 | 404 | error = lldb.SBError() |
| ... | ... | @@ -407,6 +413,89 @@ def Module_Decl_RenderFullyQualifiedName(decl): return '.'.join((Module_Namespac |
| 407 | 413 | |
| 408 | 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 | 499 | def type_Type_pointer(payload): |
| 411 | 500 | pointee_type = payload.GetChildMemberWithName('pointee_type') |
| 412 | 501 | sentinel = payload.GetChildMemberWithName('sentinel').GetChildMemberWithName('child') |
| ... | ... | @@ -468,8 +557,8 @@ type_tag_handlers = { |
| 468 | 557 | 'empty_struct_literal': lambda payload: '@TypeOf(.{})', |
| 469 | 558 | |
| 470 | 559 | 'anyerror_void_error_union': lambda payload: 'anyerror!void', |
| 471 | 'const_slice_u8': lambda payload: '[]const u8', | |
| 472 | 'const_slice_u8_sentinel_0': lambda payload: '[:0]const u8', | |
| 560 | 'slice_const_u8': lambda payload: '[]const u8', | |
| 561 | 'slice_const_u8_sentinel_0': lambda payload: '[:0]const u8', | |
| 473 | 562 | 'fn_noreturn_no_args': lambda payload: 'fn() noreturn', |
| 474 | 563 | 'fn_void_no_args': lambda payload: 'fn() void', |
| 475 | 564 | 'fn_naked_noreturn_no_args': lambda payload: 'fn() callconv(.Naked) noreturn', |
| ... | ... | @@ -495,7 +584,7 @@ type_tag_handlers = { |
| 495 | 584 | 'many_mut_pointer': lambda payload: '[*]%s' % type_Type_SummaryProvider(payload), |
| 496 | 585 | 'c_const_pointer': lambda payload: '[*c]const %s' % type_Type_SummaryProvider(payload), |
| 497 | 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 | 588 | 'mut_slice': lambda payload: '[]%s' % type_Type_SummaryProvider(payload), |
| 500 | 589 | 'int_signed': lambda payload: 'i%d' % payload.unsigned, |
| 501 | 590 | 'int_unsigned': lambda payload: 'u%d' % payload.unsigned, |
| ... | ... | @@ -611,13 +700,19 @@ def __lldb_init_module(debugger, _=None): |
| 611 | 700 | add(debugger, category='zig.stage2', type='Zir.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) |
| 612 | 701 | add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Zir\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) |
| 613 | 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 | 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 | 706 | add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) |
| 617 | 707 | add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) |
| 618 | 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) | |
| 620 | add(debugger, category='zig.stage2', type='type.Type', summary=True) | |
| 621 | add(debugger, category='zig.stage2', type='value.Value', identifier='TagOrPayloadPtr', synth=True) | |
| 622 | add(debugger, category='zig.stage2', type='value.Value', summary=True) | |
| 709 | add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True) | |
| 710 | add(debugger, category='zig.stage2', type='InternPool.Index', synth=True) | |
| 711 | add(debugger, category='zig.stage2', type='InternPool.NullTerminatedString', 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 | 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 | 18 | 'many_mut_pointer': 'Type.Payload.ElemType', |
| 19 | 19 | 'c_const_pointer': 'Type.Payload.ElemType', |
| 20 | 20 | 'c_mut_pointer': 'Type.Payload.ElemType', |
| 21 | 'const_slice': 'Type.Payload.ElemType', | |
| 21 | 'slice_const': 'Type.Payload.ElemType', | |
| 22 | 22 | 'mut_slice': 'Type.Payload.ElemType', |
| 23 | 23 | 'optional': 'Type.Payload.ElemType', |
| 24 | 24 | 'optional_single_mut_pointer': 'Type.Payload.ElemType', |