| ... | @@ -3,6 +3,9 @@ | ... | @@ -3,6 +3,9 @@ |
| 3 | map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, | 3 | map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, |
| 4 | items: std.MultiArrayList(Item) = .{}, | 4 | items: std.MultiArrayList(Item) = .{}, |
| 5 | extra: std.ArrayListUnmanaged(u32) = .{}, | 5 | extra: std.ArrayListUnmanaged(u32) = .{}, |
| | 6 | /// On 32-bit systems, this array is ignored and extra is used for everything. |
| | 7 | /// On 64-bit systems, this array is used for big integers and associated metadata. |
| | 8 | limbs: std.ArrayListUnmanaged(u64) = .{}, |
| 6 | | 9 | |
| 7 | const std = @import("std"); | 10 | const std = @import("std"); |
| 8 | const Allocator = std.mem.Allocator; | 11 | const Allocator = std.mem.Allocator; |
| ... | @@ -91,19 +94,43 @@ pub const Key = union(enum) { | ... | @@ -91,19 +94,43 @@ pub const Key = union(enum) { |
| 91 | } | 94 | } |
| 92 | | 95 | |
| 93 | pub fn hashWithHasher(key: Key, hasher: *std.hash.Wyhash) void { | 96 | pub fn hashWithHasher(key: Key, hasher: *std.hash.Wyhash) void { |
| | 97 | const KeyTag = @typeInfo(Key).Union.tag_type.?; |
| | 98 | const key_tag: KeyTag = key; |
| | 99 | std.hash.autoHash(hasher, key_tag); |
| 94 | switch (key) { | 100 | switch (key) { |
| 95 | .int_type => |int_type| { | 101 | inline .int_type, |
| 96 | std.hash.autoHash(hasher, int_type); | 102 | .ptr_type, |
| | 103 | .array_type, |
| | 104 | .vector_type, |
| | 105 | .optional_type, |
| | 106 | .error_union_type, |
| | 107 | .simple_type, |
| | 108 | .simple_value, |
| | 109 | .extern_func, |
| | 110 | => |info| std.hash.autoHash(hasher, info), |
| | 111 | |
| | 112 | .int => |int| { |
| | 113 | std.hash.autoHash(hasher, int.ty); |
| | 114 | std.hash.autoHash(hasher, int.big_int.positive); |
| | 115 | for (int.big_int.limbs) |limb| std.hash.autoHash(hasher, limb); |
| 97 | }, | 116 | }, |
| 98 | .array_type => |array_type| { | 117 | |
| 99 | std.hash.autoHash(hasher, array_type); | 118 | .enum_tag => |enum_tag| { |
| | 119 | std.hash.autoHash(hasher, enum_tag.ty); |
| | 120 | std.hash.autoHash(hasher, enum_tag.tag.positive); |
| | 121 | for (enum_tag.tag.limbs) |limb| std.hash.autoHash(hasher, limb); |
| | 122 | }, |
| | 123 | |
| | 124 | .struct_type => |struct_type| { |
| | 125 | if (struct_type.fields_len != 0) { |
| | 126 | @panic("TODO"); |
| | 127 | } |
| 100 | }, | 128 | }, |
| 101 | else => @panic("TODO"), | | |
| 102 | } | 129 | } |
| 103 | } | 130 | } |
| 104 | | 131 | |
| 105 | pub fn eql(a: Key, b: Key) bool { | 132 | pub fn eql(a: Key, b: Key) bool { |
| 106 | const KeyTag = std.meta.Tag(Key); | 133 | const KeyTag = @typeInfo(Key).Union.tag_type.?; |
| 107 | const a_tag: KeyTag = a; | 134 | const a_tag: KeyTag = a; |
| 108 | const b_tag: KeyTag = b; | 135 | const b_tag: KeyTag = b; |
| 109 | if (a_tag != b_tag) return false; | 136 | if (a_tag != b_tag) return false; |
| ... | @@ -112,11 +139,62 @@ pub const Key = union(enum) { | ... | @@ -112,11 +139,62 @@ pub const Key = union(enum) { |
| 112 | const b_info = b.int_type; | 139 | const b_info = b.int_type; |
| 113 | return std.meta.eql(a_info, b_info); | 140 | return std.meta.eql(a_info, b_info); |
| 114 | }, | 141 | }, |
| | 142 | .ptr_type => |a_info| { |
| | 143 | const b_info = b.ptr_type; |
| | 144 | return std.meta.eql(a_info, b_info); |
| | 145 | }, |
| 115 | .array_type => |a_info| { | 146 | .array_type => |a_info| { |
| 116 | const b_info = b.array_type; | 147 | const b_info = b.array_type; |
| 117 | return std.meta.eql(a_info, b_info); | 148 | return std.meta.eql(a_info, b_info); |
| 118 | }, | 149 | }, |
| 119 | else => @panic("TODO"), | 150 | .vector_type => |a_info| { |
| | 151 | const b_info = b.vector_type; |
| | 152 | return std.meta.eql(a_info, b_info); |
| | 153 | }, |
| | 154 | .optional_type => |a_info| { |
| | 155 | const b_info = b.optional_type; |
| | 156 | return std.meta.eql(a_info, b_info); |
| | 157 | }, |
| | 158 | .error_union_type => |a_info| { |
| | 159 | const b_info = b.error_union_type; |
| | 160 | return std.meta.eql(a_info, b_info); |
| | 161 | }, |
| | 162 | .simple_type => |a_info| { |
| | 163 | const b_info = b.simple_type; |
| | 164 | return a_info == b_info; |
| | 165 | }, |
| | 166 | .simple_value => |a_info| { |
| | 167 | const b_info = b.simple_value; |
| | 168 | return a_info == b_info; |
| | 169 | }, |
| | 170 | .extern_func => |a_info| { |
| | 171 | const b_info = b.extern_func; |
| | 172 | return std.meta.eql(a_info, b_info); |
| | 173 | }, |
| | 174 | |
| | 175 | .int => |a_info| { |
| | 176 | const b_info = b.int; |
| | 177 | _ = a_info; |
| | 178 | _ = b_info; |
| | 179 | @panic("TODO"); |
| | 180 | }, |
| | 181 | |
| | 182 | .enum_tag => |a_info| { |
| | 183 | const b_info = b.enum_tag; |
| | 184 | _ = a_info; |
| | 185 | _ = b_info; |
| | 186 | @panic("TODO"); |
| | 187 | }, |
| | 188 | |
| | 189 | .struct_type => |a_info| { |
| | 190 | const b_info = b.struct_type; |
| | 191 | |
| | 192 | // TODO: remove this special case for empty_struct |
| | 193 | if (a_info.fields_len == 0 and b_info.fields_len == 0) |
| | 194 | return true; |
| | 195 | |
| | 196 | @panic("TODO"); |
| | 197 | }, |
| 120 | } | 198 | } |
| 121 | } | 199 | } |
| 122 | | 200 | |
| ... | @@ -491,27 +569,65 @@ pub const Tag = enum(u8) { | ... | @@ -491,27 +569,65 @@ pub const Tag = enum(u8) { |
| 491 | /// An integer type. | 569 | /// An integer type. |
| 492 | /// data is number of bits | 570 | /// data is number of bits |
| 493 | type_int_unsigned, | 571 | type_int_unsigned, |
| 494 | /// An array type. | 572 | /// An array type that has no sentinel and whose length fits in 32 bits. |
| 495 | /// data is payload to Array. | 573 | /// data is payload to Vector. |
| 496 | type_array, | 574 | type_array, |
| | 575 | /// A vector type. |
| | 576 | /// data is payload to Vector. |
| | 577 | type_vector, |
| | 578 | /// A pointer type along with all its bells and whistles. |
| | 579 | /// data is payload to Pointer. |
| | 580 | type_pointer, |
| | 581 | /// An optional type. |
| | 582 | /// data is the child type. |
| | 583 | type_optional, |
| | 584 | /// An error union type. |
| | 585 | /// data is payload to ErrorUnion. |
| | 586 | type_error_union, |
| | 587 | /// Represents the data that an enum declaration provides, when the fields |
| | 588 | /// are auto-numbered, and there are no declarations. |
| | 589 | /// data is payload index to `EnumSimple`. |
| | 590 | type_enum_simple, |
| | 591 | |
| 497 | /// A type that can be represented with only an enum tag. | 592 | /// A type that can be represented with only an enum tag. |
| 498 | /// data is SimpleType enum value. | 593 | /// data is SimpleType enum value. |
| 499 | simple_type, | 594 | simple_type, |
| 500 | /// A value that can be represented with only an enum tag. | 595 | /// A value that can be represented with only an enum tag. |
| 501 | /// data is SimpleValue enum value. | 596 | /// data is SimpleValue enum value. |
| 502 | simple_value, | 597 | simple_value, |
| 503 | /// An unsigned integer value that can be represented by u32. | 598 | /// The SimpleType and SimpleValue enums are exposed via the InternPool API using |
| | 599 | /// SimpleType and SimpleValue as the Key data themselves. |
| | 600 | /// This tag is for miscellaneous types and values that can be represented with |
| | 601 | /// only an enum tag, but will be presented via the API with a different Key. |
| | 602 | /// data is SimpleInternal enum value. |
| | 603 | simple_internal, |
| | 604 | /// Type: u32 |
| 504 | /// data is integer value | 605 | /// data is integer value |
| 505 | int_u32, | 606 | int_small_u32, |
| 506 | /// An unsigned integer value that can be represented by i32. | 607 | /// Type: i32 |
| 507 | /// data is integer value bitcasted to u32. | 608 | /// data is integer value bitcasted to u32. |
| 508 | int_i32, | 609 | int_small_i32, |
| 509 | /// A positive integer value that does not fit in 32 bits. | 610 | /// A usize that fits in 32 bits. |
| 510 | /// data is a extra index to BigInt. | 611 | /// data is integer value. |
| 511 | int_big_positive, | 612 | int_small_usize, |
| 512 | /// A negative integer value that does not fit in 32 bits. | 613 | /// A comptime_int that fits in a u32. |
| 513 | /// data is a extra index to BigInt. | 614 | /// data is integer value. |
| 514 | int_big_negative, | 615 | int_small_comptime_unsigned, |
| | 616 | /// A comptime_int that fits in an i32. |
| | 617 | /// data is integer value bitcasted to u32. |
| | 618 | int_small_comptime_signed, |
| | 619 | /// A positive integer value. |
| | 620 | /// data is a limbs index to Int. |
| | 621 | int_positive, |
| | 622 | /// A negative integer value. |
| | 623 | /// data is a limbs index to Int. |
| | 624 | int_negative, |
| | 625 | /// An enum tag identified by a positive integer value. |
| | 626 | /// data is a limbs index to Int. |
| | 627 | enum_tag_positive, |
| | 628 | /// An enum tag identified by a negative integer value. |
| | 629 | /// data is a limbs index to Int. |
| | 630 | enum_tag_negative, |
| 515 | /// A float value that can be represented by f32. | 631 | /// A float value that can be represented by f32. |
| 516 | /// data is float value bitcasted to u32. | 632 | /// data is float value bitcasted to u32. |
| 517 | float_f32, | 633 | float_f32, |
| ... | @@ -525,10 +641,6 @@ pub const Tag = enum(u8) { | ... | @@ -525,10 +641,6 @@ pub const Tag = enum(u8) { |
| 525 | extern_func, | 641 | extern_func, |
| 526 | /// A regular function. | 642 | /// A regular function. |
| 527 | func, | 643 | func, |
| 528 | /// Represents the data that an enum declaration provides, when the fields | | |
| 529 | /// are auto-numbered, and there are no declarations. | | |
| 530 | /// data is payload index to `EnumSimple`. | | |
| 531 | enum_simple, | | |
| 532 | }; | 644 | }; |
| 533 | | 645 | |
| 534 | /// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to | 646 | /// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to |
| ... | @@ -593,11 +705,43 @@ pub const SimpleValue = enum(u32) { | ... | @@ -593,11 +705,43 @@ pub const SimpleValue = enum(u32) { |
| 593 | generic_poison, | 705 | generic_poison, |
| 594 | }; | 706 | }; |
| 595 | | 707 | |
| 596 | pub const Array = struct { | 708 | pub const SimpleInternal = enum(u32) { |
| | 709 | /// This is the empty struct type. Note that empty_struct value is exposed |
| | 710 | /// via SimpleValue. |
| | 711 | type_empty_struct, |
| | 712 | }; |
| | 713 | |
| | 714 | pub const Pointer = struct { |
| | 715 | child: Index, |
| | 716 | sentinel: Index, |
| | 717 | flags: Flags, |
| | 718 | |
| | 719 | pub const Flags = packed struct(u32) { |
| | 720 | alignment: u16, |
| | 721 | is_const: bool, |
| | 722 | is_volatile: bool, |
| | 723 | is_allowzero: bool, |
| | 724 | size: Size, |
| | 725 | address_space: AddressSpace, |
| | 726 | _: u7 = undefined, |
| | 727 | }; |
| | 728 | |
| | 729 | pub const Size = std.builtin.Type.Pointer.Size; |
| | 730 | pub const AddressSpace = std.builtin.AddressSpace; |
| | 731 | }; |
| | 732 | |
| | 733 | /// Used for non-sentineled arrays that have length fitting in u32, as well as |
| | 734 | /// vectors. |
| | 735 | pub const Vector = struct { |
| 597 | len: u32, | 736 | len: u32, |
| 598 | child: Index, | 737 | child: Index, |
| 599 | }; | 738 | }; |
| 600 | | 739 | |
| | 740 | pub const ErrorUnion = struct { |
| | 741 | error_set_type: Index, |
| | 742 | payload_type: Index, |
| | 743 | }; |
| | 744 | |
| 601 | /// Trailing: | 745 | /// Trailing: |
| 602 | /// 0. field name: null-terminated string index for each fields_len; declaration order | 746 | /// 0. field name: null-terminated string index for each fields_len; declaration order |
| 603 | pub const EnumSimple = struct { | 747 | pub const EnumSimple = struct { |
| ... | @@ -612,6 +756,12 @@ pub const EnumSimple = struct { | ... | @@ -612,6 +756,12 @@ pub const EnumSimple = struct { |
| 612 | fields_len: u32, | 756 | fields_len: u32, |
| 613 | }; | 757 | }; |
| 614 | | 758 | |
| | 759 | /// Trailing: Limb for every limbs_len |
| | 760 | pub const Int = struct { |
| | 761 | ty: Index, |
| | 762 | limbs_len: u32, |
| | 763 | }; |
| | 764 | |
| 615 | pub fn init(ip: *InternPool, gpa: Allocator) !void { | 765 | pub fn init(ip: *InternPool, gpa: Allocator) !void { |
| 616 | assert(ip.items.len == 0); | 766 | assert(ip.items.len == 0); |
| 617 | | 767 | |
| ... | @@ -619,6 +769,7 @@ pub fn init(ip: *InternPool, gpa: Allocator) !void { | ... | @@ -619,6 +769,7 @@ pub fn init(ip: *InternPool, gpa: Allocator) !void { |
| 619 | try ip.items.ensureUnusedCapacity(gpa, static_keys.len); | 769 | try ip.items.ensureUnusedCapacity(gpa, static_keys.len); |
| 620 | try ip.map.ensureUnusedCapacity(gpa, static_keys.len); | 770 | try ip.map.ensureUnusedCapacity(gpa, static_keys.len); |
| 621 | try ip.extra.ensureUnusedCapacity(gpa, static_keys.len); | 771 | try ip.extra.ensureUnusedCapacity(gpa, static_keys.len); |
| | 772 | try ip.limbs.ensureUnusedCapacity(gpa, 2); |
| 622 | | 773 | |
| 623 | // This inserts all the statically-known values into the intern pool in the | 774 | // This inserts all the statically-known values into the intern pool in the |
| 624 | // order expected. | 775 | // order expected. |
| ... | @@ -635,6 +786,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { | ... | @@ -635,6 +786,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 635 | ip.map.deinit(gpa); | 786 | ip.map.deinit(gpa); |
| 636 | ip.items.deinit(gpa); | 787 | ip.items.deinit(gpa); |
| 637 | ip.extra.deinit(gpa); | 788 | ip.extra.deinit(gpa); |
| | 789 | ip.limbs.deinit(gpa); |
| 638 | ip.* = undefined; | 790 | ip.* = undefined; |
| 639 | } | 791 | } |
| 640 | | 792 | |
| ... | @@ -655,7 +807,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -655,7 +807,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 655 | }, | 807 | }, |
| 656 | }, | 808 | }, |
| 657 | .type_array => { | 809 | .type_array => { |
| 658 | const array_info = ip.extraData(Array, data); | 810 | const array_info = ip.extraData(Vector, data); |
| 659 | return .{ .array_type = .{ | 811 | return .{ .array_type = .{ |
| 660 | .len = array_info.len, | 812 | .len = array_info.len, |
| 661 | .child = array_info.child, | 813 | .child = array_info.child, |
| ... | @@ -675,58 +827,226 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -675,58 +827,226 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 675 | if (gop.found_existing) { | 827 | if (gop.found_existing) { |
| 676 | return @intToEnum(Index, gop.index); | 828 | return @intToEnum(Index, gop.index); |
| 677 | } | 829 | } |
| | 830 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| 678 | switch (key) { | 831 | switch (key) { |
| 679 | .int_type => |int_type| { | 832 | .int_type => |int_type| { |
| 680 | const t: Tag = switch (int_type.signedness) { | 833 | const t: Tag = switch (int_type.signedness) { |
| 681 | .signed => .type_int_signed, | 834 | .signed => .type_int_signed, |
| 682 | .unsigned => .type_int_unsigned, | 835 | .unsigned => .type_int_unsigned, |
| 683 | }; | 836 | }; |
| 684 | try ip.items.append(gpa, .{ | 837 | ip.items.appendAssumeCapacity(.{ |
| 685 | .tag = t, | 838 | .tag = t, |
| 686 | .data = int_type.bits, | 839 | .data = int_type.bits, |
| 687 | }); | 840 | }); |
| 688 | }, | 841 | }, |
| | 842 | .ptr_type => |ptr_type| { |
| | 843 | // TODO introduce more pointer encodings |
| | 844 | ip.items.appendAssumeCapacity(.{ |
| | 845 | .tag = .type_pointer, |
| | 846 | .data = try ip.addExtra(gpa, Pointer{ |
| | 847 | .child = ptr_type.elem_type, |
| | 848 | .sentinel = ptr_type.sentinel, |
| | 849 | .flags = .{ |
| | 850 | .alignment = ptr_type.alignment, |
| | 851 | .is_const = ptr_type.is_const, |
| | 852 | .is_volatile = ptr_type.is_volatile, |
| | 853 | .is_allowzero = ptr_type.is_allowzero, |
| | 854 | .size = ptr_type.size, |
| | 855 | .address_space = ptr_type.address_space, |
| | 856 | }, |
| | 857 | }), |
| | 858 | }); |
| | 859 | }, |
| 689 | .array_type => |array_type| { | 860 | .array_type => |array_type| { |
| 690 | const len = @intCast(u32, array_type.len); // TODO have a big_array encoding | 861 | const len = @intCast(u32, array_type.len); // TODO have a big_array encoding |
| 691 | assert(array_type.sentinel == .none); // TODO have a sentinel_array encoding | 862 | assert(array_type.sentinel == .none); // TODO have a sentinel_array encoding |
| 692 | try ip.items.append(gpa, .{ | 863 | ip.items.appendAssumeCapacity(.{ |
| 693 | .tag = .type_array, | 864 | .tag = .type_array, |
| 694 | .data = try ip.addExtra(gpa, Array{ | 865 | .data = try ip.addExtra(gpa, Vector{ |
| 695 | .len = len, | 866 | .len = len, |
| 696 | .child = array_type.child, | 867 | .child = array_type.child, |
| 697 | }), | 868 | }), |
| 698 | }); | 869 | }); |
| 699 | }, | 870 | }, |
| 700 | else => @panic("TODO"), | 871 | .vector_type => |vector_type| { |
| | 872 | ip.items.appendAssumeCapacity(.{ |
| | 873 | .tag = .type_vector, |
| | 874 | .data = try ip.addExtra(gpa, Vector{ |
| | 875 | .len = vector_type.len, |
| | 876 | .child = vector_type.child, |
| | 877 | }), |
| | 878 | }); |
| | 879 | }, |
| | 880 | .optional_type => |optional_type| { |
| | 881 | ip.items.appendAssumeCapacity(.{ |
| | 882 | .tag = .type_optional, |
| | 883 | .data = @enumToInt(optional_type.payload_type), |
| | 884 | }); |
| | 885 | }, |
| | 886 | .error_union_type => |error_union_type| { |
| | 887 | ip.items.appendAssumeCapacity(.{ |
| | 888 | .tag = .type_error_union, |
| | 889 | .data = try ip.addExtra(gpa, ErrorUnion{ |
| | 890 | .error_set_type = error_union_type.error_set_type, |
| | 891 | .payload_type = error_union_type.payload_type, |
| | 892 | }), |
| | 893 | }); |
| | 894 | }, |
| | 895 | .simple_type => |simple_type| { |
| | 896 | ip.items.appendAssumeCapacity(.{ |
| | 897 | .tag = .simple_type, |
| | 898 | .data = @enumToInt(simple_type), |
| | 899 | }); |
| | 900 | }, |
| | 901 | .simple_value => |simple_value| { |
| | 902 | ip.items.appendAssumeCapacity(.{ |
| | 903 | .tag = .simple_value, |
| | 904 | .data = @enumToInt(simple_value), |
| | 905 | }); |
| | 906 | }, |
| | 907 | .extern_func => @panic("TODO"), |
| | 908 | |
| | 909 | .int => |int| b: { |
| | 910 | switch (int.ty) { |
| | 911 | .u32_type => { |
| | 912 | if (int.big_int.fits(u32)) { |
| | 913 | ip.items.appendAssumeCapacity(.{ |
| | 914 | .tag = .int_small_u32, |
| | 915 | .data = int.big_int.to(u32) catch unreachable, |
| | 916 | }); |
| | 917 | break :b; |
| | 918 | } |
| | 919 | }, |
| | 920 | .i32_type => { |
| | 921 | if (int.big_int.fits(i32)) { |
| | 922 | ip.items.appendAssumeCapacity(.{ |
| | 923 | .tag = .int_small_i32, |
| | 924 | .data = @bitCast(u32, int.big_int.to(i32) catch unreachable), |
| | 925 | }); |
| | 926 | break :b; |
| | 927 | } |
| | 928 | }, |
| | 929 | .usize_type => { |
| | 930 | if (int.big_int.fits(u32)) { |
| | 931 | ip.items.appendAssumeCapacity(.{ |
| | 932 | .tag = .int_small_usize, |
| | 933 | .data = int.big_int.to(u32) catch unreachable, |
| | 934 | }); |
| | 935 | break :b; |
| | 936 | } |
| | 937 | }, |
| | 938 | .comptime_int_type => { |
| | 939 | if (int.big_int.fits(u32)) { |
| | 940 | ip.items.appendAssumeCapacity(.{ |
| | 941 | .tag = .int_small_comptime_unsigned, |
| | 942 | .data = int.big_int.to(u32) catch unreachable, |
| | 943 | }); |
| | 944 | break :b; |
| | 945 | } |
| | 946 | if (int.big_int.fits(i32)) { |
| | 947 | ip.items.appendAssumeCapacity(.{ |
| | 948 | .tag = .int_small_comptime_signed, |
| | 949 | .data = @bitCast(u32, int.big_int.to(i32) catch unreachable), |
| | 950 | }); |
| | 951 | break :b; |
| | 952 | } |
| | 953 | }, |
| | 954 | else => {}, |
| | 955 | } |
| | 956 | |
| | 957 | const tag: Tag = if (int.big_int.positive) .int_positive else .int_negative; |
| | 958 | try addInt(ip, gpa, int.ty, tag, int.big_int.limbs); |
| | 959 | }, |
| | 960 | |
| | 961 | .enum_tag => |enum_tag| { |
| | 962 | const tag: Tag = if (enum_tag.tag.positive) .enum_tag_positive else .enum_tag_negative; |
| | 963 | try addInt(ip, gpa, enum_tag.ty, tag, enum_tag.tag.limbs); |
| | 964 | }, |
| | 965 | |
| | 966 | .struct_type => |struct_type| { |
| | 967 | if (struct_type.fields_len != 0) { |
| | 968 | @panic("TODO"); // handle structs other than empty_struct |
| | 969 | } |
| | 970 | ip.items.appendAssumeCapacity(.{ |
| | 971 | .tag = .simple_internal, |
| | 972 | .data = @enumToInt(SimpleInternal.type_empty_struct), |
| | 973 | }); |
| | 974 | }, |
| 701 | } | 975 | } |
| 702 | return @intToEnum(Index, ip.items.len - 1); | 976 | return @intToEnum(Index, ip.items.len - 1); |
| 703 | } | 977 | } |
| 704 | | 978 | |
| 705 | pub fn tag(ip: InternPool, index: Index) Tag { | 979 | fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const usize) !void { |
| 706 | const tags = ip.items.items(.tag); | 980 | const limbs_len = @intCast(u32, limbs.len); |
| 707 | return tags[@enumToInt(index)]; | 981 | try ip.reserveLimbs(gpa, @typeInfo(Int).Struct.fields.len + limbs_len); |
| | 982 | ip.items.appendAssumeCapacity(.{ |
| | 983 | .tag = tag, |
| | 984 | .data = ip.addLimbsExtraAssumeCapacity(Int{ |
| | 985 | .ty = ty, |
| | 986 | .limbs_len = limbs_len, |
| | 987 | }), |
| | 988 | }); |
| | 989 | ip.addLimbsAssumeCapacity(limbs); |
| 708 | } | 990 | } |
| 709 | | 991 | |
| 710 | fn addExtra(ip: *InternPool, gpa: Allocator, extra: anytype) Allocator.Error!u32 { | 992 | fn addExtra(ip: *InternPool, gpa: Allocator, extra: anytype) Allocator.Error!u32 { |
| 711 | const fields = std.meta.fields(@TypeOf(extra)); | 993 | const fields = @typeInfo(@TypeOf(extra)).Struct.fields; |
| 712 | try ip.extra.ensureUnusedCapacity(gpa, fields.len); | 994 | try ip.extra.ensureUnusedCapacity(gpa, fields.len); |
| 713 | return ip.addExtraAssumeCapacity(extra); | 995 | return ip.addExtraAssumeCapacity(extra); |
| 714 | } | 996 | } |
| 715 | | 997 | |
| 716 | fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { | 998 | fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 717 | const fields = std.meta.fields(@TypeOf(extra)); | | |
| 718 | const result = @intCast(u32, ip.extra.items.len); | 999 | const result = @intCast(u32, ip.extra.items.len); |
| 719 | inline for (fields) |field| { | 1000 | inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| { |
| 720 | ip.extra.appendAssumeCapacity(switch (field.type) { | 1001 | ip.extra.appendAssumeCapacity(switch (field.type) { |
| 721 | u32 => @field(extra, field.name), | 1002 | u32 => @field(extra, field.name), |
| 722 | Index => @enumToInt(@field(extra, field.name)), | 1003 | Index => @enumToInt(@field(extra, field.name)), |
| 723 | i32 => @bitCast(u32, @field(extra, field.name)), | 1004 | i32 => @bitCast(u32, @field(extra, field.name)), |
| 724 | else => @compileError("bad field type"), | 1005 | Pointer.Flags => @bitCast(u32, @field(extra, field.name)), |
| | 1006 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 725 | }); | 1007 | }); |
| 726 | } | 1008 | } |
| 727 | return result; | 1009 | return result; |
| 728 | } | 1010 | } |
| 729 | | 1011 | |
| | 1012 | fn reserveLimbs(ip: *InternPool, gpa: Allocator, n: usize) !void { |
| | 1013 | switch (@sizeOf(usize)) { |
| | 1014 | @sizeOf(u32) => try ip.extra.ensureUnusedCapacity(gpa, n), |
| | 1015 | @sizeOf(u64) => try ip.limbs.ensureUnusedCapacity(gpa, n), |
| | 1016 | else => @compileError("unsupported host"), |
| | 1017 | } |
| | 1018 | } |
| | 1019 | |
| | 1020 | fn addLimbsExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| | 1021 | switch (@sizeOf(usize)) { |
| | 1022 | @sizeOf(u32) => return addExtraAssumeCapacity(ip, extra), |
| | 1023 | @sizeOf(u64) => {}, |
| | 1024 | else => @compileError("unsupported host"), |
| | 1025 | } |
| | 1026 | const result = @intCast(u32, ip.extra.items.len); |
| | 1027 | inline for (@typeInfo(@TypeOf(extra)).Struct.fields, 0..) |field, i| { |
| | 1028 | const new: u32 = switch (field.type) { |
| | 1029 | u32 => @field(extra, field.name), |
| | 1030 | Index => @enumToInt(@field(extra, field.name)), |
| | 1031 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| | 1032 | }; |
| | 1033 | if (i % 2 == 0) { |
| | 1034 | ip.limbs.appendAssumeCapacity(new); |
| | 1035 | } else { |
| | 1036 | ip.limbs.items[ip.limbs.items.len - 1] |= @as(u64, new) << 32; |
| | 1037 | } |
| | 1038 | } |
| | 1039 | return result; |
| | 1040 | } |
| | 1041 | |
| | 1042 | fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const usize) void { |
| | 1043 | switch (@sizeOf(usize)) { |
| | 1044 | @sizeOf(u32) => ip.extra.appendSliceAssumeCapacity(limbs), |
| | 1045 | @sizeOf(u64) => ip.limbs.appendSliceAssumeCapacity(limbs), |
| | 1046 | else => @compileError("unsupported host"), |
| | 1047 | } |
| | 1048 | } |
| | 1049 | |
| 730 | fn extraData(ip: InternPool, comptime T: type, index: usize) T { | 1050 | fn extraData(ip: InternPool, comptime T: type, index: usize) T { |
| 731 | const fields = std.meta.fields(T); | 1051 | const fields = std.meta.fields(T); |
| 732 | var i: usize = index; | 1052 | var i: usize = index; |
| ... | @@ -736,7 +1056,8 @@ fn extraData(ip: InternPool, comptime T: type, index: usize) T { | ... | @@ -736,7 +1056,8 @@ fn extraData(ip: InternPool, comptime T: type, index: usize) T { |
| 736 | u32 => ip.extra.items[i], | 1056 | u32 => ip.extra.items[i], |
| 737 | Index => @intToEnum(Index, ip.extra.items[i]), | 1057 | Index => @intToEnum(Index, ip.extra.items[i]), |
| 738 | i32 => @bitCast(i32, ip.extra.items[i]), | 1058 | i32 => @bitCast(i32, ip.extra.items[i]), |
| 739 | else => @compileError("bad field type"), | 1059 | Pointer.Flags => @bitCast(Pointer.Flags, ip.extra.items[i]), |
| | 1060 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 740 | }; | 1061 | }; |
| 741 | i += 1; | 1062 | i += 1; |
| 742 | } | 1063 | } |