| ... | ... | @@ -69,6 +69,7 @@ const assert = std.debug.assert; |
| 69 | 69 | const BigIntConst = std.math.big.int.Const; |
| 70 | 70 | const BigIntMutable = std.math.big.int.Mutable; |
| 71 | 71 | const Limb = std.math.big.Limb; |
| 72 | const Hash = std.hash.Wyhash; |
| 72 | 73 | |
| 73 | 74 | const InternPool = @This(); |
| 74 | 75 | const Module = @import("Module.zig"); |
| ... | ... | @@ -675,34 +676,34 @@ pub const Key = union(enum) { |
| 675 | 676 | .empty_enum_value, |
| 676 | 677 | .inferred_error_set_type, |
| 677 | 678 | .un, |
| 678 | | => |x| WyhashKing.hash(seed, asBytes(&x)), |
| 679 | => |x| Hash.hash(seed, asBytes(&x)), |
| 679 | 680 | |
| 680 | | .int_type => |x| WyhashKing.hash(seed + @enumToInt(x.signedness), asBytes(&x.bits)), |
| 681 | | .union_type => |x| WyhashKing.hash(seed + @enumToInt(x.runtime_tag), asBytes(&x.index)), |
| 681 | .int_type => |x| Hash.hash(seed + @enumToInt(x.signedness), asBytes(&x.bits)), |
| 682 | .union_type => |x| Hash.hash(seed + @enumToInt(x.runtime_tag), asBytes(&x.index)), |
| 682 | 683 | |
| 683 | 684 | .error_union => |x| switch (x.val) { |
| 684 | | .err_name => |y| WyhashKing.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)), |
| 685 | | .payload => |y| WyhashKing.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)), |
| 685 | .err_name => |y| Hash.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)), |
| 686 | .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)), |
| 686 | 687 | }, |
| 687 | 688 | |
| 688 | | .runtime_value => |x| WyhashKing.hash(seed, asBytes(&x.val)), |
| 689 | | .opaque_type => |x| WyhashKing.hash(seed, asBytes(&x.decl)), |
| 689 | .runtime_value => |x| Hash.hash(seed, asBytes(&x.val)), |
| 690 | .opaque_type => |x| Hash.hash(seed, asBytes(&x.decl)), |
| 690 | 691 | |
| 691 | 692 | .enum_type => |enum_type| { |
| 692 | | var hasher = std.hash.Wyhash.init(seed); |
| 693 | var hasher = Hash.init(seed); |
| 693 | 694 | std.hash.autoHash(&hasher, enum_type.decl); |
| 694 | 695 | return hasher.final(); |
| 695 | 696 | }, |
| 696 | 697 | |
| 697 | 698 | .variable => |variable| { |
| 698 | | var hasher = std.hash.Wyhash.init(seed); |
| 699 | var hasher = Hash.init(seed); |
| 699 | 700 | std.hash.autoHash(&hasher, variable.decl); |
| 700 | 701 | return hasher.final(); |
| 701 | 702 | }, |
| 702 | | .extern_func => |x| WyhashKing.hash(seed, asBytes(&x.ty) ++ asBytes(&x.decl)), |
| 703 | .extern_func => |x| Hash.hash(seed, asBytes(&x.ty) ++ asBytes(&x.decl)), |
| 703 | 704 | |
| 704 | 705 | .int => |int| { |
| 705 | | var hasher = std.hash.Wyhash.init(seed); |
| 706 | var hasher = Hash.init(seed); |
| 706 | 707 | // Canonicalize all integers by converting them to BigIntConst. |
| 707 | 708 | switch (int.storage) { |
| 708 | 709 | .u64, .i64, .big_int => { |
| ... | ... | @@ -725,7 +726,7 @@ pub const Key = union(enum) { |
| 725 | 726 | }, |
| 726 | 727 | |
| 727 | 728 | .float => |float| { |
| 728 | | var hasher = std.hash.Wyhash.init(seed); |
| 729 | var hasher = Hash.init(seed); |
| 729 | 730 | std.hash.autoHash(&hasher, float.ty); |
| 730 | 731 | switch (float.storage) { |
| 731 | 732 | inline else => |val| std.hash.autoHash( |
| ... | ... | @@ -743,19 +744,19 @@ pub const Key = union(enum) { |
| 743 | 744 | const seed2 = seed + @enumToInt(addr); |
| 744 | 745 | const common = asBytes(&ptr.ty) ++ asBytes(&ptr.len); |
| 745 | 746 | return switch (ptr.addr) { |
| 746 | | .decl => |x| WyhashKing.hash(seed2, common ++ asBytes(&x)), |
| 747 | .decl => |x| Hash.hash(seed2, common ++ asBytes(&x)), |
| 747 | 748 | |
| 748 | | .mut_decl => |x| WyhashKing.hash( |
| 749 | .mut_decl => |x| Hash.hash( |
| 749 | 750 | seed2, |
| 750 | 751 | asBytes(&x.decl) ++ asBytes(&x.runtime_index), |
| 751 | 752 | ), |
| 752 | 753 | |
| 753 | | .int, .eu_payload, .opt_payload, .comptime_field => |int| WyhashKing.hash( |
| 754 | .int, .eu_payload, .opt_payload, .comptime_field => |int| Hash.hash( |
| 754 | 755 | seed2, |
| 755 | 756 | asBytes(&int), |
| 756 | 757 | ), |
| 757 | 758 | |
| 758 | | .elem, .field => |x| WyhashKing.hash( |
| 759 | .elem, .field => |x| Hash.hash( |
| 759 | 760 | seed2, |
| 760 | 761 | asBytes(&x.base) ++ asBytes(&x.index), |
| 761 | 762 | ), |
| ... | ... | @@ -763,7 +764,7 @@ pub const Key = union(enum) { |
| 763 | 764 | }, |
| 764 | 765 | |
| 765 | 766 | .aggregate => |aggregate| { |
| 766 | | var hasher = std.hash.Wyhash.init(seed); |
| 767 | var hasher = Hash.init(seed); |
| 767 | 768 | std.hash.autoHash(&hasher, aggregate.ty); |
| 768 | 769 | const len = ip.aggregateTypeLen(aggregate.ty); |
| 769 | 770 | const child = switch (ip.indexToKey(aggregate.ty)) { |
| ... | ... | @@ -823,13 +824,13 @@ pub const Key = union(enum) { |
| 823 | 824 | }, |
| 824 | 825 | |
| 825 | 826 | .error_set_type => |error_set_type| { |
| 826 | | var hasher = std.hash.Wyhash.init(seed); |
| 827 | var hasher = Hash.init(seed); |
| 827 | 828 | for (error_set_type.names) |elem| std.hash.autoHash(&hasher, elem); |
| 828 | 829 | return hasher.final(); |
| 829 | 830 | }, |
| 830 | 831 | |
| 831 | 832 | .anon_struct_type => |anon_struct_type| { |
| 832 | | var hasher = std.hash.Wyhash.init(seed); |
| 833 | var hasher = Hash.init(seed); |
| 833 | 834 | for (anon_struct_type.types) |elem| std.hash.autoHash(&hasher, elem); |
| 834 | 835 | for (anon_struct_type.values) |elem| std.hash.autoHash(&hasher, elem); |
| 835 | 836 | for (anon_struct_type.names) |elem| std.hash.autoHash(&hasher, elem); |
| ... | ... | @@ -837,7 +838,7 @@ pub const Key = union(enum) { |
| 837 | 838 | }, |
| 838 | 839 | |
| 839 | 840 | .func_type => |func_type| { |
| 840 | | var hasher = std.hash.Wyhash.init(seed); |
| 841 | var hasher = Hash.init(seed); |
| 841 | 842 | for (func_type.param_types) |param_type| std.hash.autoHash(&hasher, param_type); |
| 842 | 843 | std.hash.autoHash(&hasher, func_type.return_type); |
| 843 | 844 | std.hash.autoHash(&hasher, func_type.comptime_bits); |
| ... | ... | @@ -851,7 +852,7 @@ pub const Key = union(enum) { |
| 851 | 852 | }, |
| 852 | 853 | |
| 853 | 854 | .memoized_call => |memoized_call| { |
| 854 | | var hasher = std.hash.Wyhash.init(seed); |
| 855 | var hasher = Hash.init(seed); |
| 855 | 856 | std.hash.autoHash(&hasher, memoized_call.func); |
| 856 | 857 | for (memoized_call.arg_values) |arg| std.hash.autoHash(&hasher, arg); |
| 857 | 858 | return hasher.final(); |
| ... | ... | @@ -5744,79 +5745,3 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois |
| 5744 | 5745 | .none => unreachable, // special tag |
| 5745 | 5746 | }; |
| 5746 | 5747 | } |
| 5747 | | |
| 5748 | | /// I got this from King, using this temporarily until std lib hashing can be |
| 5749 | | /// improved to make stateless hashing performant. Currently the |
| 5750 | | /// implementations suffer from not special casing small lengths and not taking |
| 5751 | | /// advantage of comptime-known lengths, both of which this implementation |
| 5752 | | /// does. |
| 5753 | | const WyhashKing = struct { |
| 5754 | | inline fn mum(pair: *[2]u64) void { |
| 5755 | | const x = @as(u128, pair[0]) *% pair[1]; |
| 5756 | | pair[0] = @truncate(u64, x); |
| 5757 | | pair[1] = @truncate(u64, x >> 64); |
| 5758 | | } |
| 5759 | | |
| 5760 | | inline fn mix(a: u64, b: u64) u64 { |
| 5761 | | var pair = [_]u64{ a, b }; |
| 5762 | | mum(&pair); |
| 5763 | | return pair[0] ^ pair[1]; |
| 5764 | | } |
| 5765 | | |
| 5766 | | inline fn read(comptime I: type, in: []const u8) I { |
| 5767 | | return std.mem.readIntLittle(I, in[0..@sizeOf(I)]); |
| 5768 | | } |
| 5769 | | |
| 5770 | | const secret = [_]u64{ |
| 5771 | | 0xa0761d6478bd642f, |
| 5772 | | 0xe7037ed1a0b428db, |
| 5773 | | 0x8ebc6af09c88c6e3, |
| 5774 | | 0x589965cc75374cc3, |
| 5775 | | }; |
| 5776 | | |
| 5777 | | fn hash(seed: u64, input: anytype) u64 { |
| 5778 | | var in: []const u8 = input; |
| 5779 | | var last = std.mem.zeroes([2]u64); |
| 5780 | | const starting_len: u64 = input.len; |
| 5781 | | var state = seed ^ mix(seed ^ secret[0], secret[1]); |
| 5782 | | |
| 5783 | | if (in.len <= 16) { |
| 5784 | | if (in.len >= 4) { |
| 5785 | | const end = (in.len >> 3) << 2; |
| 5786 | | last[0] = (@as(u64, read(u32, in)) << 32) | read(u32, in[end..]); |
| 5787 | | last[1] = (@as(u64, read(u32, in[in.len - 4 ..])) << 32) | read(u32, in[in.len - 4 - end ..]); |
| 5788 | | } else if (in.len > 0) { |
| 5789 | | last[0] = (@as(u64, in[0]) << 16) | (@as(u64, in[in.len >> 1]) << 8) | in[in.len - 1]; |
| 5790 | | } |
| 5791 | | } else { |
| 5792 | | large: { |
| 5793 | | if (in.len <= 48) break :large; |
| 5794 | | var split = [_]u64{ state, state, state }; |
| 5795 | | while (true) { |
| 5796 | | for (&split, 0..) |*lane, i| { |
| 5797 | | const a = read(u64, in[(i * 2) * 8 ..]) ^ secret[i + 1]; |
| 5798 | | const b = read(u64, in[((i * 2) + 1) * 8 ..]) ^ lane.*; |
| 5799 | | lane.* = mix(a, b); |
| 5800 | | } |
| 5801 | | in = in[48..]; |
| 5802 | | if (in.len > 48) continue; |
| 5803 | | state = split[0] ^ (split[1] ^ split[2]); |
| 5804 | | break :large; |
| 5805 | | } |
| 5806 | | } |
| 5807 | | while (true) { |
| 5808 | | if (in.len <= 16) break; |
| 5809 | | state = mix(read(u64, in) ^ secret[1], read(u64, in[8..]) ^ state); |
| 5810 | | in = in[16..]; |
| 5811 | | if (in.len <= 16) break; |
| 5812 | | } |
| 5813 | | last[0] = read(u64, in[in.len - 16 ..]); |
| 5814 | | last[1] = read(u64, in[in.len - 8 ..]); |
| 5815 | | } |
| 5816 | | |
| 5817 | | last[0] ^= secret[1]; |
| 5818 | | last[1] ^= state; |
| 5819 | | mum(&last); |
| 5820 | | return mix(last[0] ^ secret[0] ^ starting_len, last[1] ^ secret[1]); |
| 5821 | | } |
| 5822 | | }; |