authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-30 22:29:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:47:57-07:00
logaed142ebaa65ff3ced948b18c55835b540e1e04a
tree94391b7ae2ce93571da7a33dd9fe86879a828e3d
parenta0d4ef0acf50db06fdde8ff229d20d15afc7d402

InternPool: further optimize Key hashing

This is a continuation of 2f24228c758bc8a35d13379703bc1695008212b0. This commit comes with smaller gains, but gains nonetheless. memcpy is showing up as much less interesting in callgrind output for behavior tests. Current status: this branch is 1.15 ± 0.02 times slower than merge-base.

1 files changed, 56 insertions(+), 72 deletions(-)

src/InternPool.zig+56-72
...@@ -197,7 +197,7 @@ pub const Key = union(enum) {...@@ -197,7 +197,7 @@ pub const Key = union(enum) {
197 undef: Index,197 undef: Index,
198 runtime_value: TypeValue,198 runtime_value: TypeValue,
199 simple_value: SimpleValue,199 simple_value: SimpleValue,
200 variable: Key.Variable,200 variable: Variable,
201 extern_func: ExternFunc,201 extern_func: ExternFunc,
202 func: Func,202 func: Func,
203 int: Key.Int,203 int: Key.Int,
...@@ -205,19 +205,19 @@ pub const Key = union(enum) {...@@ -205,19 +205,19 @@ pub const Key = union(enum) {
205 error_union: ErrorUnion,205 error_union: ErrorUnion,
206 enum_literal: NullTerminatedString,206 enum_literal: NullTerminatedString,
207 /// A specific enum tag, indicated by the integer tag value.207 /// A specific enum tag, indicated by the integer tag value.
208 enum_tag: Key.EnumTag,208 enum_tag: EnumTag,
209 /// An empty enum or union. TODO: this value's existence is strange, because such a type in209 /// An empty enum or union. TODO: this value's existence is strange, because such a type in
210 /// reality has no values. See #15909.210 /// reality has no values. See #15909.
211 /// Payload is the type for which we are an empty value.211 /// Payload is the type for which we are an empty value.
212 empty_enum_value: Index,212 empty_enum_value: Index,
213 float: Key.Float,213 float: Float,
214 ptr: Ptr,214 ptr: Ptr,
215 opt: Opt,215 opt: Opt,
216 /// An instance of a struct, array, or vector.216 /// An instance of a struct, array, or vector.
217 /// Each element/field stored as an `Index`.217 /// Each element/field stored as an `Index`.
218 /// In the case of sentinel-terminated arrays, the sentinel value *is* stored,218 /// In the case of sentinel-terminated arrays, the sentinel value *is* stored,
219 /// so the slice length will be one more than the type's array length.219 /// so the slice length will be one more than the type's array length.
220 aggregate: Key.Aggregate,220 aggregate: Aggregate,
221 /// An instance of a union.221 /// An instance of a union.
222 un: Union,222 un: Union,
223223
...@@ -226,14 +226,15 @@ pub const Key = union(enum) {...@@ -226,14 +226,15 @@ pub const Key = union(enum) {
226 /// A comptime function call with a memoized result.226 /// A comptime function call with a memoized result.
227 memoized_call: Key.MemoizedCall,227 memoized_call: Key.MemoizedCall,
228228
229 pub const TypeValue = struct {229 pub const TypeValue = extern struct {
230 ty: Index,230 ty: Index,
231 val: Index,231 val: Index,
232 };232 };
233233
234 pub const IntType = std.builtin.Type.Int;234 pub const IntType = std.builtin.Type.Int;
235235
236 pub const ErrorUnionType = struct {236 /// Extern for hashing via memory reinterpretation.
237 pub const ErrorUnionType = extern struct {
237 error_set_type: Index,238 error_set_type: Index,
238 payload_type: Index,239 payload_type: Index,
239 };240 };
...@@ -296,25 +297,27 @@ pub const Key = union(enum) {...@@ -296,25 +297,27 @@ pub const Key = union(enum) {
296 pub const AddressSpace = std.builtin.AddressSpace;297 pub const AddressSpace = std.builtin.AddressSpace;
297 };298 };
298299
299 pub const ArrayType = struct {300 /// Extern so that hashing can be done via memory reinterpreting.
301 pub const ArrayType = extern struct {
300 len: u64,302 len: u64,
301 child: Index,303 child: Index,
302 sentinel: Index = .none,304 sentinel: Index = .none,
303 };305 };
304306
305 pub const VectorType = struct {307 /// Extern so that hashing can be done via memory reinterpreting.
308 pub const VectorType = extern struct {
306 len: u32,309 len: u32,
307 child: Index,310 child: Index,
308 };311 };
309312
310 pub const OpaqueType = struct {313 pub const OpaqueType = extern struct {
311 /// The Decl that corresponds to the opaque itself.314 /// The Decl that corresponds to the opaque itself.
312 decl: Module.Decl.Index,315 decl: Module.Decl.Index,
313 /// Represents the declarations inside this opaque.316 /// Represents the declarations inside this opaque.
314 namespace: Module.Namespace.Index,317 namespace: Module.Namespace.Index,
315 };318 };
316319
317 pub const StructType = struct {320 pub const StructType = extern struct {
318 /// The `none` tag is used to represent a struct with no fields.321 /// The `none` tag is used to represent a struct with no fields.
319 index: Module.Struct.OptionalIndex,322 index: Module.Struct.OptionalIndex,
320 /// May be `none` if the struct has no declarations.323 /// May be `none` if the struct has no declarations.
...@@ -501,7 +504,8 @@ pub const Key = union(enum) {...@@ -501,7 +504,8 @@ pub const Key = union(enum) {
501 lib_name: OptionalNullTerminatedString,504 lib_name: OptionalNullTerminatedString,
502 };505 };
503506
504 pub const Func = struct {507 /// Extern so it can be hashed by reinterpreting memory.
508 pub const Func = extern struct {
505 ty: Index,509 ty: Index,
506 index: Module.Fn.Index,510 index: Module.Fn.Index,
507 };511 };
...@@ -534,7 +538,7 @@ pub const Key = union(enum) {...@@ -534,7 +538,7 @@ pub const Key = union(enum) {
534 };538 };
535 };539 };
536540
537 pub const Error = struct {541 pub const Error = extern struct {
538 ty: Index,542 ty: Index,
539 name: NullTerminatedString,543 name: NullTerminatedString,
540 };544 };
...@@ -549,7 +553,7 @@ pub const Key = union(enum) {...@@ -549,7 +553,7 @@ pub const Key = union(enum) {
549 };553 };
550 };554 };
551555
552 pub const EnumTag = struct {556 pub const EnumTag = extern struct {
553 /// The enum type.557 /// The enum type.
554 ty: Index,558 ty: Index,
555 /// The integer tag value which has the integer tag type of the enum.559 /// The integer tag value which has the integer tag type of the enum.
...@@ -600,14 +604,14 @@ pub const Key = union(enum) {...@@ -600,14 +604,14 @@ pub const Key = union(enum) {
600 };604 };
601605
602 /// `null` is represented by the `val` field being `none`.606 /// `null` is represented by the `val` field being `none`.
603 pub const Opt = struct {607 pub const Opt = extern struct {
604 /// This is the optional type; not the payload type.608 /// This is the optional type; not the payload type.
605 ty: Index,609 ty: Index,
606 /// This could be `none`, indicating the optional is `null`.610 /// This could be `none`, indicating the optional is `null`.
607 val: Index,611 val: Index,
608 };612 };
609613
610 pub const Union = struct {614 pub const Union = extern struct {
611 /// This is the union type; not the field type.615 /// This is the union type; not the field type.
612 ty: Index,616 ty: Index,
613 /// Indicates the active field.617 /// Indicates the active field.
...@@ -654,10 +658,10 @@ pub const Key = union(enum) {...@@ -654,10 +658,10 @@ pub const Key = union(enum) {
654 const asBytes = std.mem.asBytes;658 const asBytes = std.mem.asBytes;
655 const KeyTag = @typeInfo(Key).Union.tag_type.?;659 const KeyTag = @typeInfo(Key).Union.tag_type.?;
656 const seed = @enumToInt(@as(KeyTag, key));660 const seed = @enumToInt(@as(KeyTag, key));
657 switch (key) {661 return switch (key) {
658 .ptr_type => |x| return WyhashKing.hash(seed, asBytes(&x)),662 // TODO: assert no padding in these types
659663 inline .ptr_type,
660 inline .int_type,664 .func,
661 .array_type,665 .array_type,
662 .vector_type,666 .vector_type,
663 .opt_type,667 .opt_type,
...@@ -667,31 +671,26 @@ pub const Key = union(enum) {...@@ -667,31 +671,26 @@ pub const Key = union(enum) {
667 .simple_value,671 .simple_value,
668 .opt,672 .opt,
669 .struct_type,673 .struct_type,
670 .union_type,
671 .un,
672 .undef,674 .undef,
673 .err,675 .err,
674 .error_union,
675 .enum_literal,676 .enum_literal,
676 .enum_tag,677 .enum_tag,
677 .empty_enum_value,678 .empty_enum_value,
678 .inferred_error_set_type,679 .inferred_error_set_type,
679 => |info| {680 .un,
680 var hasher = std.hash.Wyhash.init(seed);681 => |x| WyhashKing.hash(seed, asBytes(&x)),
681 std.hash.autoHash(&hasher, info);
682 return hasher.final();
683 },
684682
685 .runtime_value => |runtime_value| {683 .int_type => |x| WyhashKing.hash(seed + @enumToInt(x.signedness), asBytes(&x.bits)),
686 var hasher = std.hash.Wyhash.init(seed);684 .union_type => |x| WyhashKing.hash(seed + @enumToInt(x.runtime_tag), asBytes(&x.index)),
687 std.hash.autoHash(&hasher, runtime_value.val);685
688 return hasher.final();686 .error_union => |x| switch (x.val) {
689 },687 .err_name => |y| WyhashKing.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)),
690 .opaque_type => |opaque_type| {688 .payload => |y| WyhashKing.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),
691 var hasher = std.hash.Wyhash.init(seed);
692 std.hash.autoHash(&hasher, opaque_type.decl);
693 return hasher.final();
694 },689 },
690
691 .runtime_value => |x| WyhashKing.hash(seed, asBytes(&x.val)),
692 .opaque_type => |x| WyhashKing.hash(seed, asBytes(&x.decl)),
693
695 .enum_type => |enum_type| {694 .enum_type => |enum_type| {
696 var hasher = std.hash.Wyhash.init(seed);695 var hasher = std.hash.Wyhash.init(seed);
697 std.hash.autoHash(&hasher, enum_type.decl);696 std.hash.autoHash(&hasher, enum_type.decl);
...@@ -703,18 +702,7 @@ pub const Key = union(enum) {...@@ -703,18 +702,7 @@ pub const Key = union(enum) {
703 std.hash.autoHash(&hasher, variable.decl);702 std.hash.autoHash(&hasher, variable.decl);
704 return hasher.final();703 return hasher.final();
705 },704 },
706 .extern_func => |extern_func| {705 .extern_func => |x| WyhashKing.hash(seed, asBytes(&x.ty) ++ asBytes(&x.decl)),
707 var hasher = std.hash.Wyhash.init(seed);
708 std.hash.autoHash(&hasher, extern_func.ty);
709 std.hash.autoHash(&hasher, extern_func.decl);
710 return hasher.final();
711 },
712 .func => |func| {
713 var hasher = std.hash.Wyhash.init(seed);
714 std.hash.autoHash(&hasher, func.ty);
715 std.hash.autoHash(&hasher, func.index);
716 return hasher.final();
717 },
718706
719 .int => |int| {707 .int => |int| {
720 var hasher = std.hash.Wyhash.init(seed);708 var hasher = std.hash.Wyhash.init(seed);
...@@ -865,11 +853,7 @@ pub const Key = union(enum) {...@@ -865,11 +853,7 @@ pub const Key = union(enum) {
865 return hasher.final();853 return hasher.final();
866 },854 },
867855
868 .memoized_decl => |memoized_decl| {856 .memoized_decl => |x| WyhashKing.hash(seed, asBytes(&x.val)),
869 var hasher = std.hash.Wyhash.init(seed);
870 std.hash.autoHash(&hasher, memoized_decl.val);
871 return hasher.final();
872 },
873857
874 .memoized_call => |memoized_call| {858 .memoized_call => |memoized_call| {
875 var hasher = std.hash.Wyhash.init(seed);859 var hasher = std.hash.Wyhash.init(seed);
...@@ -877,7 +861,7 @@ pub const Key = union(enum) {...@@ -877,7 +861,7 @@ pub const Key = union(enum) {
877 for (memoized_call.arg_values) |arg| std.hash.autoHash(&hasher, arg);861 for (memoized_call.arg_values) |arg| std.hash.autoHash(&hasher, arg);
878 return hasher.final();862 return hasher.final();
879 },863 },
880 }864 };
881 }865 }
882866
883 pub fn eql(a: Key, b: Key, ip: *const InternPool) bool {867 pub fn eql(a: Key, b: Key, ip: *const InternPool) bool {
...@@ -1474,7 +1458,7 @@ pub const Index = enum(u32) {...@@ -1474,7 +1458,7 @@ pub const Index = enum(u32) {
1474 error_union_error: struct { data: *Key.Error },1458 error_union_error: struct { data: *Key.Error },
1475 error_union_payload: struct { data: *Tag.TypeValue },1459 error_union_payload: struct { data: *Tag.TypeValue },
1476 enum_literal: struct { data: NullTerminatedString },1460 enum_literal: struct { data: NullTerminatedString },
1477 enum_tag: struct { data: *Key.EnumTag },1461 enum_tag: struct { data: *Tag.EnumTag },
1478 float_f16: struct { data: f16 },1462 float_f16: struct { data: f16 },
1479 float_f32: struct { data: f32 },1463 float_f32: struct { data: f32 },
1480 float_f64: struct { data: *Float64 },1464 float_f64: struct { data: *Float64 },
...@@ -1491,7 +1475,7 @@ pub const Index = enum(u32) {...@@ -1491,7 +1475,7 @@ pub const Index = enum(u32) {
1491 bytes: struct { data: *Bytes },1475 bytes: struct { data: *Bytes },
1492 aggregate: struct {1476 aggregate: struct {
1493 const @"data.ty.data.len orelse data.ty.data.fields_len" = opaque {};1477 const @"data.ty.data.len orelse data.ty.data.fields_len" = opaque {};
1494 data: *Aggregate,1478 data: *Tag.Aggregate,
1495 @"trailing.element_values.len": *@"data.ty.data.len orelse data.ty.data.fields_len",1479 @"trailing.element_values.len": *@"data.ty.data.len orelse data.ty.data.fields_len",
1496 trailing: struct { element_values: []Index },1480 trailing: struct { element_values: []Index },
1497 },1481 },
...@@ -1944,7 +1928,7 @@ pub const Tag = enum(u8) {...@@ -1944,7 +1928,7 @@ pub const Tag = enum(u8) {
1944 /// data is `NullTerminatedString` of the error name.1928 /// data is `NullTerminatedString` of the error name.
1945 enum_literal,1929 enum_literal,
1946 /// An enum tag value.1930 /// An enum tag value.
1947 /// data is extra index of `Key.EnumTag`.1931 /// data is extra index of `EnumTag`.
1948 enum_tag,1932 enum_tag,
1949 /// An f16 value.1933 /// An f16 value.
1950 /// data is float value bitcasted to u16 and zero-extended.1934 /// data is float value bitcasted to u16 and zero-extended.
...@@ -2121,6 +2105,14 @@ pub const Tag = enum(u8) {...@@ -2121,6 +2105,14 @@ pub const Tag = enum(u8) {
2121 _: u28 = 0,2105 _: u28 = 0,
2122 };2106 };
2123 };2107 };
2108
2109 /// Trailing:
2110 /// 0. element: Index for each len
2111 /// len is determined by the aggregate type.
2112 pub const Aggregate = struct {
2113 /// The type of the aggregate.
2114 ty: Index,
2115 };
2124};2116};
21252117
2126/// Trailing:2118/// Trailing:
...@@ -2161,14 +2153,6 @@ pub const Bytes = struct {...@@ -2161,14 +2153,6 @@ pub const Bytes = struct {
2161 bytes: String,2153 bytes: String,
2162};2154};
21632155
2164/// Trailing:
2165/// 0. element: Index for each len
2166/// len is determined by the aggregate type.
2167pub const Aggregate = struct {
2168 /// The type of the aggregate.
2169 ty: Index,
2170};
2171
2172pub const Repeated = struct {2156pub const Repeated = struct {
2173 /// The type of the aggregate.2157 /// The type of the aggregate.
2174 ty: Index,2158 ty: Index,
...@@ -2982,7 +2966,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -2982,7 +2966,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
2982 } };2966 } };
2983 },2967 },
2984 .aggregate => {2968 .aggregate => {
2985 const extra = ip.extraDataTrail(Aggregate, data);2969 const extra = ip.extraDataTrail(Tag.Aggregate, data);
2986 const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(extra.data.ty));2970 const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(extra.data.ty));
2987 const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]);2971 const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]);
2988 return .{ .aggregate = .{2972 return .{ .aggregate = .{
...@@ -3014,7 +2998,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3014,7 +2998,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3014 } };2998 } };
3015 },2999 },
3016 .enum_literal => .{ .enum_literal = @intToEnum(NullTerminatedString, data) },3000 .enum_literal => .{ .enum_literal = @intToEnum(NullTerminatedString, data) },
3017 .enum_tag => .{ .enum_tag = ip.extraData(Key.EnumTag, data) },3001 .enum_tag => .{ .enum_tag = ip.extraData(Tag.EnumTag, data) },
30183002
3019 .memoized_decl => .{ .memoized_decl = ip.extraData(Key.MemoizedDecl, data) },3003 .memoized_decl => .{ .memoized_decl = ip.extraData(Key.MemoizedDecl, data) },
3020 .memoized_call => {3004 .memoized_call => {
...@@ -3989,11 +3973,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3989,11 +3973,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
39893973
3990 try ip.extra.ensureUnusedCapacity(3974 try ip.extra.ensureUnusedCapacity(
3991 gpa,3975 gpa,
3992 @typeInfo(Aggregate).Struct.fields.len + len_including_sentinel,3976 @typeInfo(Tag.Aggregate).Struct.fields.len + len_including_sentinel,
3993 );3977 );
3994 ip.items.appendAssumeCapacity(.{3978 ip.items.appendAssumeCapacity(.{
3995 .tag = .aggregate,3979 .tag = .aggregate,
3996 .data = ip.addExtraAssumeCapacity(Aggregate{3980 .data = ip.addExtraAssumeCapacity(Tag.Aggregate{
3997 .ty = aggregate.ty,3981 .ty = aggregate.ty,
3998 }),3982 }),
3999 });3983 });
...@@ -4992,7 +4976,7 @@ fn dumpFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -4992,7 +4976,7 @@ fn dumpFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
4992 .error_set_error, .error_union_error => @sizeOf(Key.Error),4976 .error_set_error, .error_union_error => @sizeOf(Key.Error),
4993 .error_union_payload => @sizeOf(Tag.TypeValue),4977 .error_union_payload => @sizeOf(Tag.TypeValue),
4994 .enum_literal => 0,4978 .enum_literal => 0,
4995 .enum_tag => @sizeOf(Key.EnumTag),4979 .enum_tag => @sizeOf(Tag.EnumTag),
49964980
4997 .bytes => b: {4981 .bytes => b: {
4998 const info = ip.extraData(Bytes, data);4982 const info = ip.extraData(Bytes, data);
...@@ -5001,9 +4985,9 @@ fn dumpFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -5001,9 +4985,9 @@ fn dumpFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
5001 @boolToInt(ip.string_bytes.items[@enumToInt(info.bytes) + len - 1] != 0);4985 @boolToInt(ip.string_bytes.items[@enumToInt(info.bytes) + len - 1] != 0);
5002 },4986 },
5003 .aggregate => b: {4987 .aggregate => b: {
5004 const info = ip.extraData(Aggregate, data);4988 const info = ip.extraData(Tag.Aggregate, data);
5005 const fields_len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(info.ty));4989 const fields_len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(info.ty));
5006 break :b @sizeOf(Aggregate) + (@sizeOf(Index) * fields_len);4990 break :b @sizeOf(Tag.Aggregate) + (@sizeOf(Index) * fields_len);
5007 },4991 },
5008 .repeated => @sizeOf(Repeated),4992 .repeated => @sizeOf(Repeated),
50094993