From 5ab7ec5b16b08584764b1a02441299e18328df1e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 16:37:19 +0000 Subject: [PATCH] Support any comparable type for map keys --- src/check_type.cpp | 42 ++++++++++++++----- src/ir.cpp | 96 +++++++++++++++++++++++++++++++++++++++---- src/llvm_backend.cpp | 98 ++++++++++++++++++++++++++++++++++++++++---- src/types.cpp | 6 +++ 4 files changed, 214 insertions(+), 28 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 10ffe076c..9c8308757 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2849,26 +2849,48 @@ void init_map_internal_types(Type *type) { } void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { + key = core_type(key); + if (is_type_cstring(key)) { add_package_dependency(ctx, "runtime", "default_hasher_cstring"); } else if (is_type_string(key)) { add_package_dependency(ctx, "runtime", "default_hasher_string"); } else if (!is_type_polymorphic(key)) { - if (!is_type_simple_compare(key)) { + if (!is_type_comparable(key)) { return; } - if (is_type_struct(key)) { + if (key->kind == Type_Struct) { add_package_dependency(ctx, "runtime", "default_hasher_n"); - } + if (!is_type_simple_compare(key)) { + for_array(i, key->Struct.fields) { + Entity *field = key->Struct.fields[i]; + add_map_key_type_dependencies(ctx, field->type); + } + } + } else if (key->kind == Type_EnumeratedArray) { + add_package_dependency(ctx, "runtime", "default_hasher_n"); + if (!is_type_simple_compare(key->EnumeratedArray.elem)) { + add_map_key_type_dependencies(ctx, key->EnumeratedArray.elem); + } + } else if (key->kind == Type_Array) { + add_package_dependency(ctx, "runtime", "default_hasher_n"); + if (!is_type_simple_compare(key->Array.elem)) { + add_map_key_type_dependencies(ctx, key->Array.elem); + } + } else { + if (!is_type_simple_compare(key)) { + GB_PANIC("HERE"); + } - i64 sz = type_size_of(key); - switch (sz) { - case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; - case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; - case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; - case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; - case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; + i64 sz = type_size_of(key); + switch (sz) { + case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; + case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; + case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; + case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; + case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; + } } } } diff --git a/src/ir.cpp b/src/ir.cpp index 84f943eda..7e3050825 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4967,7 +4967,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { Type *original_type = type; - type = base_type(type); + type = core_type(type); Type *pt = alloc_type_pointer(type); GB_ASSERT(is_type_valid_for_keys(type)); @@ -5006,14 +5006,92 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { if (type->kind == Type_Struct) { type_set_offsets(type); - GB_ASSERT(is_type_simple_compare(type)); - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = ir_const_int(sz); - irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); - ir_emit(proc, ir_instr_return(proc, res)); + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + data = ir_emit_conv(proc, data, t_u8_ptr); + + auto args = array_make(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + irValue *field_hasher = ir_get_hasher_proc_for_type(m, field->type); + irValue *ptr = ir_emit_ptr_offset(proc, data, ir_const_uintptr(offset)); + + args[0] = ptr; + args[1] = seed; + seed = ir_emit_call(proc, field_hasher, args); + } + ir_emit(proc, ir_instr_return(proc, seed)); + } + } else if (type->kind == Type_Array) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + irValue *pres = ir_add_local_generated(proc, t_uintptr, false); + ir_emit_store(proc, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); + + data = ir_emit_conv(proc, data, pt); + + irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); + args[0] = ptr; + args[1] = ir_emit_load(proc, pres); + irValue *new_seed = ir_emit_call(proc, elem_hasher, args); + ir_emit_store(proc, pres, new_seed); + + ir_loop_end(proc, loop_data); + + irValue *res = ir_emit_load(proc, pres); + ir_emit(proc, ir_instr_return(proc, res)); + } + } else if (type->kind == Type_EnumeratedArray) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + irValue *pres = ir_add_local_generated(proc, t_uintptr, false); + ir_emit_store(proc, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); + + data = ir_emit_conv(proc, data, pt); + + irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); + args[0] = ptr; + args[1] = ir_emit_load(proc, pres); + irValue *new_seed = ir_emit_call(proc, elem_hasher, args); + ir_emit_store(proc, pres, new_seed); + + ir_loop_end(proc, loop_data); + + irValue *res = ir_emit_load(proc, pres); + ir_emit(proc, ir_instr_return(proc, res)); + } } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 4fe98bfcf..140d01292 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9251,7 +9251,7 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { Type *original_type = type; - type = base_type(type); + type = core_type(type); GB_ASSERT(is_type_valid_for_keys(type)); Type *pt = alloc_type_pointer(type); @@ -9284,14 +9284,94 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { if (type->kind == Type_Struct) { type_set_offsets(type); - GB_ASSERT(is_type_simple_compare(type)); - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = lb_const_int(m, t_int, sz); - lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); - LLVMBuildRet(p->builder, res.value); + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + data = lb_emit_conv(p, data, t_u8_ptr); + + auto args = array_make(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + lbValue field_hasher = lb_get_hasher_proc_for_type(m, field->type); + lbValue ptr = lb_emit_ptr_offset(p, data, lb_const_int(m, t_uintptr, offset)); + + args[0] = ptr; + args[1] = seed; + seed = lb_emit_call(p, field_hasher, args); + } + LLVMBuildRet(p->builder, seed.value); + } + } else if (type->kind == Type_Array) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + lbAddr pres = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = lb_loop_start(p, type->Array.count, t_i32); + + data = lb_emit_conv(p, data, pt); + + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, pres); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, pres, new_seed); + + lb_loop_end(p, loop_data); + + lbValue res = lb_addr_load(p, pres); + LLVMBuildRet(p->builder, res.value); + } + } else if (type->kind == Type_EnumeratedArray) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + lbAddr res = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, res, seed); + + auto args = array_make(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->EnumeratedArray.elem); + + auto loop_data = lb_loop_start(p, type->EnumeratedArray.count, t_i32); + + data = lb_emit_conv(p, data, pt); + + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, res); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, res, new_seed); + + lb_loop_end(p, loop_data); + + lbValue vres = lb_addr_load(p, res); + LLVMBuildRet(p->builder, vres.value); + } + + } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/types.cpp b/src/types.cpp index f8f7dd66e..df87cb645 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1542,6 +1542,8 @@ bool is_type_valid_for_keys(Type *t) { if (is_type_untyped(t)) { return false; } + return is_type_comparable(t); +#if 0 if (is_type_integer(t)) { return true; } @@ -1560,8 +1562,12 @@ bool is_type_valid_for_keys(Type *t) { if (is_type_simple_compare(t)) { return true; } + if (is_type_comparable(t)) { + return true; + } return false; +#endif } bool is_type_valid_bit_set_elem(Type *t) {