| author | |
| committer | |
| log | dfd91abfe15e653cba7b61fef73340ea07c6e3e9 |
| tree | 574fbae55c7cf30d53994cd2e8be291c53411fb4 |
| parent | cbf304d8c3f7f1e1746a98dcad979ecf79ed16b5 |
7 files changed, 583 insertions(+), 113 deletions(-)
src/Air.zig+1-1| ... | @@ -1292,7 +1292,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type { | ... | @@ -1292,7 +1292,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type { |
| 1292 | .try_ptr, | 1292 | .try_ptr, |
| 1293 | => return air.getRefType(datas[inst].ty_pl.ty), | 1293 | => return air.getRefType(datas[inst].ty_pl.ty), |
| 1294 | 1294 | ||
| 1295 | .interned => return ip.indexToKey(datas[inst].interned).typeOf().toType(), | 1295 | .interned => return ip.typeOf(datas[inst].interned).toType(), |
| 1296 | 1296 | ||
| 1297 | .not, | 1297 | .not, |
| 1298 | .bitcast, | 1298 | .bitcast, |
src/InternPool.zig+207-69| ... | @@ -510,6 +510,16 @@ pub const Key = union(enum) { | ... | @@ -510,6 +510,16 @@ pub const Key = union(enum) { |
| 510 | runtime_index: RuntimeIndex, | 510 | runtime_index: RuntimeIndex, |
| 511 | }, | 511 | }, |
| 512 | int: Index, | 512 | int: Index, |
| 513 | eu_payload: Index, | ||
| 514 | opt_payload: Index, | ||
| 515 | comptime_field: Index, | ||
| 516 | elem: BaseIndex, | ||
| 517 | field: BaseIndex, | ||
| 518 | |||
| 519 | pub const BaseIndex = struct { | ||
| 520 | base: Index, | ||
| 521 | index: u64, | ||
| 522 | }; | ||
| 513 | }; | 523 | }; |
| 514 | }; | 524 | }; |
| 515 | 525 | ||
| ... | @@ -599,6 +609,7 @@ pub const Key = union(enum) { | ... | @@ -599,6 +609,7 @@ pub const Key = union(enum) { |
| 599 | 609 | ||
| 600 | .ptr => |ptr| { | 610 | .ptr => |ptr| { |
| 601 | std.hash.autoHash(hasher, ptr.ty); | 611 | std.hash.autoHash(hasher, ptr.ty); |
| 612 | std.hash.autoHash(hasher, ptr.len); | ||
| 602 | // Int-to-ptr pointers are hashed separately than decl-referencing pointers. | 613 | // Int-to-ptr pointers are hashed separately than decl-referencing pointers. |
| 603 | // This is sound due to pointer provenance rules. | 614 | // This is sound due to pointer provenance rules. |
| 604 | std.hash.autoHash(hasher, @as(@typeInfo(Key.Ptr.Addr).Union.tag_type.?, ptr.addr)); | 615 | std.hash.autoHash(hasher, @as(@typeInfo(Key.Ptr.Addr).Union.tag_type.?, ptr.addr)); |
| ... | @@ -607,6 +618,11 @@ pub const Key = union(enum) { | ... | @@ -607,6 +618,11 @@ pub const Key = union(enum) { |
| 607 | .decl => |decl| std.hash.autoHash(hasher, decl), | 618 | .decl => |decl| std.hash.autoHash(hasher, decl), |
| 608 | .mut_decl => |mut_decl| std.hash.autoHash(hasher, mut_decl), | 619 | .mut_decl => |mut_decl| std.hash.autoHash(hasher, mut_decl), |
| 609 | .int => |int| std.hash.autoHash(hasher, int), | 620 | .int => |int| std.hash.autoHash(hasher, int), |
| 621 | .eu_payload => |eu_payload| std.hash.autoHash(hasher, eu_payload), | ||
| 622 | .opt_payload => |opt_payload| std.hash.autoHash(hasher, opt_payload), | ||
| 623 | .comptime_field => |comptime_field| std.hash.autoHash(hasher, comptime_field), | ||
| 624 | .elem => |elem| std.hash.autoHash(hasher, elem), | ||
| 625 | .field => |field| std.hash.autoHash(hasher, field), | ||
| 610 | } | 626 | } |
| 611 | }, | 627 | }, |
| 612 | 628 | ||
| ... | @@ -719,7 +735,7 @@ pub const Key = union(enum) { | ... | @@ -719,7 +735,7 @@ pub const Key = union(enum) { |
| 719 | 735 | ||
| 720 | .ptr => |a_info| { | 736 | .ptr => |a_info| { |
| 721 | const b_info = b.ptr; | 737 | const b_info = b.ptr; |
| 722 | if (a_info.ty != b_info.ty) return false; | 738 | if (a_info.ty != b_info.ty or a_info.len != b_info.len) return false; |
| 723 | 739 | ||
| 724 | const AddrTag = @typeInfo(Key.Ptr.Addr).Union.tag_type.?; | 740 | const AddrTag = @typeInfo(Key.Ptr.Addr).Union.tag_type.?; |
| 725 | if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false; | 741 | if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false; |
| ... | @@ -729,6 +745,11 @@ pub const Key = union(enum) { | ... | @@ -729,6 +745,11 @@ pub const Key = union(enum) { |
| 729 | .decl => |a_decl| a_decl == b_info.addr.decl, | 745 | .decl => |a_decl| a_decl == b_info.addr.decl, |
| 730 | .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl), | 746 | .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl), |
| 731 | .int => |a_int| a_int == b_info.addr.int, | 747 | .int => |a_int| a_int == b_info.addr.int, |
| 748 | .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload, | ||
| 749 | .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload, | ||
| 750 | .comptime_field => |a_comptime_field| a_comptime_field == b_info.addr.comptime_field, | ||
| 751 | .elem => |a_elem| std.meta.eql(a_elem, b_info.addr.elem), | ||
| 752 | .field => |a_field| std.meta.eql(a_field, b_info.addr.field), | ||
| 732 | }; | 753 | }; |
| 733 | }, | 754 | }, |
| 734 | 755 | ||
| ... | @@ -1375,6 +1396,26 @@ pub const Tag = enum(u8) { | ... | @@ -1375,6 +1396,26 @@ pub const Tag = enum(u8) { |
| 1375 | /// Only pointer types are allowed to have this encoding. Optional types must use | 1396 | /// Only pointer types are allowed to have this encoding. Optional types must use |
| 1376 | /// `opt_payload` or `opt_null`. | 1397 | /// `opt_payload` or `opt_null`. |
| 1377 | ptr_int, | 1398 | ptr_int, |
| 1399 | /// A pointer to the payload of an error union. | ||
| 1400 | /// data is Index of a pointer value to the error union. | ||
| 1401 | /// In order to use this encoding, one must ensure that the `InternPool` | ||
| 1402 | /// already contains the payload pointer type corresponding to this payload. | ||
| 1403 | ptr_eu_payload, | ||
| 1404 | /// A pointer to the payload of an optional. | ||
| 1405 | /// data is Index of a pointer value to the optional. | ||
| 1406 | /// In order to use this encoding, one must ensure that the `InternPool` | ||
| 1407 | /// already contains the payload pointer type corresponding to this payload. | ||
| 1408 | ptr_opt_payload, | ||
| 1409 | /// data is extra index of PtrComptimeField, which contains the pointer type and field value. | ||
| 1410 | ptr_comptime_field, | ||
| 1411 | /// A pointer to an array element. | ||
| 1412 | /// data is extra index of PtrBaseIndex, which contains the base array and element index. | ||
| 1413 | /// In order to use this encoding, one must ensure that the `InternPool` | ||
| 1414 | /// already contains the elem pointer type corresponding to this payload. | ||
| 1415 | ptr_elem, | ||
| 1416 | /// A pointer to a container field. | ||
| 1417 | /// data is extra index of PtrBaseIndex, which contains the base container and field index. | ||
| 1418 | ptr_field, | ||
| 1378 | /// A slice. | 1419 | /// A slice. |
| 1379 | /// data is extra index of PtrSlice, which contains the ptr and len values | 1420 | /// data is extra index of PtrSlice, which contains the ptr and len values |
| 1380 | /// In order to use this encoding, one must ensure that the `InternPool` | 1421 | /// In order to use this encoding, one must ensure that the `InternPool` |
| ... | @@ -1753,6 +1794,17 @@ pub const PtrInt = struct { | ... | @@ -1753,6 +1794,17 @@ pub const PtrInt = struct { |
| 1753 | addr: Index, | 1794 | addr: Index, |
| 1754 | }; | 1795 | }; |
| 1755 | 1796 | ||
| 1797 | pub const PtrComptimeField = struct { | ||
| 1798 | ty: Index, | ||
| 1799 | field_val: Index, | ||
| 1800 | }; | ||
| 1801 | |||
| 1802 | pub const PtrBaseIndex = struct { | ||
| 1803 | ty: Index, | ||
| 1804 | base: Index, | ||
| 1805 | index: Index, | ||
| 1806 | }; | ||
| 1807 | |||
| 1756 | pub const PtrSlice = struct { | 1808 | pub const PtrSlice = struct { |
| 1757 | ptr: Index, | 1809 | ptr: Index, |
| 1758 | len: Index, | 1810 | len: Index, |
| ... | @@ -1956,10 +2008,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -1956,10 +2008,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1956 | }, | 2008 | }, |
| 1957 | 2009 | ||
| 1958 | .type_slice => { | 2010 | .type_slice => { |
| 1959 | const ptr_ty_index = @intToEnum(Index, data); | 2011 | const ptr_type_index = @intToEnum(Index, data); |
| 1960 | var result = indexToKey(ip, ptr_ty_index); | 2012 | var result = indexToKey(ip, ptr_type_index).ptr_type; |
| 1961 | result.ptr_type.size = .Slice; | 2013 | result.size = .Slice; |
| 1962 | return result; | 2014 | return .{ .ptr_type = result }; |
| 1963 | }, | 2015 | }, |
| 1964 | 2016 | ||
| 1965 | .type_optional => .{ .opt_type = @intToEnum(Index, data) }, | 2017 | .type_optional => .{ .opt_type = @intToEnum(Index, data) }, |
| ... | @@ -2063,7 +2115,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -2063,7 +2115,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2063 | // The existence of `opt_payload` guarantees that the optional type will be | 2115 | // The existence of `opt_payload` guarantees that the optional type will be |
| 2064 | // stored in the `InternPool`. | 2116 | // stored in the `InternPool`. |
| 2065 | const opt_ty = ip.getAssumeExists(.{ | 2117 | const opt_ty = ip.getAssumeExists(.{ |
| 2066 | .opt_type = indexToKey(ip, payload_val).typeOf(), | 2118 | .opt_type = ip.typeOf(payload_val), |
| 2067 | }); | 2119 | }); |
| 2068 | return .{ .opt = .{ | 2120 | return .{ .opt = .{ |
| 2069 | .ty = opt_ty, | 2121 | .ty = opt_ty, |
| ... | @@ -2108,14 +2160,59 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -2108,14 +2160,59 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2108 | .addr = .{ .int = info.addr }, | 2160 | .addr = .{ .int = info.addr }, |
| 2109 | } }; | 2161 | } }; |
| 2110 | }, | 2162 | }, |
| 2163 | .ptr_eu_payload => { | ||
| 2164 | const ptr_eu_index = @intToEnum(Index, data); | ||
| 2165 | var ptr_type = ip.indexToKey(ip.typeOf(ptr_eu_index)).ptr_type; | ||
| 2166 | ptr_type.elem_type = ip.indexToKey(ptr_type.elem_type).error_union_type.payload_type; | ||
| 2167 | return .{ .ptr = .{ | ||
| 2168 | .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }), | ||
| 2169 | .addr = .{ .eu_payload = ptr_eu_index }, | ||
| 2170 | } }; | ||
| 2171 | }, | ||
| 2172 | .ptr_opt_payload => { | ||
| 2173 | const ptr_opt_index = @intToEnum(Index, data); | ||
| 2174 | var ptr_type = ip.indexToKey(ip.typeOf(ptr_opt_index)).ptr_type; | ||
| 2175 | ptr_type.elem_type = ip.indexToKey(ptr_type.elem_type).opt_type; | ||
| 2176 | return .{ .ptr = .{ | ||
| 2177 | .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }), | ||
| 2178 | .addr = .{ .opt_payload = ptr_opt_index }, | ||
| 2179 | } }; | ||
| 2180 | }, | ||
| 2181 | .ptr_comptime_field => { | ||
| 2182 | const info = ip.extraData(PtrComptimeField, data); | ||
| 2183 | return .{ .ptr = .{ | ||
| 2184 | .ty = info.ty, | ||
| 2185 | .addr = .{ .comptime_field = info.field_val }, | ||
| 2186 | } }; | ||
| 2187 | }, | ||
| 2188 | .ptr_elem => { | ||
| 2189 | const info = ip.extraData(PtrBaseIndex, data); | ||
| 2190 | return .{ .ptr = .{ | ||
| 2191 | .ty = info.ty, | ||
| 2192 | .addr = .{ .elem = .{ | ||
| 2193 | .base = info.base, | ||
| 2194 | .index = ip.indexToKey(info.index).int.storage.u64, | ||
| 2195 | } }, | ||
| 2196 | } }; | ||
| 2197 | }, | ||
| 2198 | .ptr_field => { | ||
| 2199 | const info = ip.extraData(PtrBaseIndex, data); | ||
| 2200 | return .{ .ptr = .{ | ||
| 2201 | .ty = info.ty, | ||
| 2202 | .addr = .{ .field = .{ | ||
| 2203 | .base = info.base, | ||
| 2204 | .index = ip.indexToKey(info.index).int.storage.u64, | ||
| 2205 | } }, | ||
| 2206 | } }; | ||
| 2207 | }, | ||
| 2111 | .ptr_slice => { | 2208 | .ptr_slice => { |
| 2112 | const info = ip.extraData(PtrSlice, data); | 2209 | const info = ip.extraData(PtrSlice, data); |
| 2113 | const ptr = ip.indexToKey(info.ptr).ptr; | 2210 | const ptr = ip.indexToKey(info.ptr).ptr; |
| 2114 | var ptr_ty = ip.indexToKey(ptr.ty); | 2211 | var ptr_type = ip.indexToKey(ptr.ty).ptr_type; |
| 2115 | assert(ptr_ty.ptr_type.size == .Many); | 2212 | assert(ptr_type.size == .Many); |
| 2116 | ptr_ty.ptr_type.size = .Slice; | 2213 | ptr_type.size = .Slice; |
| 2117 | return .{ .ptr = .{ | 2214 | return .{ .ptr = .{ |
| 2118 | .ty = ip.getAssumeExists(ptr_ty), | 2215 | .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }), |
| 2119 | .addr = ptr.addr, | 2216 | .addr = ptr.addr, |
| 2120 | .len = info.len, | 2217 | .len = info.len, |
| 2121 | } }; | 2218 | } }; |
| ... | @@ -2301,9 +2398,7 @@ fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key { | ... | @@ -2301,9 +2398,7 @@ fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key { |
| 2301 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | 2398 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2302 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | 2399 | const adapter: KeyAdapter = .{ .intern_pool = ip }; |
| 2303 | const gop = try ip.map.getOrPutAdapted(gpa, key, adapter); | 2400 | const gop = try ip.map.getOrPutAdapted(gpa, key, adapter); |
| 2304 | if (gop.found_existing) { | 2401 | if (gop.found_existing) return @intToEnum(Index, gop.index); |
| 2305 | return @intToEnum(Index, gop.index); | ||
| 2306 | } | ||
| 2307 | try ip.items.ensureUnusedCapacity(gpa, 1); | 2402 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| 2308 | switch (key) { | 2403 | switch (key) { |
| 2309 | .int_type => |int_type| { | 2404 | .int_type => |int_type| { |
| ... | @@ -2322,11 +2417,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2322,11 +2417,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2322 | if (ptr_type.size == .Slice) { | 2417 | if (ptr_type.size == .Slice) { |
| 2323 | var new_key = key; | 2418 | var new_key = key; |
| 2324 | new_key.ptr_type.size = .Many; | 2419 | new_key.ptr_type.size = .Many; |
| 2325 | const ptr_ty_index = try get(ip, gpa, new_key); | 2420 | const ptr_type_index = try get(ip, gpa, new_key); |
| 2326 | try ip.items.ensureUnusedCapacity(gpa, 1); | 2421 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| 2327 | ip.items.appendAssumeCapacity(.{ | 2422 | ip.items.appendAssumeCapacity(.{ |
| 2328 | .tag = .type_slice, | 2423 | .tag = .type_slice, |
| 2329 | .data = @enumToInt(ptr_ty_index), | 2424 | .data = @enumToInt(ptr_type_index), |
| 2330 | }); | 2425 | }); |
| 2331 | return @intToEnum(Index, ip.items.len - 1); | 2426 | return @intToEnum(Index, ip.items.len - 1); |
| 2332 | } | 2427 | } |
| ... | @@ -2584,64 +2679,98 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2584,64 +2679,98 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2584 | 2679 | ||
| 2585 | .extern_func => @panic("TODO"), | 2680 | .extern_func => @panic("TODO"), |
| 2586 | 2681 | ||
| 2587 | .ptr => |ptr| switch (ptr.len) { | 2682 | .ptr => |ptr| { |
| 2588 | .none => { | 2683 | const ptr_type = ip.indexToKey(ptr.ty).ptr_type; |
| 2589 | assert(ip.indexToKey(ptr.ty).ptr_type.size != .Slice); | 2684 | switch (ptr.len) { |
| 2590 | switch (ptr.addr) { | 2685 | .none => { |
| 2591 | .@"var" => |@"var"| ip.items.appendAssumeCapacity(.{ | 2686 | assert(ptr_type.size != .Slice); |
| 2592 | .tag = .ptr_var, | 2687 | switch (ptr.addr) { |
| 2593 | .data = try ip.addExtra(gpa, PtrVar{ | 2688 | .@"var" => |@"var"| ip.items.appendAssumeCapacity(.{ |
| 2594 | .ty = ptr.ty, | 2689 | .tag = .ptr_var, |
| 2595 | .init = @"var".init, | 2690 | .data = try ip.addExtra(gpa, PtrVar{ |
| 2596 | .owner_decl = @"var".owner_decl, | 2691 | .ty = ptr.ty, |
| 2597 | .lib_name = @"var".lib_name, | 2692 | .init = @"var".init, |
| 2598 | .flags = .{ | 2693 | .owner_decl = @"var".owner_decl, |
| 2599 | .is_const = @"var".is_const, | 2694 | .lib_name = @"var".lib_name, |
| 2600 | .is_threadlocal = @"var".is_threadlocal, | 2695 | .flags = .{ |
| 2601 | .is_weak_linkage = @"var".is_weak_linkage, | 2696 | .is_const = @"var".is_const, |
| 2602 | }, | 2697 | .is_threadlocal = @"var".is_threadlocal, |
| 2698 | .is_weak_linkage = @"var".is_weak_linkage, | ||
| 2699 | }, | ||
| 2700 | }), | ||
| 2603 | }), | 2701 | }), |
| 2604 | }), | 2702 | .decl => |decl| ip.items.appendAssumeCapacity(.{ |
| 2605 | .decl => |decl| ip.items.appendAssumeCapacity(.{ | 2703 | .tag = .ptr_decl, |
| 2606 | .tag = .ptr_decl, | 2704 | .data = try ip.addExtra(gpa, PtrDecl{ |
| 2607 | .data = try ip.addExtra(gpa, PtrDecl{ | 2705 | .ty = ptr.ty, |
| 2608 | .ty = ptr.ty, | 2706 | .decl = decl, |
| 2609 | .decl = decl, | 2707 | }), |
| 2610 | }), | 2708 | }), |
| 2611 | }), | 2709 | .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{ |
| 2612 | .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{ | 2710 | .tag = .ptr_mut_decl, |
| 2613 | .tag = .ptr_mut_decl, | 2711 | .data = try ip.addExtra(gpa, PtrMutDecl{ |
| 2614 | .data = try ip.addExtra(gpa, PtrMutDecl{ | 2712 | .ty = ptr.ty, |
| 2615 | .ty = ptr.ty, | 2713 | .decl = mut_decl.decl, |
| 2616 | .decl = mut_decl.decl, | 2714 | .runtime_index = mut_decl.runtime_index, |
| 2617 | .runtime_index = mut_decl.runtime_index, | 2715 | }), |
| 2618 | }), | 2716 | }), |
| 2619 | }), | 2717 | .int => |int| ip.items.appendAssumeCapacity(.{ |
| 2620 | .int => |int| ip.items.appendAssumeCapacity(.{ | 2718 | .tag = .ptr_int, |
| 2621 | .tag = .ptr_int, | 2719 | .data = try ip.addExtra(gpa, PtrInt{ |
| 2622 | .data = try ip.addExtra(gpa, PtrInt{ | 2720 | .ty = ptr.ty, |
| 2623 | .ty = ptr.ty, | 2721 | .addr = int, |
| 2624 | .addr = int, | 2722 | }), |
| 2625 | }), | 2723 | }), |
| 2626 | }), | 2724 | .eu_payload, .opt_payload => |data| ip.items.appendAssumeCapacity(.{ |
| 2627 | } | 2725 | .tag = switch (ptr.addr) { |
| 2628 | }, | 2726 | .eu_payload => .ptr_eu_payload, |
| 2629 | else => { | 2727 | .opt_payload => .ptr_opt_payload, |
| 2630 | assert(ip.indexToKey(ptr.ty).ptr_type.size == .Slice); | 2728 | else => unreachable, |
| 2631 | var new_key = key; | 2729 | }, |
| 2632 | new_key.ptr.ty = ip.slicePtrType(ptr.ty); | 2730 | .data = @enumToInt(data), |
| 2633 | new_key.ptr.len = .none; | 2731 | }), |
| 2634 | assert(ip.indexToKey(new_key.ptr.ty).ptr_type.size == .Many); | 2732 | .comptime_field => |field_val| ip.items.appendAssumeCapacity(.{ |
| 2635 | const ptr_index = try get(ip, gpa, new_key); | 2733 | .tag = .ptr_comptime_field, |
| 2636 | try ip.items.ensureUnusedCapacity(gpa, 1); | 2734 | .data = try ip.addExtra(gpa, PtrComptimeField{ |
| 2637 | ip.items.appendAssumeCapacity(.{ | 2735 | .ty = ptr.ty, |
| 2638 | .tag = .ptr_slice, | 2736 | .field_val = field_val, |
| 2639 | .data = try ip.addExtra(gpa, PtrSlice{ | 2737 | }), |
| 2640 | .ptr = ptr_index, | 2738 | }), |
| 2641 | .len = ptr.len, | 2739 | .elem, .field => |base_index| { |
| 2642 | }), | 2740 | const index_index = try get(ip, gpa, .{ .int = .{ |
| 2643 | }); | 2741 | .ty = .usize_type, |
| 2644 | }, | 2742 | .storage = .{ .u64 = base_index.index }, |
| 2743 | } }); | ||
| 2744 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 2745 | ip.items.appendAssumeCapacity(.{ | ||
| 2746 | .tag = .ptr_elem, | ||
| 2747 | .data = try ip.addExtra(gpa, PtrBaseIndex{ | ||
| 2748 | .ty = ptr.ty, | ||
| 2749 | .base = base_index.base, | ||
| 2750 | .index = index_index, | ||
| 2751 | }), | ||
| 2752 | }); | ||
| 2753 | }, | ||
| 2754 | } | ||
| 2755 | }, | ||
| 2756 | else => { | ||
| 2757 | assert(ptr_type.size == .Slice); | ||
| 2758 | var new_key = key; | ||
| 2759 | new_key.ptr.ty = ip.slicePtrType(ptr.ty); | ||
| 2760 | new_key.ptr.len = .none; | ||
| 2761 | assert(ip.indexToKey(new_key.ptr.ty).ptr_type.size == .Many); | ||
| 2762 | const ptr_index = try get(ip, gpa, new_key); | ||
| 2763 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 2764 | ip.items.appendAssumeCapacity(.{ | ||
| 2765 | .tag = .ptr_slice, | ||
| 2766 | .data = try ip.addExtra(gpa, PtrSlice{ | ||
| 2767 | .ptr = ptr_index, | ||
| 2768 | .len = ptr.len, | ||
| 2769 | }), | ||
| 2770 | }); | ||
| 2771 | }, | ||
| 2772 | } | ||
| 2773 | assert(ptr.ty == ip.indexToKey(@intToEnum(Index, ip.items.len - 1)).ptr.ty); | ||
| 2645 | }, | 2774 | }, |
| 2646 | 2775 | ||
| 2647 | .opt => |opt| { | 2776 | .opt => |opt| { |
| ... | @@ -3683,6 +3812,11 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { | ... | @@ -3683,6 +3812,11 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3683 | .ptr_decl => @sizeOf(PtrDecl), | 3812 | .ptr_decl => @sizeOf(PtrDecl), |
| 3684 | .ptr_mut_decl => @sizeOf(PtrMutDecl), | 3813 | .ptr_mut_decl => @sizeOf(PtrMutDecl), |
| 3685 | .ptr_int => @sizeOf(PtrInt), | 3814 | .ptr_int => @sizeOf(PtrInt), |
| 3815 | .ptr_eu_payload => 0, | ||
| 3816 | .ptr_opt_payload => 0, | ||
| 3817 | .ptr_comptime_field => @sizeOf(PtrComptimeField), | ||
| 3818 | .ptr_elem => @sizeOf(PtrBaseIndex), | ||
| 3819 | .ptr_field => @sizeOf(PtrBaseIndex), | ||
| 3686 | .ptr_slice => @sizeOf(PtrSlice), | 3820 | .ptr_slice => @sizeOf(PtrSlice), |
| 3687 | .opt_null => 0, | 3821 | .opt_null => 0, |
| 3688 | .opt_payload => 0, | 3822 | .opt_payload => 0, |
| ... | @@ -3757,6 +3891,10 @@ pub fn unionPtr(ip: *InternPool, index: Module.Union.Index) *Module.Union { | ... | @@ -3757,6 +3891,10 @@ pub fn unionPtr(ip: *InternPool, index: Module.Union.Index) *Module.Union { |
| 3757 | return ip.allocated_unions.at(@enumToInt(index)); | 3891 | return ip.allocated_unions.at(@enumToInt(index)); |
| 3758 | } | 3892 | } |
| 3759 | 3893 | ||
| 3894 | pub fn unionPtrConst(ip: InternPool, index: Module.Union.Index) *const Module.Union { | ||
| 3895 | return ip.allocated_unions.at(@enumToInt(index)); | ||
| 3896 | } | ||
| 3897 | |||
| 3760 | pub fn inferredErrorSetPtr(ip: *InternPool, index: Module.Fn.InferredErrorSet.Index) *Module.Fn.InferredErrorSet { | 3898 | pub fn inferredErrorSetPtr(ip: *InternPool, index: Module.Fn.InferredErrorSet.Index) *Module.Fn.InferredErrorSet { |
| 3761 | return ip.allocated_inferred_error_sets.at(@enumToInt(index)); | 3899 | return ip.allocated_inferred_error_sets.at(@enumToInt(index)); |
| 3762 | } | 3900 | } |
src/Module.zig+2-2| ... | @@ -6783,7 +6783,7 @@ pub fn intType(mod: *Module, signedness: std.builtin.Signedness, bits: u16) Allo | ... | @@ -6783,7 +6783,7 @@ pub fn intType(mod: *Module, signedness: std.builtin.Signedness, bits: u16) Allo |
| 6783 | 6783 | ||
| 6784 | pub fn arrayType(mod: *Module, info: InternPool.Key.ArrayType) Allocator.Error!Type { | 6784 | pub fn arrayType(mod: *Module, info: InternPool.Key.ArrayType) Allocator.Error!Type { |
| 6785 | if (std.debug.runtime_safety and info.sentinel != .none) { | 6785 | if (std.debug.runtime_safety and info.sentinel != .none) { |
| 6786 | const sent_ty = mod.intern_pool.indexToKey(info.sentinel).typeOf(); | 6786 | const sent_ty = mod.intern_pool.typeOf(info.sentinel); |
| 6787 | assert(sent_ty == info.child); | 6787 | assert(sent_ty == info.child); |
| 6788 | } | 6788 | } |
| 6789 | const i = try intern(mod, .{ .array_type = info }); | 6789 | const i = try intern(mod, .{ .array_type = info }); |
| ... | @@ -6802,7 +6802,7 @@ pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error! | ... | @@ -6802,7 +6802,7 @@ pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error! |
| 6802 | 6802 | ||
| 6803 | pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { | 6803 | pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { |
| 6804 | if (std.debug.runtime_safety and info.sentinel != .none) { | 6804 | if (std.debug.runtime_safety and info.sentinel != .none) { |
| 6805 | const sent_ty = mod.intern_pool.indexToKey(info.sentinel).typeOf(); | 6805 | const sent_ty = mod.intern_pool.typeOf(info.sentinel); |
| 6806 | assert(sent_ty == info.elem_type); | 6806 | assert(sent_ty == info.elem_type); |
| 6807 | } | 6807 | } |
| 6808 | const i = try intern(mod, .{ .ptr_type = info }); | 6808 | const i = try intern(mod, .{ .ptr_type = info }); |
src/Sema.zig+186-8| ... | @@ -28473,6 +28473,178 @@ fn beginComptimePtrLoad( | ... | @@ -28473,6 +28473,178 @@ fn beginComptimePtrLoad( |
| 28473 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, | 28473 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, |
| 28474 | }; | 28474 | }; |
| 28475 | }, | 28475 | }, |
| 28476 | .eu_payload, .opt_payload => |container_ptr| blk: { | ||
| 28477 | const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod); | ||
| 28478 | const payload_ty = ptr.ty.toType().childType(mod); | ||
| 28479 | var deref = try sema.beginComptimePtrLoad(block, src, container_ptr.toValue(), container_ty); | ||
| 28480 | |||
| 28481 | // eu_payload_ptr and opt_payload_ptr never have a well-defined layout | ||
| 28482 | if (deref.parent != null) { | ||
| 28483 | deref.parent = null; | ||
| 28484 | deref.ty_without_well_defined_layout = container_ty; | ||
| 28485 | } | ||
| 28486 | |||
| 28487 | if (deref.pointee) |*tv| { | ||
| 28488 | const coerce_in_mem_ok = | ||
| 28489 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or | ||
| 28490 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; | ||
| 28491 | if (coerce_in_mem_ok) { | ||
| 28492 | const payload_val = switch (ptr_val.tag()) { | ||
| 28493 | .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else { | ||
| 28494 | return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name}); | ||
| 28495 | }, | ||
| 28496 | .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: { | ||
| 28497 | if (tv.val.isNull(mod)) return sema.fail(block, src, "attempt to use null value", .{}); | ||
| 28498 | break :opt tv.val; | ||
| 28499 | }, | ||
| 28500 | else => unreachable, | ||
| 28501 | }; | ||
| 28502 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; | ||
| 28503 | break :blk deref; | ||
| 28504 | } | ||
| 28505 | } | ||
| 28506 | deref.pointee = null; | ||
| 28507 | break :blk deref; | ||
| 28508 | }, | ||
| 28509 | .comptime_field => |comptime_field| blk: { | ||
| 28510 | const field_ty = mod.intern_pool.typeOf(comptime_field).toType(); | ||
| 28511 | break :blk ComptimePtrLoadKit{ | ||
| 28512 | .parent = null, | ||
| 28513 | .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() }, | ||
| 28514 | .is_mutable = false, | ||
| 28515 | .ty_without_well_defined_layout = field_ty, | ||
| 28516 | }; | ||
| 28517 | }, | ||
| 28518 | .elem => |elem_ptr| blk: { | ||
| 28519 | const elem_ty = ptr.ty.toType().childType(mod); | ||
| 28520 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null); | ||
| 28521 | |||
| 28522 | // This code assumes that elem_ptrs have been "flattened" in order for direct dereference | ||
| 28523 | // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that | ||
| 28524 | // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" | ||
| 28525 | switch (mod.intern_pool.indexToKey(elem_ptr.base)) { | ||
| 28526 | .ptr => |base_ptr| switch (base_ptr.addr) { | ||
| 28527 | .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)), | ||
| 28528 | else => {}, | ||
| 28529 | }, | ||
| 28530 | else => {}, | ||
| 28531 | } | ||
| 28532 | |||
| 28533 | if (elem_ptr.index != 0) { | ||
| 28534 | if (elem_ty.hasWellDefinedLayout(mod)) { | ||
| 28535 | if (deref.parent) |*parent| { | ||
| 28536 | // Update the byte offset (in-place) | ||
| 28537 | const elem_size = try sema.typeAbiSize(elem_ty); | ||
| 28538 | const offset = parent.byte_offset + elem_size * elem_ptr.index; | ||
| 28539 | parent.byte_offset = try sema.usizeCast(block, src, offset); | ||
| 28540 | } | ||
| 28541 | } else { | ||
| 28542 | deref.parent = null; | ||
| 28543 | deref.ty_without_well_defined_layout = elem_ty; | ||
| 28544 | } | ||
| 28545 | } | ||
| 28546 | |||
| 28547 | // If we're loading an elem that was derived from a different type | ||
| 28548 | // than the true type of the underlying decl, we cannot deref directly | ||
| 28549 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { | ||
| 28550 | const deref_elem_ty = deref.pointee.?.ty.childType(mod); | ||
| 28551 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or | ||
| 28552 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; | ||
| 28553 | } else false; | ||
| 28554 | if (!ty_matches) { | ||
| 28555 | deref.pointee = null; | ||
| 28556 | break :blk deref; | ||
| 28557 | } | ||
| 28558 | |||
| 28559 | var array_tv = deref.pointee.?; | ||
| 28560 | const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); | ||
| 28561 | if (maybe_array_ty) |load_ty| { | ||
| 28562 | // It's possible that we're loading a [N]T, in which case we'd like to slice | ||
| 28563 | // the pointee array directly from our parent array. | ||
| 28564 | if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) { | ||
| 28565 | const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod)); | ||
| 28566 | deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ | ||
| 28567 | .ty = try Type.array(sema.arena, N, null, elem_ty, mod), | ||
| 28568 | .val = try array_tv.val.sliceArray(mod, sema.arena, elem_ptr.index, elem_ptr.index + N), | ||
| 28569 | } else null; | ||
| 28570 | break :blk deref; | ||
| 28571 | } | ||
| 28572 | } | ||
| 28573 | |||
| 28574 | if (elem_ptr.index >= check_len) { | ||
| 28575 | deref.pointee = null; | ||
| 28576 | break :blk deref; | ||
| 28577 | } | ||
| 28578 | if (elem_ptr.index == check_len - 1) { | ||
| 28579 | if (array_tv.ty.sentinel(mod)) |sent| { | ||
| 28580 | deref.pointee = TypedValue{ | ||
| 28581 | .ty = elem_ty, | ||
| 28582 | .val = sent, | ||
| 28583 | }; | ||
| 28584 | break :blk deref; | ||
| 28585 | } | ||
| 28586 | } | ||
| 28587 | deref.pointee = TypedValue{ | ||
| 28588 | .ty = elem_ty, | ||
| 28589 | .val = try array_tv.val.elemValue(mod, elem_ptr.index), | ||
| 28590 | }; | ||
| 28591 | break :blk deref; | ||
| 28592 | }, | ||
| 28593 | .field => |field_ptr| blk: { | ||
| 28594 | const field_index = @intCast(u32, field_ptr.index); | ||
| 28595 | const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | ||
| 28596 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty); | ||
| 28597 | |||
| 28598 | if (container_ty.hasWellDefinedLayout(mod)) { | ||
| 28599 | const struct_obj = mod.typeToStruct(container_ty); | ||
| 28600 | if (struct_obj != null and struct_obj.?.layout == .Packed) { | ||
| 28601 | // packed structs are not byte addressable | ||
| 28602 | deref.parent = null; | ||
| 28603 | } else if (deref.parent) |*parent| { | ||
| 28604 | // Update the byte offset (in-place) | ||
| 28605 | try sema.resolveTypeLayout(container_ty); | ||
| 28606 | const field_offset = container_ty.structFieldOffset(field_index, mod); | ||
| 28607 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); | ||
| 28608 | } | ||
| 28609 | } else { | ||
| 28610 | deref.parent = null; | ||
| 28611 | deref.ty_without_well_defined_layout = container_ty; | ||
| 28612 | } | ||
| 28613 | |||
| 28614 | const tv = deref.pointee orelse { | ||
| 28615 | deref.pointee = null; | ||
| 28616 | break :blk deref; | ||
| 28617 | }; | ||
| 28618 | const coerce_in_mem_ok = | ||
| 28619 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or | ||
| 28620 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; | ||
| 28621 | if (!coerce_in_mem_ok) { | ||
| 28622 | deref.pointee = null; | ||
| 28623 | break :blk deref; | ||
| 28624 | } | ||
| 28625 | |||
| 28626 | if (container_ty.isSlice(mod)) { | ||
| 28627 | const slice_val = tv.val.castTag(.slice).?.data; | ||
| 28628 | deref.pointee = switch (field_index) { | ||
| 28629 | Value.Payload.Slice.ptr_index => TypedValue{ | ||
| 28630 | .ty = container_ty.slicePtrFieldType(mod), | ||
| 28631 | .val = slice_val.ptr, | ||
| 28632 | }, | ||
| 28633 | Value.Payload.Slice.len_index => TypedValue{ | ||
| 28634 | .ty = Type.usize, | ||
| 28635 | .val = slice_val.len, | ||
| 28636 | }, | ||
| 28637 | else => unreachable, | ||
| 28638 | }; | ||
| 28639 | } else { | ||
| 28640 | const field_ty = container_ty.structFieldType(field_index, mod); | ||
| 28641 | deref.pointee = TypedValue{ | ||
| 28642 | .ty = field_ty, | ||
| 28643 | .val = try tv.val.fieldValue(tv.ty, mod, field_index), | ||
| 28644 | }; | ||
| 28645 | } | ||
| 28646 | break :blk deref; | ||
| 28647 | }, | ||
| 28476 | }, | 28648 | }, |
| 28477 | else => unreachable, | 28649 | else => unreachable, |
| 28478 | }, | 28650 | }, |
| ... | @@ -28559,11 +28731,12 @@ fn coerceArrayPtrToSlice( | ... | @@ -28559,11 +28731,12 @@ fn coerceArrayPtrToSlice( |
| 28559 | if (try sema.resolveMaybeUndefVal(inst)) |val| { | 28731 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 28560 | const ptr_array_ty = sema.typeOf(inst); | 28732 | const ptr_array_ty = sema.typeOf(inst); |
| 28561 | const array_ty = ptr_array_ty.childType(mod); | 28733 | const array_ty = ptr_array_ty.childType(mod); |
| 28562 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | 28734 | const slice_val = try mod.intern(.{ .ptr = .{ |
| 28563 | .ptr = val, | 28735 | .ty = dest_ty.ip_index, |
| 28564 | .len = try mod.intValue(Type.usize, array_ty.arrayLen(mod)), | 28736 | .addr = mod.intern_pool.indexToKey(val.ip_index).ptr.addr, |
| 28565 | }); | 28737 | .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).ip_index, |
| 28566 | return sema.addConstant(dest_ty, slice_val); | 28738 | } }); |
| 28739 | return sema.addConstant(dest_ty, slice_val.toValue()); | ||
| 28567 | } | 28740 | } |
| 28568 | try sema.requireRuntimeBlock(block, inst_src, null); | 28741 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28569 | return block.addTyOp(.array_to_slice, dest_ty, inst); | 28742 | return block.addTyOp(.array_to_slice, dest_ty, inst); |
| ... | @@ -29769,6 +29942,7 @@ fn analyzeSlice( | ... | @@ -29769,6 +29942,7 @@ fn analyzeSlice( |
| 29769 | 29942 | ||
| 29770 | const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); | 29943 | const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); |
| 29771 | const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src); | 29944 | const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src); |
| 29945 | const new_ptr_ty = sema.typeOf(new_ptr); | ||
| 29772 | 29946 | ||
| 29773 | // true if and only if the end index of the slice, implicitly or explicitly, equals | 29947 | // true if and only if the end index of the slice, implicitly or explicitly, equals |
| 29774 | // the length of the underlying object being sliced. we might learn the length of the | 29948 | // the length of the underlying object being sliced. we might learn the length of the |
| ... | @@ -29914,7 +30088,7 @@ fn analyzeSlice( | ... | @@ -29914,7 +30088,7 @@ fn analyzeSlice( |
| 29914 | const end_int = end_val.getUnsignedInt(mod).?; | 30088 | const end_int = end_val.getUnsignedInt(mod).?; |
| 29915 | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); | 30089 | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); |
| 29916 | 30090 | ||
| 29917 | const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); | 30091 | const elem_ptr = try ptr_val.elemPtr(new_ptr_ty, sema.arena, sentinel_index, sema.mod); |
| 29918 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); | 30092 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); |
| 29919 | const actual_sentinel = switch (res) { | 30093 | const actual_sentinel = switch (res) { |
| 29920 | .runtime_load => break :sentinel_check, | 30094 | .runtime_load => break :sentinel_check, |
| ... | @@ -29960,7 +30134,7 @@ fn analyzeSlice( | ... | @@ -29960,7 +30134,7 @@ fn analyzeSlice( |
| 29960 | try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); | 30134 | try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); |
| 29961 | const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); | 30135 | const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); |
| 29962 | 30136 | ||
| 29963 | const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo(mod); | 30137 | const new_ptr_ty_info = new_ptr_ty.ptrInfo(mod); |
| 29964 | const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize(mod) != .C; | 30138 | const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize(mod) != .C; |
| 29965 | 30139 | ||
| 29966 | if (opt_new_len_val) |new_len_val| { | 30140 | if (opt_new_len_val) |new_len_val| { |
| ... | @@ -30009,7 +30183,11 @@ fn analyzeSlice( | ... | @@ -30009,7 +30183,11 @@ fn analyzeSlice( |
| 30009 | }; | 30183 | }; |
| 30010 | 30184 | ||
| 30011 | if (!new_ptr_val.isUndef(mod)) { | 30185 | if (!new_ptr_val.isUndef(mod)) { |
| 30012 | return sema.addConstant(return_ty, new_ptr_val); | 30186 | return sema.addConstant(return_ty, (try mod.intern_pool.getCoerced( |
| 30187 | mod.gpa, | ||
| 30188 | try new_ptr_val.intern(new_ptr_ty, mod), | ||
| 30189 | return_ty.ip_index, | ||
| 30190 | )).toValue()); | ||
| 30013 | } | 30191 | } |
| 30014 | 30192 | ||
| 30015 | // Special case: @as([]i32, undefined)[x..x] | 30193 | // Special case: @as([]i32, undefined)[x..x] |
src/codegen/llvm.zig+134-2| ... | @@ -3374,9 +3374,15 @@ pub const DeclGen = struct { | ... | @@ -3374,9 +3374,15 @@ pub const DeclGen = struct { |
| 3374 | val; | 3374 | val; |
| 3375 | break :ptr addrspace_casted_ptr; | 3375 | break :ptr addrspace_casted_ptr; |
| 3376 | }, | 3376 | }, |
| 3377 | .decl => |decl| try lowerDeclRefValue(dg, tv, decl), | 3377 | .decl => |decl| try dg.lowerDeclRefValue(tv, decl), |
| 3378 | .mut_decl => |mut_decl| try lowerDeclRefValue(dg, tv, mut_decl.decl), | 3378 | .mut_decl => |mut_decl| try dg.lowerDeclRefValue(tv, mut_decl.decl), |
| 3379 | .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int), | 3379 | .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int), |
| 3380 | .eu_payload, | ||
| 3381 | .opt_payload, | ||
| 3382 | .elem, | ||
| 3383 | .field, | ||
| 3384 | => try dg.lowerParentPtr(tv.val, tv.ty.ptrInfo(mod).bit_offset % 8 == 0), | ||
| 3385 | .comptime_field => unreachable, | ||
| 3380 | }; | 3386 | }; |
| 3381 | switch (ptr.len) { | 3387 | switch (ptr.len) { |
| 3382 | .none => return ptr_val, | 3388 | .none => return ptr_val, |
| ... | @@ -4091,6 +4097,132 @@ pub const DeclGen = struct { | ... | @@ -4091,6 +4097,132 @@ pub const DeclGen = struct { |
| 4091 | .decl => |decl| dg.lowerParentPtrDecl(ptr_val, decl), | 4097 | .decl => |decl| dg.lowerParentPtrDecl(ptr_val, decl), |
| 4092 | .mut_decl => |mut_decl| dg.lowerParentPtrDecl(ptr_val, mut_decl.decl), | 4098 | .mut_decl => |mut_decl| dg.lowerParentPtrDecl(ptr_val, mut_decl.decl), |
| 4093 | .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int), | 4099 | .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int), |
| 4100 | .eu_payload => |eu_ptr| { | ||
| 4101 | const parent_llvm_ptr = try dg.lowerParentPtr(eu_ptr.toValue(), true); | ||
| 4102 | |||
| 4103 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); | ||
| 4104 | const payload_ty = eu_ty.errorUnionPayload(mod); | ||
| 4105 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | ||
| 4106 | // In this case, we represent pointer to error union the same as pointer | ||
| 4107 | // to the payload. | ||
| 4108 | return parent_llvm_ptr; | ||
| 4109 | } | ||
| 4110 | |||
| 4111 | const payload_offset: u8 = if (payload_ty.abiAlignment(mod) > Type.anyerror.abiSize(mod)) 2 else 1; | ||
| 4112 | const llvm_u32 = dg.context.intType(32); | ||
| 4113 | const indices: [2]*llvm.Value = .{ | ||
| 4114 | llvm_u32.constInt(0, .False), | ||
| 4115 | llvm_u32.constInt(payload_offset, .False), | ||
| 4116 | }; | ||
| 4117 | const eu_llvm_ty = try dg.lowerType(eu_ty); | ||
| 4118 | return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4119 | }, | ||
| 4120 | .opt_payload => |opt_ptr| { | ||
| 4121 | const parent_llvm_ptr = try dg.lowerParentPtr(opt_ptr.toValue(), true); | ||
| 4122 | |||
| 4123 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); | ||
| 4124 | const payload_ty = opt_ty.optionalChild(mod); | ||
| 4125 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or | ||
| 4126 | payload_ty.optionalReprIsPayload(mod)) | ||
| 4127 | { | ||
| 4128 | // In this case, we represent pointer to optional the same as pointer | ||
| 4129 | // to the payload. | ||
| 4130 | return parent_llvm_ptr; | ||
| 4131 | } | ||
| 4132 | |||
| 4133 | const llvm_u32 = dg.context.intType(32); | ||
| 4134 | const indices: [2]*llvm.Value = .{ | ||
| 4135 | llvm_u32.constInt(0, .False), | ||
| 4136 | llvm_u32.constInt(0, .False), | ||
| 4137 | }; | ||
| 4138 | const opt_llvm_ty = try dg.lowerType(opt_ty); | ||
| 4139 | return opt_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4140 | }, | ||
| 4141 | .comptime_field => unreachable, | ||
| 4142 | .elem => |elem_ptr| { | ||
| 4143 | const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.base.toValue(), true); | ||
| 4144 | |||
| 4145 | const llvm_usize = try dg.lowerType(Type.usize); | ||
| 4146 | const indices: [1]*llvm.Value = .{ | ||
| 4147 | llvm_usize.constInt(elem_ptr.index, .False), | ||
| 4148 | }; | ||
| 4149 | const elem_llvm_ty = try dg.lowerType(ptr.ty.toType().childType(mod)); | ||
| 4150 | return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4151 | }, | ||
| 4152 | .field => |field_ptr| { | ||
| 4153 | const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.base.toValue(), byte_aligned); | ||
| 4154 | const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | ||
| 4155 | |||
| 4156 | const field_index = @intCast(u32, field_ptr.index); | ||
| 4157 | const llvm_u32 = dg.context.intType(32); | ||
| 4158 | switch (parent_ty.zigTypeTag(mod)) { | ||
| 4159 | .Union => { | ||
| 4160 | if (parent_ty.containerLayout(mod) == .Packed) { | ||
| 4161 | return parent_llvm_ptr; | ||
| 4162 | } | ||
| 4163 | |||
| 4164 | const layout = parent_ty.unionGetLayout(mod); | ||
| 4165 | if (layout.payload_size == 0) { | ||
| 4166 | // In this case a pointer to the union and a pointer to any | ||
| 4167 | // (void) payload is the same. | ||
| 4168 | return parent_llvm_ptr; | ||
| 4169 | } | ||
| 4170 | const llvm_pl_index = if (layout.tag_size == 0) | ||
| 4171 | 0 | ||
| 4172 | else | ||
| 4173 | @boolToInt(layout.tag_align >= layout.payload_align); | ||
| 4174 | const indices: [2]*llvm.Value = .{ | ||
| 4175 | llvm_u32.constInt(0, .False), | ||
| 4176 | llvm_u32.constInt(llvm_pl_index, .False), | ||
| 4177 | }; | ||
| 4178 | const parent_llvm_ty = try dg.lowerType(parent_ty); | ||
| 4179 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4180 | }, | ||
| 4181 | .Struct => { | ||
| 4182 | if (parent_ty.containerLayout(mod) == .Packed) { | ||
| 4183 | if (!byte_aligned) return parent_llvm_ptr; | ||
| 4184 | const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth()); | ||
| 4185 | const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); | ||
| 4186 | // count bits of fields before this one | ||
| 4187 | const prev_bits = b: { | ||
| 4188 | var b: usize = 0; | ||
| 4189 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { | ||
| 4190 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 4191 | b += @intCast(usize, field.ty.bitSize(mod)); | ||
| 4192 | } | ||
| 4193 | break :b b; | ||
| 4194 | }; | ||
| 4195 | const byte_offset = llvm_usize.constInt(prev_bits / 8, .False); | ||
| 4196 | const field_addr = base_addr.constAdd(byte_offset); | ||
| 4197 | const final_llvm_ty = dg.context.pointerType(0); | ||
| 4198 | return field_addr.constIntToPtr(final_llvm_ty); | ||
| 4199 | } | ||
| 4200 | |||
| 4201 | const parent_llvm_ty = try dg.lowerType(parent_ty); | ||
| 4202 | if (llvmField(parent_ty, field_index, mod)) |llvm_field| { | ||
| 4203 | const indices: [2]*llvm.Value = .{ | ||
| 4204 | llvm_u32.constInt(0, .False), | ||
| 4205 | llvm_u32.constInt(llvm_field.index, .False), | ||
| 4206 | }; | ||
| 4207 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4208 | } else { | ||
| 4209 | const llvm_index = llvm_u32.constInt(@boolToInt(parent_ty.hasRuntimeBitsIgnoreComptime(mod)), .False); | ||
| 4210 | const indices: [1]*llvm.Value = .{llvm_index}; | ||
| 4211 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4212 | } | ||
| 4213 | }, | ||
| 4214 | .Pointer => { | ||
| 4215 | assert(parent_ty.isSlice(mod)); | ||
| 4216 | const indices: [2]*llvm.Value = .{ | ||
| 4217 | llvm_u32.constInt(0, .False), | ||
| 4218 | llvm_u32.constInt(field_index, .False), | ||
| 4219 | }; | ||
| 4220 | const parent_llvm_ty = try dg.lowerType(parent_ty); | ||
| 4221 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4222 | }, | ||
| 4223 | else => unreachable, | ||
| 4224 | } | ||
| 4225 | }, | ||
| 4094 | }, | 4226 | }, |
| 4095 | else => unreachable, | 4227 | else => unreachable, |
| 4096 | }; | 4228 | }; |
src/print_zir.zig+1-1| ... | @@ -1192,7 +1192,7 @@ const Writer = struct { | ... | @@ -1192,7 +1192,7 @@ const Writer = struct { |
| 1192 | .field => { | 1192 | .field => { |
| 1193 | const field_name = self.code.nullTerminatedString(extra.data.field_name_start); | 1193 | const field_name = self.code.nullTerminatedString(extra.data.field_name_start); |
| 1194 | try self.writeInstRef(stream, extra.data.obj_ptr); | 1194 | try self.writeInstRef(stream, extra.data.obj_ptr); |
| 1195 | try stream.print(", {}", .{std.zig.fmtId(field_name)}); | 1195 | try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)}); |
| 1196 | }, | 1196 | }, |
| 1197 | } | 1197 | } |
| 1198 | try stream.writeAll(", ["); | 1198 | try stream.writeAll(", ["); |
src/value.zig+52-30| ... | @@ -559,37 +559,46 @@ pub const Value = struct { | ... | @@ -559,37 +559,46 @@ pub const Value = struct { |
| 559 | /// Asserts that the value is representable as an array of bytes. | 559 | /// Asserts that the value is representable as an array of bytes. |
| 560 | /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. | 560 | /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. |
| 561 | pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 { | 561 | pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 { |
| 562 | switch (val.tag()) { | 562 | switch (val.ip_index) { |
| 563 | .bytes => { | 563 | .none => switch (val.tag()) { |
| 564 | const bytes = val.castTag(.bytes).?.data; | 564 | .bytes => { |
| 565 | const adjusted_len = bytes.len - @boolToInt(ty.sentinel(mod) != null); | 565 | const bytes = val.castTag(.bytes).?.data; |
| 566 | const adjusted_bytes = bytes[0..adjusted_len]; | 566 | const adjusted_len = bytes.len - @boolToInt(ty.sentinel(mod) != null); |
| 567 | return allocator.dupe(u8, adjusted_bytes); | 567 | const adjusted_bytes = bytes[0..adjusted_len]; |
| 568 | }, | 568 | return allocator.dupe(u8, adjusted_bytes); |
| 569 | .str_lit => { | 569 | }, |
| 570 | const str_lit = val.castTag(.str_lit).?.data; | 570 | .str_lit => { |
| 571 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | 571 | const str_lit = val.castTag(.str_lit).?.data; |
| 572 | return allocator.dupe(u8, bytes); | 572 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; |
| 573 | }, | 573 | return allocator.dupe(u8, bytes); |
| 574 | .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data), | 574 | }, |
| 575 | .repeated => { | 575 | .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data), |
| 576 | const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt(mod)); | 576 | .repeated => { |
| 577 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); | 577 | const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt(mod)); |
| 578 | @memset(result, byte); | 578 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); |
| 579 | return result; | 579 | @memset(result, byte); |
| 580 | }, | 580 | return result; |
| 581 | .decl_ref => { | 581 | }, |
| 582 | const decl_index = val.castTag(.decl_ref).?.data; | 582 | .decl_ref => { |
| 583 | const decl = mod.declPtr(decl_index); | 583 | const decl_index = val.castTag(.decl_ref).?.data; |
| 584 | const decl_val = try decl.value(); | 584 | const decl = mod.declPtr(decl_index); |
| 585 | return decl_val.toAllocatedBytes(decl.ty, allocator, mod); | 585 | const decl_val = try decl.value(); |
| 586 | return decl_val.toAllocatedBytes(decl.ty, allocator, mod); | ||
| 587 | }, | ||
| 588 | .the_only_possible_value => return &[_]u8{}, | ||
| 589 | .slice => { | ||
| 590 | const slice = val.castTag(.slice).?.data; | ||
| 591 | return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(mod), allocator, mod); | ||
| 592 | }, | ||
| 593 | else => return arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod), | ||
| 586 | }, | 594 | }, |
| 587 | .the_only_possible_value => return &[_]u8{}, | 595 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 588 | .slice => { | 596 | .ptr => |ptr| switch (ptr.len) { |
| 589 | const slice = val.castTag(.slice).?.data; | 597 | .none => unreachable, |
| 590 | return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(mod), allocator, mod); | 598 | else => return arrayToAllocatedBytes(val, ptr.len.toValue().toUnsignedInt(mod), allocator, mod), |
| 599 | }, | ||
| 600 | else => unreachable, | ||
| 591 | }, | 601 | }, |
| 592 | else => return arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod), | ||
| 593 | } | 602 | } |
| 594 | } | 603 | } |
| 595 | 604 | ||
| ... | @@ -605,6 +614,16 @@ pub const Value = struct { | ... | @@ -605,6 +614,16 @@ pub const Value = struct { |
| 605 | pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { | 614 | pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { |
| 606 | if (val.ip_index != .none) return mod.intern_pool.getCoerced(mod.gpa, val.ip_index, ty.ip_index); | 615 | if (val.ip_index != .none) return mod.intern_pool.getCoerced(mod.gpa, val.ip_index, ty.ip_index); |
| 607 | switch (val.tag()) { | 616 | switch (val.tag()) { |
| 617 | .elem_ptr => { | ||
| 618 | const pl = val.castTag(.elem_ptr).?.data; | ||
| 619 | return mod.intern(.{ .ptr = .{ | ||
| 620 | .ty = ty.ip_index, | ||
| 621 | .addr = .{ .elem = .{ | ||
| 622 | .base = pl.array_ptr.ip_index, | ||
| 623 | .index = pl.index, | ||
| 624 | } }, | ||
| 625 | } }); | ||
| 626 | }, | ||
| 608 | .slice => { | 627 | .slice => { |
| 609 | const pl = val.castTag(.slice).?.data; | 628 | const pl = val.castTag(.slice).?.data; |
| 610 | const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod); | 629 | const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod); |
| ... | @@ -2601,7 +2620,10 @@ pub const Value = struct { | ... | @@ -2601,7 +2620,10 @@ pub const Value = struct { |
| 2601 | .@"var" => unreachable, | 2620 | .@"var" => unreachable, |
| 2602 | .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), | 2621 | .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), |
| 2603 | .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index), | 2622 | .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index), |
| 2604 | .int => unreachable, | 2623 | .int, .eu_payload, .opt_payload => unreachable, |
| 2624 | .comptime_field => |field_val| field_val.toValue().elemValue(mod, index), | ||
| 2625 | .elem => |elem| elem.base.toValue().elemValue(mod, index + elem.index), | ||
| 2626 | .field => unreachable, | ||
| 2605 | }, | 2627 | }, |
| 2606 | .aggregate => |aggregate| switch (aggregate.storage) { | 2628 | .aggregate => |aggregate| switch (aggregate.storage) { |
| 2607 | .elems => |elems| elems[index].toValue(), | 2629 | .elems => |elems| elems[index].toValue(), |