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) {
197197 undef: Index,
198198 runtime_value: TypeValue,
199199 simple_value: SimpleValue,
200 variable: Key.Variable,
200 variable: Variable,
201201 extern_func: ExternFunc,
202202 func: Func,
203203 int: Key.Int,
......@@ -205,19 +205,19 @@ pub const Key = union(enum) {
205205 error_union: ErrorUnion,
206206 enum_literal: NullTerminatedString,
207207 /// A specific enum tag, indicated by the integer tag value.
208 enum_tag: Key.EnumTag,
208 enum_tag: EnumTag,
209209 /// An empty enum or union. TODO: this value's existence is strange, because such a type in
210210 /// reality has no values. See #15909.
211211 /// Payload is the type for which we are an empty value.
212212 empty_enum_value: Index,
213 float: Key.Float,
213 float: Float,
214214 ptr: Ptr,
215215 opt: Opt,
216216 /// An instance of a struct, array, or vector.
217217 /// Each element/field stored as an `Index`.
218218 /// In the case of sentinel-terminated arrays, the sentinel value *is* stored,
219219 /// so the slice length will be one more than the type's array length.
220 aggregate: Key.Aggregate,
220 aggregate: Aggregate,
221221 /// An instance of a union.
222222 un: Union,
223223
......@@ -226,14 +226,15 @@ pub const Key = union(enum) {
226226 /// A comptime function call with a memoized result.
227227 memoized_call: Key.MemoizedCall,
228228
229 pub const TypeValue = struct {
229 pub const TypeValue = extern struct {
230230 ty: Index,
231231 val: Index,
232232 };
233233
234234 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 {
237238 error_set_type: Index,
238239 payload_type: Index,
239240 };
......@@ -296,25 +297,27 @@ pub const Key = union(enum) {
296297 pub const AddressSpace = std.builtin.AddressSpace;
297298 };
298299
299 pub const ArrayType = struct {
300 /// Extern so that hashing can be done via memory reinterpreting.
301 pub const ArrayType = extern struct {
300302 len: u64,
301303 child: Index,
302304 sentinel: Index = .none,
303305 };
304306
305 pub const VectorType = struct {
307 /// Extern so that hashing can be done via memory reinterpreting.
308 pub const VectorType = extern struct {
306309 len: u32,
307310 child: Index,
308311 };
309312
310 pub const OpaqueType = struct {
313 pub const OpaqueType = extern struct {
311314 /// The Decl that corresponds to the opaque itself.
312315 decl: Module.Decl.Index,
313316 /// Represents the declarations inside this opaque.
314317 namespace: Module.Namespace.Index,
315318 };
316319
317 pub const StructType = struct {
320 pub const StructType = extern struct {
318321 /// The `none` tag is used to represent a struct with no fields.
319322 index: Module.Struct.OptionalIndex,
320323 /// May be `none` if the struct has no declarations.
......@@ -501,7 +504,8 @@ pub const Key = union(enum) {
501504 lib_name: OptionalNullTerminatedString,
502505 };
503506
504 pub const Func = struct {
507 /// Extern so it can be hashed by reinterpreting memory.
508 pub const Func = extern struct {
505509 ty: Index,
506510 index: Module.Fn.Index,
507511 };
......@@ -534,7 +538,7 @@ pub const Key = union(enum) {
534538 };
535539 };
536540
537 pub const Error = struct {
541 pub const Error = extern struct {
538542 ty: Index,
539543 name: NullTerminatedString,
540544 };
......@@ -549,7 +553,7 @@ pub const Key = union(enum) {
549553 };
550554 };
551555
552 pub const EnumTag = struct {
556 pub const EnumTag = extern struct {
553557 /// The enum type.
554558 ty: Index,
555559 /// The integer tag value which has the integer tag type of the enum.
......@@ -600,14 +604,14 @@ pub const Key = union(enum) {
600604 };
601605
602606 /// `null` is represented by the `val` field being `none`.
603 pub const Opt = struct {
607 pub const Opt = extern struct {
604608 /// This is the optional type; not the payload type.
605609 ty: Index,
606610 /// This could be `none`, indicating the optional is `null`.
607611 val: Index,
608612 };
609613
610 pub const Union = struct {
614 pub const Union = extern struct {
611615 /// This is the union type; not the field type.
612616 ty: Index,
613617 /// Indicates the active field.
......@@ -654,10 +658,10 @@ pub const Key = union(enum) {
654658 const asBytes = std.mem.asBytes;
655659 const KeyTag = @typeInfo(Key).Union.tag_type.?;
656660 const seed = @enumToInt(@as(KeyTag, key));
657 switch (key) {
658 .ptr_type => |x| return WyhashKing.hash(seed, asBytes(&x)),
659
660 inline .int_type,
661 return switch (key) {
662 // TODO: assert no padding in these types
663 inline .ptr_type,
664 .func,
661665 .array_type,
662666 .vector_type,
663667 .opt_type,
......@@ -667,31 +671,26 @@ pub const Key = union(enum) {
667671 .simple_value,
668672 .opt,
669673 .struct_type,
670 .union_type,
671 .un,
672674 .undef,
673675 .err,
674 .error_union,
675676 .enum_literal,
676677 .enum_tag,
677678 .empty_enum_value,
678679 .inferred_error_set_type,
679 => |info| {
680 var hasher = std.hash.Wyhash.init(seed);
681 std.hash.autoHash(&hasher, info);
682 return hasher.final();
683 },
680 .un,
681 => |x| WyhashKing.hash(seed, asBytes(&x)),
684682
685 .runtime_value => |runtime_value| {
686 var hasher = std.hash.Wyhash.init(seed);
687 std.hash.autoHash(&hasher, runtime_value.val);
688 return hasher.final();
689 },
690 .opaque_type => |opaque_type| {
691 var hasher = std.hash.Wyhash.init(seed);
692 std.hash.autoHash(&hasher, opaque_type.decl);
693 return hasher.final();
683 .int_type => |x| WyhashKing.hash(seed + @enumToInt(x.signedness), asBytes(&x.bits)),
684 .union_type => |x| WyhashKing.hash(seed + @enumToInt(x.runtime_tag), asBytes(&x.index)),
685
686 .error_union => |x| switch (x.val) {
687 .err_name => |y| WyhashKing.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)),
688 .payload => |y| WyhashKing.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),
694689 },
690
691 .runtime_value => |x| WyhashKing.hash(seed, asBytes(&x.val)),
692 .opaque_type => |x| WyhashKing.hash(seed, asBytes(&x.decl)),
693
695694 .enum_type => |enum_type| {
696695 var hasher = std.hash.Wyhash.init(seed);
697696 std.hash.autoHash(&hasher, enum_type.decl);
......@@ -703,18 +702,7 @@ pub const Key = union(enum) {
703702 std.hash.autoHash(&hasher, variable.decl);
704703 return hasher.final();
705704 },
706 .extern_func => |extern_func| {
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 },
705 .extern_func => |x| WyhashKing.hash(seed, asBytes(&x.ty) ++ asBytes(&x.decl)),
718706
719707 .int => |int| {
720708 var hasher = std.hash.Wyhash.init(seed);
......@@ -865,11 +853,7 @@ pub const Key = union(enum) {
865853 return hasher.final();
866854 },
867855
868 .memoized_decl => |memoized_decl| {
869 var hasher = std.hash.Wyhash.init(seed);
870 std.hash.autoHash(&hasher, memoized_decl.val);
871 return hasher.final();
872 },
856 .memoized_decl => |x| WyhashKing.hash(seed, asBytes(&x.val)),
873857
874858 .memoized_call => |memoized_call| {
875859 var hasher = std.hash.Wyhash.init(seed);
......@@ -877,7 +861,7 @@ pub const Key = union(enum) {
877861 for (memoized_call.arg_values) |arg| std.hash.autoHash(&hasher, arg);
878862 return hasher.final();
879863 },
880 }
864 };
881865 }
882866
883867 pub fn eql(a: Key, b: Key, ip: *const InternPool) bool {
......@@ -1474,7 +1458,7 @@ pub const Index = enum(u32) {
14741458 error_union_error: struct { data: *Key.Error },
14751459 error_union_payload: struct { data: *Tag.TypeValue },
14761460 enum_literal: struct { data: NullTerminatedString },
1477 enum_tag: struct { data: *Key.EnumTag },
1461 enum_tag: struct { data: *Tag.EnumTag },
14781462 float_f16: struct { data: f16 },
14791463 float_f32: struct { data: f32 },
14801464 float_f64: struct { data: *Float64 },
......@@ -1491,7 +1475,7 @@ pub const Index = enum(u32) {
14911475 bytes: struct { data: *Bytes },
14921476 aggregate: struct {
14931477 const @"data.ty.data.len orelse data.ty.data.fields_len" = opaque {};
1494 data: *Aggregate,
1478 data: *Tag.Aggregate,
14951479 @"trailing.element_values.len": *@"data.ty.data.len orelse data.ty.data.fields_len",
14961480 trailing: struct { element_values: []Index },
14971481 },
......@@ -1944,7 +1928,7 @@ pub const Tag = enum(u8) {
19441928 /// data is `NullTerminatedString` of the error name.
19451929 enum_literal,
19461930 /// An enum tag value.
1947 /// data is extra index of `Key.EnumTag`.
1931 /// data is extra index of `EnumTag`.
19481932 enum_tag,
19491933 /// An f16 value.
19501934 /// data is float value bitcasted to u16 and zero-extended.
......@@ -2121,6 +2105,14 @@ pub const Tag = enum(u8) {
21212105 _: u28 = 0,
21222106 };
21232107 };
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 };
21242116};
21252117
21262118/// Trailing:
......@@ -2161,14 +2153,6 @@ pub const Bytes = struct {
21612153 bytes: String,
21622154};
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
21722156pub const Repeated = struct {
21732157 /// The type of the aggregate.
21742158 ty: Index,
......@@ -2982,7 +2966,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
29822966 } };
29832967 },
29842968 .aggregate => {
2985 const extra = ip.extraDataTrail(Aggregate, data);
2969 const extra = ip.extraDataTrail(Tag.Aggregate, data);
29862970 const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(extra.data.ty));
29872971 const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]);
29882972 return .{ .aggregate = .{
......@@ -3014,7 +2998,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
30142998 } };
30152999 },
30163000 .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
30193003 .memoized_decl => .{ .memoized_decl = ip.extraData(Key.MemoizedDecl, data) },
30203004 .memoized_call => {
......@@ -3989,11 +3973,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
39893973
39903974 try ip.extra.ensureUnusedCapacity(
39913975 gpa,
3992 @typeInfo(Aggregate).Struct.fields.len + len_including_sentinel,
3976 @typeInfo(Tag.Aggregate).Struct.fields.len + len_including_sentinel,
39933977 );
39943978 ip.items.appendAssumeCapacity(.{
39953979 .tag = .aggregate,
3996 .data = ip.addExtraAssumeCapacity(Aggregate{
3980 .data = ip.addExtraAssumeCapacity(Tag.Aggregate{
39973981 .ty = aggregate.ty,
39983982 }),
39993983 });
......@@ -4992,7 +4976,7 @@ fn dumpFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
49924976 .error_set_error, .error_union_error => @sizeOf(Key.Error),
49934977 .error_union_payload => @sizeOf(Tag.TypeValue),
49944978 .enum_literal => 0,
4995 .enum_tag => @sizeOf(Key.EnumTag),
4979 .enum_tag => @sizeOf(Tag.EnumTag),
49964980
49974981 .bytes => b: {
49984982 const info = ip.extraData(Bytes, data);
......@@ -5001,9 +4985,9 @@ fn dumpFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
50014985 @boolToInt(ip.string_bytes.items[@enumToInt(info.bytes) + len - 1] != 0);
50024986 },
50034987 .aggregate => b: {
5004 const info = ip.extraData(Aggregate, data);
4988 const info = ip.extraData(Tag.Aggregate, data);
50054989 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);
50074991 },
50084992 .repeated => @sizeOf(Repeated),
50094993