InternPool: optimize zigTypeTag()

This is a particularly hot function, so we operate directly on encodings
rather than the more straightforward implementation of calling
`indexToKey`.

I measured this as 1.05 ± 0.04 times faster than the previous commit
with a ReleaseFast build against hello world (which includes std.debug
and formatted printing).

I also profiled the function and found that zigTypeTag() went from being
a major caller of `indexToKey` to being completely insignificant due to
being so fast.
This commit is contained in:
Andrew Kelley 2023-05-26 21:14:18 -07:00
parent fc358435cb
commit c8b0d4d149
2 changed files with 202 additions and 86 deletions

View file

@ -4899,3 +4899,204 @@ pub fn isNoReturn(ip: InternPool, ty: Index) bool {
},
};
}
/// This is a particularly hot function, so we operate directly on encodings
/// rather than the more straightforward implementation of calling `indexToKey`.
pub fn zigTypeTagOrPoison(ip: InternPool, index: Index) error{GenericPoison}!std.builtin.TypeId {
return switch (index) {
.u1_type,
.u8_type,
.i8_type,
.u16_type,
.i16_type,
.u29_type,
.u32_type,
.i32_type,
.u64_type,
.i64_type,
.u80_type,
.u128_type,
.i128_type,
.usize_type,
.isize_type,
.c_char_type,
.c_short_type,
.c_ushort_type,
.c_int_type,
.c_uint_type,
.c_long_type,
.c_ulong_type,
.c_longlong_type,
.c_ulonglong_type,
=> .Int,
.c_longdouble_type,
.f16_type,
.f32_type,
.f64_type,
.f80_type,
.f128_type,
=> .Float,
.anyopaque_type => .Opaque,
.bool_type => .Bool,
.void_type => .Void,
.type_type => .Type,
.anyerror_type => .ErrorSet,
.comptime_int_type => .ComptimeInt,
.comptime_float_type => .ComptimeFloat,
.noreturn_type => .NoReturn,
.anyframe_type => .AnyFrame,
.null_type => .Null,
.undefined_type => .Undefined,
.enum_literal_type => .EnumLiteral,
.atomic_order_type,
.atomic_rmw_op_type,
.calling_convention_type,
.address_space_type,
.float_mode_type,
.reduce_op_type,
.call_modifier_type,
=> .Enum,
.prefetch_options_type,
.export_options_type,
.extern_options_type,
=> .Struct,
.type_info_type => .Union,
.manyptr_u8_type,
.manyptr_const_u8_type,
.manyptr_const_u8_sentinel_0_type,
.single_const_pointer_to_comptime_int_type,
.slice_const_u8_type,
.slice_const_u8_sentinel_0_type,
=> .Pointer,
.anyerror_void_error_union_type => .ErrorUnion,
.empty_struct_type => .Struct,
.generic_poison_type => return error.GenericPoison,
// values, not types
.undef => unreachable,
.zero => unreachable,
.zero_usize => unreachable,
.zero_u8 => unreachable,
.one => unreachable,
.one_usize => unreachable,
.one_u8 => unreachable,
.four_u8 => unreachable,
.negative_one => unreachable,
.calling_convention_c => unreachable,
.calling_convention_inline => unreachable,
.void_value => unreachable,
.unreachable_value => unreachable,
.null_value => unreachable,
.bool_true => unreachable,
.bool_false => unreachable,
.empty_struct => unreachable,
.generic_poison => unreachable,
.var_args_param_type => unreachable, // special tag
_ => switch (ip.items.items(.tag)[@enumToInt(index)]) {
.type_int_signed,
.type_int_unsigned,
=> .Int,
.type_array_big,
.type_array_small,
=> .Array,
.type_vector => .Vector,
.type_pointer,
.type_slice,
=> .Pointer,
.type_optional => .Optional,
.type_anyframe => .AnyFrame,
.type_error_union => .ErrorUnion,
.type_error_set,
.type_inferred_error_set,
=> .ErrorSet,
.type_enum_auto,
.type_enum_explicit,
.type_enum_nonexhaustive,
=> .Enum,
.simple_type => unreachable, // handled via Index tag above
.type_opaque => .Opaque,
.type_struct,
.type_struct_ns,
.type_struct_anon,
.type_tuple_anon,
=> .Struct,
.type_union_tagged,
.type_union_untagged,
.type_union_safety,
=> .Union,
.type_function => .Fn,
// values, not types
.undef,
.runtime_value,
.simple_value,
.ptr_mut_decl,
.ptr_decl,
.ptr_int,
.ptr_eu_payload,
.ptr_opt_payload,
.ptr_comptime_field,
.ptr_elem,
.ptr_field,
.ptr_slice,
.opt_payload,
.opt_null,
.int_u8,
.int_u16,
.int_u32,
.int_i32,
.int_usize,
.int_comptime_int_u32,
.int_comptime_int_i32,
.int_small,
.int_positive,
.int_negative,
.int_lazy_align,
.int_lazy_size,
.error_set_error,
.error_union_error,
.error_union_payload,
.enum_literal,
.enum_tag,
.float_f16,
.float_f32,
.float_f64,
.float_f80,
.float_f128,
.float_c_longdouble_f80,
.float_c_longdouble_f128,
.float_comptime_float,
.variable,
.extern_func,
.func,
.only_possible_value,
.union_value,
.bytes,
.aggregate,
.repeated,
=> unreachable,
},
.none => unreachable, // special tag
};
}

View file

@ -23,92 +23,7 @@ pub const Type = struct {
}
pub fn zigTypeTagOrPoison(ty: Type, mod: *const Module) error{GenericPoison}!std.builtin.TypeId {
return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
.int_type => .Int,
.ptr_type => .Pointer,
.array_type => .Array,
.vector_type => .Vector,
.opt_type => .Optional,
.error_union_type => .ErrorUnion,
.error_set_type, .inferred_error_set_type => .ErrorSet,
.struct_type, .anon_struct_type => .Struct,
.union_type => .Union,
.opaque_type => .Opaque,
.enum_type => .Enum,
.func_type => .Fn,
.anyframe_type => .AnyFrame,
.simple_type => |s| switch (s) {
.f16,
.f32,
.f64,
.f80,
.f128,
.c_longdouble,
=> .Float,
.usize,
.isize,
.c_char,
.c_short,
.c_ushort,
.c_int,
.c_uint,
.c_long,
.c_ulong,
.c_longlong,
.c_ulonglong,
=> .Int,
.anyopaque => .Opaque,
.bool => .Bool,
.void => .Void,
.type => .Type,
.anyerror => .ErrorSet,
.comptime_int => .ComptimeInt,
.comptime_float => .ComptimeFloat,
.noreturn => .NoReturn,
.null => .Null,
.undefined => .Undefined,
.enum_literal => .EnumLiteral,
.atomic_order,
.atomic_rmw_op,
.calling_convention,
.address_space,
.float_mode,
.reduce_op,
.call_modifier,
=> .Enum,
.prefetch_options,
.export_options,
.extern_options,
=> .Struct,
.type_info => .Union,
.generic_poison => return error.GenericPoison,
},
// values, not types
.undef,
.runtime_value,
.simple_value,
.variable,
.extern_func,
.func,
.int,
.err,
.error_union,
.enum_literal,
.enum_tag,
.float,
.ptr,
.opt,
.aggregate,
.un,
=> unreachable,
};
return mod.intern_pool.zigTypeTagOrPoison(ty.toIntern());
}
pub fn baseZigTypeTag(self: Type, mod: *Module) std.builtin.TypeId {