Sema: rewrite monomorphed_funcs usage

In an effort to delete `Value.hashUncoerced`, generic instantiation has
been redesigned.  Instead of just storing instantiations in
`monomorphed_funcs`, partially instantiated generic argument types are
also cached.  This isn't quite the single `getOrPut` that it used to be,
but one `get` per generic argument plus one get for the instantiation,
with an equal number of `put`s per unique instantiation isn't bad.
This commit is contained in:
Jacob Young
2023-06-02 04:24:25 -04:00
committed by Andrew Kelley
parent 04e66e6b4d
commit da24ea7f36
3 changed files with 126 additions and 224 deletions

View File

@@ -99,6 +99,7 @@ tmp_hack_arena: std.heap.ArenaAllocator,
/// This is currently only used for string literals.
memoized_decls: std.AutoHashMapUnmanaged(InternPool.Index, Decl.Index) = .{},
monomorphed_func_keys: std.ArrayListUnmanaged(InternPool.Index) = .{},
/// The set of all the generic function instantiations. This is used so that when a generic
/// function is called twice with the same comptime parameter arguments, both calls dispatch
/// to the same function.
@@ -202,24 +203,40 @@ pub const CImportError = struct {
}
};
const MonomorphedFuncsSet = std.HashMapUnmanaged(
Fn.Index,
void,
pub const MonomorphedFuncKey = struct { func: Fn.Index, args_index: u32, args_len: u32 };
pub const MonomorphedFuncAdaptedKey = struct { func: Fn.Index, args: []const InternPool.Index };
pub const MonomorphedFuncsSet = std.HashMapUnmanaged(
MonomorphedFuncKey,
InternPool.Index,
MonomorphedFuncsContext,
std.hash_map.default_max_load_percentage,
);
const MonomorphedFuncsContext = struct {
pub const MonomorphedFuncsContext = struct {
mod: *Module,
pub fn eql(ctx: @This(), a: Fn.Index, b: Fn.Index) bool {
_ = ctx;
return a == b;
pub fn eql(_: @This(), a: MonomorphedFuncKey, b: MonomorphedFuncKey) bool {
return std.meta.eql(a, b);
}
/// Must match `Sema.GenericCallAdapter.hash`.
pub fn hash(ctx: @This(), key: Fn.Index) u64 {
return ctx.mod.funcPtr(key).hash;
pub fn hash(ctx: @This(), key: MonomorphedFuncKey) u64 {
const key_args = ctx.mod.monomorphed_func_keys.items[key.args_index..][0..key.args_len];
return std.hash.Wyhash.hash(@enumToInt(key.func), std.mem.sliceAsBytes(key_args));
}
};
pub const MonomorphedFuncsAdaptedContext = struct {
mod: *Module,
pub fn eql(ctx: @This(), adapted_key: MonomorphedFuncAdaptedKey, other_key: MonomorphedFuncKey) bool {
const other_key_args = ctx.mod.monomorphed_func_keys.items[other_key.args_index..][0..other_key.args_len];
return adapted_key.func == other_key.func and std.mem.eql(InternPool.Index, adapted_key.args, other_key_args);
}
pub fn hash(_: @This(), adapted_key: MonomorphedFuncAdaptedKey) u64 {
return std.hash.Wyhash.hash(@enumToInt(adapted_key.func), std.mem.sliceAsBytes(adapted_key.args));
}
};
@@ -571,9 +588,6 @@ pub const Decl = struct {
pub fn clearValues(decl: *Decl, mod: *Module) void {
if (decl.getOwnedFunctionIndex(mod).unwrap()) |func| {
_ = mod.align_stack_fns.remove(func);
if (mod.funcPtr(func).comptime_args != null) {
_ = mod.monomorphed_funcs.removeContext(func, .{ .mod = mod });
}
mod.destroyFunc(func);
}
}