| 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 | 1292 | .try_ptr, |
| 1293 | 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 | 1297 | .not, |
| 1298 | 1298 | .bitcast, |
src/InternPool.zig+207-69| ... | ... | @@ -510,6 +510,16 @@ pub const Key = union(enum) { |
| 510 | 510 | runtime_index: RuntimeIndex, |
| 511 | 511 | }, |
| 512 | 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 | 609 | |
| 600 | 610 | .ptr => |ptr| { |
| 601 | 611 | std.hash.autoHash(hasher, ptr.ty); |
| 612 | std.hash.autoHash(hasher, ptr.len); | |
| 602 | 613 | // Int-to-ptr pointers are hashed separately than decl-referencing pointers. |
| 603 | 614 | // This is sound due to pointer provenance rules. |
| 604 | 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 | 618 | .decl => |decl| std.hash.autoHash(hasher, decl), |
| 608 | 619 | .mut_decl => |mut_decl| std.hash.autoHash(hasher, mut_decl), |
| 609 | 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 | 735 | |
| 720 | 736 | .ptr => |a_info| { |
| 721 | 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 | 740 | const AddrTag = @typeInfo(Key.Ptr.Addr).Union.tag_type.?; |
| 725 | 741 | if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false; |
| ... | ... | @@ -729,6 +745,11 @@ pub const Key = union(enum) { |
| 729 | 745 | .decl => |a_decl| a_decl == b_info.addr.decl, |
| 730 | 746 | .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl), |
| 731 | 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 | 1396 | /// Only pointer types are allowed to have this encoding. Optional types must use |
| 1376 | 1397 | /// `opt_payload` or `opt_null`. |
| 1377 | 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 | 1419 | /// A slice. |
| 1379 | 1420 | /// data is extra index of PtrSlice, which contains the ptr and len values |
| 1380 | 1421 | /// In order to use this encoding, one must ensure that the `InternPool` |
| ... | ... | @@ -1753,6 +1794,17 @@ pub const PtrInt = struct { |
| 1753 | 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 | 1808 | pub const PtrSlice = struct { |
| 1757 | 1809 | ptr: Index, |
| 1758 | 1810 | len: Index, |
| ... | ... | @@ -1956,10 +2008,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1956 | 2008 | }, |
| 1957 | 2009 | |
| 1958 | 2010 | .type_slice => { |
| 1959 | const ptr_ty_index = @intToEnum(Index, data); | |
| 1960 | var result = indexToKey(ip, ptr_ty_index); | |
| 1961 | result.ptr_type.size = .Slice; | |
| 1962 | return result; | |
| 2011 | const ptr_type_index = @intToEnum(Index, data); | |
| 2012 | var result = indexToKey(ip, ptr_type_index).ptr_type; | |
| 2013 | result.size = .Slice; | |
| 2014 | return .{ .ptr_type = result }; | |
| 1963 | 2015 | }, |
| 1964 | 2016 | |
| 1965 | 2017 | .type_optional => .{ .opt_type = @intToEnum(Index, data) }, |
| ... | ... | @@ -2063,7 +2115,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2063 | 2115 | // The existence of `opt_payload` guarantees that the optional type will be |
| 2064 | 2116 | // stored in the `InternPool`. |
| 2065 | 2117 | const opt_ty = ip.getAssumeExists(.{ |
| 2066 | .opt_type = indexToKey(ip, payload_val).typeOf(), | |
| 2118 | .opt_type = ip.typeOf(payload_val), | |
| 2067 | 2119 | }); |
| 2068 | 2120 | return .{ .opt = .{ |
| 2069 | 2121 | .ty = opt_ty, |
| ... | ... | @@ -2108,14 +2160,59 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2108 | 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 | 2208 | .ptr_slice => { |
| 2112 | 2209 | const info = ip.extraData(PtrSlice, data); |
| 2113 | 2210 | const ptr = ip.indexToKey(info.ptr).ptr; |
| 2114 | var ptr_ty = ip.indexToKey(ptr.ty); | |
| 2115 | assert(ptr_ty.ptr_type.size == .Many); | |
| 2116 | ptr_ty.ptr_type.size = .Slice; | |
| 2211 | var ptr_type = ip.indexToKey(ptr.ty).ptr_type; | |
| 2212 | assert(ptr_type.size == .Many); | |
| 2213 | ptr_type.size = .Slice; | |
| 2117 | 2214 | return .{ .ptr = .{ |
| 2118 | .ty = ip.getAssumeExists(ptr_ty), | |
| 2215 | .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }), | |
| 2119 | 2216 | .addr = ptr.addr, |
| 2120 | 2217 | .len = info.len, |
| 2121 | 2218 | } }; |
| ... | ... | @@ -2301,9 +2398,7 @@ fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key { |
| 2301 | 2398 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2302 | 2399 | const adapter: KeyAdapter = .{ .intern_pool = ip }; |
| 2303 | 2400 | const gop = try ip.map.getOrPutAdapted(gpa, key, adapter); |
| 2304 | if (gop.found_existing) { | |
| 2305 | return @intToEnum(Index, gop.index); | |
| 2306 | } | |
| 2401 | if (gop.found_existing) return @intToEnum(Index, gop.index); | |
| 2307 | 2402 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| 2308 | 2403 | switch (key) { |
| 2309 | 2404 | .int_type => |int_type| { |
| ... | ... | @@ -2322,11 +2417,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2322 | 2417 | if (ptr_type.size == .Slice) { |
| 2323 | 2418 | var new_key = key; |
| 2324 | 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 | 2421 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| 2327 | 2422 | ip.items.appendAssumeCapacity(.{ |
| 2328 | 2423 | .tag = .type_slice, |
| 2329 | .data = @enumToInt(ptr_ty_index), | |
| 2424 | .data = @enumToInt(ptr_type_index), | |
| 2330 | 2425 | }); |
| 2331 | 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 | 2679 | |
| 2585 | 2680 | .extern_func => @panic("TODO"), |
| 2586 | 2681 | |
| 2587 | .ptr => |ptr| switch (ptr.len) { | |
| 2588 | .none => { | |
| 2589 | assert(ip.indexToKey(ptr.ty).ptr_type.size != .Slice); | |
| 2590 | switch (ptr.addr) { | |
| 2591 | .@"var" => |@"var"| ip.items.appendAssumeCapacity(.{ | |
| 2592 | .tag = .ptr_var, | |
| 2593 | .data = try ip.addExtra(gpa, PtrVar{ | |
| 2594 | .ty = ptr.ty, | |
| 2595 | .init = @"var".init, | |
| 2596 | .owner_decl = @"var".owner_decl, | |
| 2597 | .lib_name = @"var".lib_name, | |
| 2598 | .flags = .{ | |
| 2599 | .is_const = @"var".is_const, | |
| 2600 | .is_threadlocal = @"var".is_threadlocal, | |
| 2601 | .is_weak_linkage = @"var".is_weak_linkage, | |
| 2602 | }, | |
| 2682 | .ptr => |ptr| { | |
| 2683 | const ptr_type = ip.indexToKey(ptr.ty).ptr_type; | |
| 2684 | switch (ptr.len) { | |
| 2685 | .none => { | |
| 2686 | assert(ptr_type.size != .Slice); | |
| 2687 | switch (ptr.addr) { | |
| 2688 | .@"var" => |@"var"| ip.items.appendAssumeCapacity(.{ | |
| 2689 | .tag = .ptr_var, | |
| 2690 | .data = try ip.addExtra(gpa, PtrVar{ | |
| 2691 | .ty = ptr.ty, | |
| 2692 | .init = @"var".init, | |
| 2693 | .owner_decl = @"var".owner_decl, | |
| 2694 | .lib_name = @"var".lib_name, | |
| 2695 | .flags = .{ | |
| 2696 | .is_const = @"var".is_const, | |
| 2697 | .is_threadlocal = @"var".is_threadlocal, | |
| 2698 | .is_weak_linkage = @"var".is_weak_linkage, | |
| 2699 | }, | |
| 2700 | }), | |
| 2603 | 2701 | }), |
| 2604 | }), | |
| 2605 | .decl => |decl| ip.items.appendAssumeCapacity(.{ | |
| 2606 | .tag = .ptr_decl, | |
| 2607 | .data = try ip.addExtra(gpa, PtrDecl{ | |
| 2608 | .ty = ptr.ty, | |
| 2609 | .decl = decl, | |
| 2702 | .decl => |decl| ip.items.appendAssumeCapacity(.{ | |
| 2703 | .tag = .ptr_decl, | |
| 2704 | .data = try ip.addExtra(gpa, PtrDecl{ | |
| 2705 | .ty = ptr.ty, | |
| 2706 | .decl = decl, | |
| 2707 | }), | |
| 2610 | 2708 | }), |
| 2611 | }), | |
| 2612 | .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{ | |
| 2613 | .tag = .ptr_mut_decl, | |
| 2614 | .data = try ip.addExtra(gpa, PtrMutDecl{ | |
| 2615 | .ty = ptr.ty, | |
| 2616 | .decl = mut_decl.decl, | |
| 2617 | .runtime_index = mut_decl.runtime_index, | |
| 2709 | .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{ | |
| 2710 | .tag = .ptr_mut_decl, | |
| 2711 | .data = try ip.addExtra(gpa, PtrMutDecl{ | |
| 2712 | .ty = ptr.ty, | |
| 2713 | .decl = mut_decl.decl, | |
| 2714 | .runtime_index = mut_decl.runtime_index, | |
| 2715 | }), | |
| 2618 | 2716 | }), |
| 2619 | }), | |
| 2620 | .int => |int| ip.items.appendAssumeCapacity(.{ | |
| 2621 | .tag = .ptr_int, | |
| 2622 | .data = try ip.addExtra(gpa, PtrInt{ | |
| 2623 | .ty = ptr.ty, | |
| 2624 | .addr = int, | |
| 2717 | .int => |int| ip.items.appendAssumeCapacity(.{ | |
| 2718 | .tag = .ptr_int, | |
| 2719 | .data = try ip.addExtra(gpa, PtrInt{ | |
| 2720 | .ty = ptr.ty, | |
| 2721 | .addr = int, | |
| 2722 | }), | |
| 2625 | 2723 | }), |
| 2626 | }), | |
| 2627 | } | |
| 2628 | }, | |
| 2629 | else => { | |
| 2630 | assert(ip.indexToKey(ptr.ty).ptr_type.size == .Slice); | |
| 2631 | var new_key = key; | |
| 2632 | new_key.ptr.ty = ip.slicePtrType(ptr.ty); | |
| 2633 | new_key.ptr.len = .none; | |
| 2634 | assert(ip.indexToKey(new_key.ptr.ty).ptr_type.size == .Many); | |
| 2635 | const ptr_index = try get(ip, gpa, new_key); | |
| 2636 | try ip.items.ensureUnusedCapacity(gpa, 1); | |
| 2637 | ip.items.appendAssumeCapacity(.{ | |
| 2638 | .tag = .ptr_slice, | |
| 2639 | .data = try ip.addExtra(gpa, PtrSlice{ | |
| 2640 | .ptr = ptr_index, | |
| 2641 | .len = ptr.len, | |
| 2642 | }), | |
| 2643 | }); | |
| 2644 | }, | |
| 2724 | .eu_payload, .opt_payload => |data| ip.items.appendAssumeCapacity(.{ | |
| 2725 | .tag = switch (ptr.addr) { | |
| 2726 | .eu_payload => .ptr_eu_payload, | |
| 2727 | .opt_payload => .ptr_opt_payload, | |
| 2728 | else => unreachable, | |
| 2729 | }, | |
| 2730 | .data = @enumToInt(data), | |
| 2731 | }), | |
| 2732 | .comptime_field => |field_val| ip.items.appendAssumeCapacity(.{ | |
| 2733 | .tag = .ptr_comptime_field, | |
| 2734 | .data = try ip.addExtra(gpa, PtrComptimeField{ | |
| 2735 | .ty = ptr.ty, | |
| 2736 | .field_val = field_val, | |
| 2737 | }), | |
| 2738 | }), | |
| 2739 | .elem, .field => |base_index| { | |
| 2740 | const index_index = try get(ip, gpa, .{ .int = .{ | |
| 2741 | .ty = .usize_type, | |
| 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 | 2776 | .opt => |opt| { |
| ... | ... | @@ -3683,6 +3812,11 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3683 | 3812 | .ptr_decl => @sizeOf(PtrDecl), |
| 3684 | 3813 | .ptr_mut_decl => @sizeOf(PtrMutDecl), |
| 3685 | 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 | 3820 | .ptr_slice => @sizeOf(PtrSlice), |
| 3687 | 3821 | .opt_null => 0, |
| 3688 | 3822 | .opt_payload => 0, |
| ... | ... | @@ -3757,6 +3891,10 @@ pub fn unionPtr(ip: *InternPool, index: Module.Union.Index) *Module.Union { |
| 3757 | 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 | 3898 | pub fn inferredErrorSetPtr(ip: *InternPool, index: Module.Fn.InferredErrorSet.Index) *Module.Fn.InferredErrorSet { |
| 3761 | 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 | 6783 | |
| 6784 | 6784 | pub fn arrayType(mod: *Module, info: InternPool.Key.ArrayType) Allocator.Error!Type { |
| 6785 | 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 | 6787 | assert(sent_ty == info.child); |
| 6788 | 6788 | } |
| 6789 | 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 | 6802 | |
| 6803 | 6803 | pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { |
| 6804 | 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 | 6806 | assert(sent_ty == info.elem_type); |
| 6807 | 6807 | } |
| 6808 | 6808 | const i = try intern(mod, .{ .ptr_type = info }); |
src/Sema.zig+186-8| ... | ... | @@ -28473,6 +28473,178 @@ fn beginComptimePtrLoad( |
| 28473 | 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 | 28649 | else => unreachable, |
| 28478 | 28650 | }, |
| ... | ... | @@ -28559,11 +28731,12 @@ fn coerceArrayPtrToSlice( |
| 28559 | 28731 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 28560 | 28732 | const ptr_array_ty = sema.typeOf(inst); |
| 28561 | 28733 | const array_ty = ptr_array_ty.childType(mod); |
| 28562 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | |
| 28563 | .ptr = val, | |
| 28564 | .len = try mod.intValue(Type.usize, array_ty.arrayLen(mod)), | |
| 28565 | }); | |
| 28566 | return sema.addConstant(dest_ty, slice_val); | |
| 28734 | const slice_val = try mod.intern(.{ .ptr = .{ | |
| 28735 | .ty = dest_ty.ip_index, | |
| 28736 | .addr = mod.intern_pool.indexToKey(val.ip_index).ptr.addr, | |
| 28737 | .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).ip_index, | |
| 28738 | } }); | |
| 28739 | return sema.addConstant(dest_ty, slice_val.toValue()); | |
| 28567 | 28740 | } |
| 28568 | 28741 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28569 | 28742 | return block.addTyOp(.array_to_slice, dest_ty, inst); |
| ... | ... | @@ -29769,6 +29942,7 @@ fn analyzeSlice( |
| 29769 | 29942 | |
| 29770 | 29943 | const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); |
| 29771 | 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 | 29947 | // true if and only if the end index of the slice, implicitly or explicitly, equals |
| 29774 | 29948 | // the length of the underlying object being sliced. we might learn the length of the |
| ... | ... | @@ -29914,7 +30088,7 @@ fn analyzeSlice( |
| 29914 | 30088 | const end_int = end_val.getUnsignedInt(mod).?; |
| 29915 | 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 | 30092 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); |
| 29919 | 30093 | const actual_sentinel = switch (res) { |
| 29920 | 30094 | .runtime_load => break :sentinel_check, |
| ... | ... | @@ -29960,7 +30134,7 @@ fn analyzeSlice( |
| 29960 | 30134 | try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); |
| 29961 | 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 | 30138 | const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize(mod) != .C; |
| 29965 | 30139 | |
| 29966 | 30140 | if (opt_new_len_val) |new_len_val| { |
| ... | ... | @@ -30009,7 +30183,11 @@ fn analyzeSlice( |
| 30009 | 30183 | }; |
| 30010 | 30184 | |
| 30011 | 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 | 30193 | // Special case: @as([]i32, undefined)[x..x] |
src/codegen/llvm.zig+134-2| ... | ... | @@ -3374,9 +3374,15 @@ pub const DeclGen = struct { |
| 3374 | 3374 | val; |
| 3375 | 3375 | break :ptr addrspace_casted_ptr; |
| 3376 | 3376 | }, |
| 3377 | .decl => |decl| try lowerDeclRefValue(dg, tv, decl), | |
| 3378 | .mut_decl => |mut_decl| try lowerDeclRefValue(dg, tv, mut_decl.decl), | |
| 3377 | .decl => |decl| try dg.lowerDeclRefValue(tv, decl), | |
| 3378 | .mut_decl => |mut_decl| try dg.lowerDeclRefValue(tv, mut_decl.decl), | |
| 3379 | 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 | 3387 | switch (ptr.len) { |
| 3382 | 3388 | .none => return ptr_val, |
| ... | ... | @@ -4091,6 +4097,132 @@ pub const DeclGen = struct { |
| 4091 | 4097 | .decl => |decl| dg.lowerParentPtrDecl(ptr_val, decl), |
| 4092 | 4098 | .mut_decl => |mut_decl| dg.lowerParentPtrDecl(ptr_val, mut_decl.decl), |
| 4093 | 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 | 4227 | else => unreachable, |
| 4096 | 4228 | }; |
src/print_zir.zig+1-1| ... | ... | @@ -1192,7 +1192,7 @@ const Writer = struct { |
| 1192 | 1192 | .field => { |
| 1193 | 1193 | const field_name = self.code.nullTerminatedString(extra.data.field_name_start); |
| 1194 | 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 | 1198 | try stream.writeAll(", ["); |
src/value.zig+52-30| ... | ... | @@ -559,37 +559,46 @@ pub const Value = struct { |
| 559 | 559 | /// Asserts that the value is representable as an array of bytes. |
| 560 | 560 | /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. |
| 561 | 561 | pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 { |
| 562 | switch (val.tag()) { | |
| 563 | .bytes => { | |
| 564 | const bytes = val.castTag(.bytes).?.data; | |
| 565 | const adjusted_len = bytes.len - @boolToInt(ty.sentinel(mod) != null); | |
| 566 | const adjusted_bytes = bytes[0..adjusted_len]; | |
| 567 | return allocator.dupe(u8, adjusted_bytes); | |
| 568 | }, | |
| 569 | .str_lit => { | |
| 570 | const str_lit = val.castTag(.str_lit).?.data; | |
| 571 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 572 | return allocator.dupe(u8, bytes); | |
| 573 | }, | |
| 574 | .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data), | |
| 575 | .repeated => { | |
| 576 | const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt(mod)); | |
| 577 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); | |
| 578 | @memset(result, byte); | |
| 579 | return result; | |
| 580 | }, | |
| 581 | .decl_ref => { | |
| 582 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 583 | const decl = mod.declPtr(decl_index); | |
| 584 | const decl_val = try decl.value(); | |
| 585 | return decl_val.toAllocatedBytes(decl.ty, allocator, mod); | |
| 562 | switch (val.ip_index) { | |
| 563 | .none => switch (val.tag()) { | |
| 564 | .bytes => { | |
| 565 | const bytes = val.castTag(.bytes).?.data; | |
| 566 | const adjusted_len = bytes.len - @boolToInt(ty.sentinel(mod) != null); | |
| 567 | const adjusted_bytes = bytes[0..adjusted_len]; | |
| 568 | return allocator.dupe(u8, adjusted_bytes); | |
| 569 | }, | |
| 570 | .str_lit => { | |
| 571 | const str_lit = val.castTag(.str_lit).?.data; | |
| 572 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 573 | return allocator.dupe(u8, bytes); | |
| 574 | }, | |
| 575 | .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data), | |
| 576 | .repeated => { | |
| 577 | const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt(mod)); | |
| 578 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); | |
| 579 | @memset(result, byte); | |
| 580 | return result; | |
| 581 | }, | |
| 582 | .decl_ref => { | |
| 583 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 584 | const decl = mod.declPtr(decl_index); | |
| 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{}, | |
| 588 | .slice => { | |
| 589 | const slice = val.castTag(.slice).?.data; | |
| 590 | return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(mod), allocator, mod); | |
| 595 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 596 | .ptr => |ptr| switch (ptr.len) { | |
| 597 | .none => unreachable, | |
| 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 | 614 | pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { |
| 606 | 615 | if (val.ip_index != .none) return mod.intern_pool.getCoerced(mod.gpa, val.ip_index, ty.ip_index); |
| 607 | 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 | 627 | .slice => { |
| 609 | 628 | const pl = val.castTag(.slice).?.data; |
| 610 | 629 | const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod); |
| ... | ... | @@ -2601,7 +2620,10 @@ pub const Value = struct { |
| 2601 | 2620 | .@"var" => unreachable, |
| 2602 | 2621 | .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), |
| 2603 | 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 | 2628 | .aggregate => |aggregate| switch (aggregate.storage) { |
| 2607 | 2629 | .elems => |elems| elems[index].toValue(), |