diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-05-30 20:23:51 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-06-10 20:47:57 -0700 |
| commit | 82f6f164a1af6557451e580dcf3197ad94e5437e (patch) | |
| tree | 6a88050cac9da741c2ae8434ef0fe2989c411ee5 /src/Module.zig | |
| parent | c7d65fa3685a5f48cfedaa7a1adf758e1dc6d219 (diff) | |
| download | zig-82f6f164a1af6557451e580dcf3197ad94e5437e.tar.gz zig-82f6f164a1af6557451e580dcf3197ad94e5437e.zip | |
InternPool: improve hashing performance
Key.PtrType is now an extern struct so that hashing it can be done by
reinterpreting bytes directly. It also uses the same representation for
type_pointer Tag encoding and the Key. Accessing pointer attributes now
requires packed struct access, however, many operations are now a copy
of a u32 rather than several independent fields.
This function moves the top two most used Key variants - pointer types
and pointer values - to use a single-shot hash function that branches
for small keys instead of calling memcpy.
As a result, perf against merge-base went from 1.17x ± 0.04 slower to
1.12x ± 0.04 slower. After the pointer value hashing was changed, total
CPU instructions spent in memcpy went from 4.40% to 4.08%, and after
additionally improving pointer type hashing, it further decreased to
3.72%.
Diffstat (limited to 'src/Module.zig')
| -rw-r--r-- | src/Module.zig | 69 |
1 files changed, 38 insertions, 31 deletions
diff --git a/src/Module.zig b/src/Module.zig index b1a74932d3..862025d8f9 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -6430,8 +6430,10 @@ pub fn populateTestFunctions( // func try mod.intern(.{ .ptr = .{ .ty = try mod.intern(.{ .ptr_type = .{ - .elem_type = test_decl.ty.toIntern(), - .is_const = true, + .child = test_decl.ty.toIntern(), + .flags = .{ + .is_const = true, + }, } }), .addr = .{ .decl = test_decl_index }, } }), @@ -6466,9 +6468,11 @@ pub fn populateTestFunctions( { const new_ty = try mod.ptrType(.{ - .elem_type = test_fn_ty.toIntern(), - .is_const = true, - .size = .Slice, + .child = test_fn_ty.toIntern(), + .flags = .{ + .is_const = true, + .size = .Slice, + }, }); const new_val = decl.val; const new_init = try mod.intern(.{ .ptr = .{ @@ -6681,65 +6685,68 @@ pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error! pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { var canon_info = info; - const have_elem_layout = info.elem_type.toType().layoutIsResolved(mod); + const have_elem_layout = info.child.toType().layoutIsResolved(mod); - if (info.size == .C) canon_info.is_allowzero = true; + if (info.flags.size == .C) canon_info.flags.is_allowzero = true; // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee // type, we change it to 0 here. If this causes an assertion trip because the // pointee type needs to be resolved more, that needs to be done before calling // this ptr() function. - if (info.alignment.toByteUnitsOptional()) |info_align| { - if (have_elem_layout and info_align == info.elem_type.toType().abiAlignment(mod)) { - canon_info.alignment = .none; + if (info.flags.alignment.toByteUnitsOptional()) |info_align| { + if (have_elem_layout and info_align == info.child.toType().abiAlignment(mod)) { + canon_info.flags.alignment = .none; } } - switch (info.vector_index) { + switch (info.flags.vector_index) { // Canonicalize host_size. If it matches the bit size of the pointee type, // we change it to 0 here. If this causes an assertion trip, the pointee type // needs to be resolved before calling this ptr() function. - .none => if (have_elem_layout and info.host_size != 0) { - const elem_bit_size = info.elem_type.toType().bitSize(mod); - assert(info.bit_offset + elem_bit_size <= info.host_size * 8); - if (info.host_size * 8 == elem_bit_size) { - canon_info.host_size = 0; + .none => if (have_elem_layout and info.packed_offset.host_size != 0) { + const elem_bit_size = info.child.toType().bitSize(mod); + assert(info.packed_offset.bit_offset + elem_bit_size <= info.packed_offset.host_size * 8); + if (info.packed_offset.host_size * 8 == elem_bit_size) { + canon_info.packed_offset.host_size = 0; } }, .runtime => {}, - _ => assert(@enumToInt(info.vector_index) < info.host_size), + _ => assert(@enumToInt(info.flags.vector_index) < info.packed_offset.host_size), } return (try intern(mod, .{ .ptr_type = canon_info })).toType(); } pub fn singleMutPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { - return ptrType(mod, .{ .elem_type = child_type.toIntern() }); + return ptrType(mod, .{ .child = child_type.toIntern() }); } pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { - return ptrType(mod, .{ .elem_type = child_type.toIntern(), .is_const = true }); + return ptrType(mod, .{ + .child = child_type.toIntern(), + .flags = .{ + .is_const = true, + }, + }); } pub fn manyConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { - return ptrType(mod, .{ .elem_type = child_type.toIntern(), .size = .Many, .is_const = true }); + return ptrType(mod, .{ + .child = child_type.toIntern(), + .flags = .{ + .size = .Many, + .is_const = true, + }, + }); } pub fn adjustPtrTypeChild(mod: *Module, ptr_ty: Type, new_child: Type) Allocator.Error!Type { const info = Type.ptrInfoIp(&mod.intern_pool, ptr_ty.toIntern()); return mod.ptrType(.{ - .elem_type = new_child.toIntern(), - + .child = new_child.toIntern(), .sentinel = info.sentinel, - .alignment = info.alignment, - .host_size = info.host_size, - .bit_offset = info.bit_offset, - .vector_index = info.vector_index, - .size = info.size, - .is_const = info.is_const, - .is_volatile = info.is_volatile, - .is_allowzero = info.is_allowzero, - .address_space = info.address_space, + .flags = info.flags, + .packed_offset = info.packed_offset, }); } |
