diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index 792b1edc6..85d3303c2 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -422,19 +422,17 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm delete(key, p.allocator) return err } - - hash := runtime.Map_Hash { - hash = runtime.default_hasher_string(&key, 0), - key_ptr = &key, - } - + + key_hash := runtime.default_hasher_string(&key, 0) + key_ptr := rawptr(&key) + key_cstr: cstring if reflect.is_cstring(t.key) { key_cstr = cstring(raw_data(key)) - hash.key_ptr = &key_cstr + key_ptr = &key_cstr } - set_ptr := runtime.__dynamic_map_set(header, hash, map_backing_value.data) + set_ptr := runtime.__dynamic_map_set(header, key_hash, key_ptr, map_backing_value.data) if set_ptr == nil { delete(key, p.allocator) } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 0310aff6d..81cce8caf 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -394,7 +394,7 @@ Raw_Dynamic_Array :: struct { } Raw_Map :: struct { - hashes: []int, + hashes: []Map_Index, entries: Raw_Dynamic_Array, } diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 4c736b6f6..f8e39b8b2 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -289,14 +289,14 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) { entries := (^Raw_Dynamic_Array)(&raw_map.entries) entries.len = 0 for _, i in raw_map.hashes { - raw_map.hashes[i] = -1 + raw_map.hashes[i] = MAP_SENTINEL } } @builtin reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) { if m != nil { - __dynamic_map_reserve(__get_map_header(m), capacity, loc) + __dynamic_map_reserve(__get_map_header(m), uint(capacity), loc) } } @@ -325,9 +325,8 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: if m != nil { key := key h := __get_map_header(m) - hash := __get_map_hash(&key) - fr := __dynamic_map_find(h, hash) - if fr.entry_index >= 0 { + fr := __map_find(h, &key) + if fr.entry_index != MAP_SENTINEL { entry := __dynamic_map_get_entry(h, fr.entry_index) deleted_key = (^K)(uintptr(entry)+h.key_offset)^ deleted_value = (^V)(uintptr(entry)+h.value_offset)^ @@ -335,7 +334,6 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: __dynamic_map_erase(h, fr) } } - return } @@ -674,9 +672,8 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) { key, value := key, value h := __get_map_header(m) - hash := __get_map_hash(&key) - - data := uintptr(__dynamic_map_set(h, hash, &value, loc)) + + data := uintptr(__dynamic_map_set(h, __get_map_key_hash(&key), &key, &value, loc)) return (^V)(data + h.value_offset) } diff --git a/core/runtime/dynamic_array_internal.odin b/core/runtime/dynamic_array_internal.odin index b6a685fcf..267ee0785 100644 --- a/core/runtime/dynamic_array_internal.odin +++ b/core/runtime/dynamic_array_internal.odin @@ -59,6 +59,8 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c return } + new_cap := new_cap + new_cap = max(new_cap, 0) old_size := array.cap * elem_size new_size := new_cap * elem_size allocator := array.allocator diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index d2aaa49f4..6ca9455ef 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -11,30 +11,27 @@ Map_Hash :: struct { key_ptr: rawptr, // address of Map_Entry_Header.key } -__get_map_hash :: proc "contextless" (k: ^$K) -> (map_hash: Map_Hash) { +__get_map_key_hash :: #force_inline proc "contextless" (k: ^$K) -> uintptr { hasher := intrinsics.type_hasher_proc(K) - map_hash.key_ptr = k - map_hash.hash = hasher(k, 0) - return + return hasher(k, 0) } -__get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) { - hash.hash = entry.hash - hash.key_ptr = rawptr(uintptr(entry) + h.key_offset) - return +__get_map_entry_key_ptr :: #force_inline proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> rawptr { + return rawptr(uintptr(entry) + h.key_offset) } - +Map_Index :: distinct uint +MAP_SENTINEL :: ~Map_Index(0) Map_Find_Result :: struct { - hash_index: int, - entry_prev: int, - entry_index: int, + hash_index: Map_Index, + entry_prev: Map_Index, + entry_index: Map_Index, } Map_Entry_Header :: struct { hash: uintptr, - next: int, + next: Map_Index, /* key: Key_Value, value: Value_Type, @@ -183,7 +180,7 @@ __get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map) } -__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool { +__slice_resize :: proc "odin" (array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool { array := (^Raw_Slice)(array_) if new_count < array.len { @@ -205,86 +202,95 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l return false } -__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) { - for i in 0.. (did_shrink: bool) { +__dynamic_map_shrink :: proc "odin" (h: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) { c := context - if m.entries.allocator.procedure != nil { - c.allocator = m.entries.allocator + if h.m.entries.allocator.procedure != nil { + c.allocator = h.m.entries.allocator } context = c - return __dynamic_array_shrink(&m.entries, entry_size, entry_align, cap, loc) + return __dynamic_array_shrink(&h.m.entries, h.entry_size, h.entry_align, cap, loc) } -__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) { - #force_inline __dynamic_map_reserve(header, new_count, loc) -} - -__dynamic_map_get :: proc(h: Map_Header, hash: Map_Hash) -> rawptr { - index := __dynamic_map_find(h, hash).entry_index - if index >= 0 { +// USED INTERNALLY BY THE COMPILER +__dynamic_map_get :: proc "contextless" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr) -> rawptr { + index := __dynamic_map_find(h, key_hash, key_ptr).entry_index + if index != MAP_SENTINEL { data := uintptr(__dynamic_map_get_entry(h, index)) return rawptr(data + h.value_offset) } return nil } -__dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check { - index: int +// USED INTERNALLY BY THE COMPILER +__dynamic_map_set :: proc "odin" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check { + add_entry :: proc "odin" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr, loc := #caller_location) -> Map_Index { + prev := Map_Index(h.m.entries.len) + c := Map_Index(__dynamic_array_append_nothing(&h.m.entries, h.entry_size, h.entry_align, loc)) + if c != prev { + end := __dynamic_map_get_entry(h, c-1) + end.hash = key_hash + mem_copy(rawptr(uintptr(end) + h.key_offset), key_ptr, h.key_size) + end.next = MAP_SENTINEL + } + return prev + } + + index := MAP_SENTINEL if len(h.m.hashes) == 0 { __dynamic_map_reserve(h, INITIAL_MAP_CAP, loc) __dynamic_map_grow(h, loc) } - fr := __dynamic_map_find(h, hash) - if fr.entry_index >= 0 { + fr := __dynamic_map_find(h, key_hash, key_ptr) + if fr.entry_index != MAP_SENTINEL { index = fr.entry_index } else { - index = __dynamic_map_add_entry(h, hash, loc) - if fr.entry_prev >= 0 { + index = add_entry(h, key_hash, key_ptr, loc) + if fr.entry_prev != MAP_SENTINEL { entry := __dynamic_map_get_entry(h, fr.entry_prev) entry.next = index - } else if fr.hash_index >= 0 { + } else if fr.hash_index != MAP_SENTINEL { h.m.hashes[fr.hash_index] = index } else { return nil @@ -292,12 +298,12 @@ __dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := # } e := __dynamic_map_get_entry(h, index) - e.hash = hash.hash + e.hash = key_hash key := rawptr(uintptr(e) + h.key_offset) - mem_copy(key, hash.key_ptr, h.key_size) - val := rawptr(uintptr(e) + h.value_offset) + + mem_copy(key, key_ptr, h.key_size) mem_copy(val, value, h.value_size) if __dynamic_map_full(h) { @@ -309,13 +315,11 @@ __dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := # @(private="file") -ceil_to_pow2 :: proc "contextless" (n: int) -> int { - n := n - if n <= 0 { - return 0 - } else if n <= 2 { +ceil_to_pow2 :: proc "contextless" (n: uint) -> uint { + if n <= 2 { return n } + n := n n -= 1 n |= n >> 1 n |= n >> 2 @@ -329,33 +333,33 @@ ceil_to_pow2 :: proc "contextless" (n: int) -> int { return n } -__dynamic_map_grow :: proc(using h: Map_Header, loc := #caller_location) { - // TODO(bill): Determine an efficient growing rate - new_count := max(m.entries.cap * 2, INITIAL_MAP_CAP) - __dynamic_map_rehash(h, new_count, loc) +__dynamic_map_grow :: proc "odin" (h: Map_Header, loc := #caller_location) { + new_count := max(uint(h.m.entries.cap) * 2, INITIAL_MAP_CAP) + // Rehash through Reserve + __dynamic_map_reserve(h, new_count, loc) } -__dynamic_map_full :: #force_inline proc "contextless" (using h: Map_Header) -> bool { - return int(0.75 * f64(len(m.hashes))) <= m.entries.len +__dynamic_map_full :: #force_inline proc "contextless" (h: Map_Header) -> bool { + return int(0.75 * f64(len(h.m.hashes))) <= h.m.entries.len } +__dynamic_map_find_from_entry :: proc "contextless" (h: Map_Header, e: ^Map_Entry_Header) -> Map_Find_Result #no_bounds_check { + key_ptr := __get_map_entry_key_ptr(h, e) + return __dynamic_map_find(h, e.hash, key_ptr) -__dynamic_map_hash_equal :: proc "contextless" (h: Map_Header, a, b: Map_Hash) -> bool { - return a.hash == b.hash && h.equal(a.key_ptr, b.key_ptr) } -__dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Result #no_bounds_check { - fr := Map_Find_Result{-1, -1, -1} - if n := uintptr(len(m.hashes)); n != 0 { - fr.hash_index = int(hash.hash & (n-1)) - fr.entry_index = m.hashes[fr.hash_index] - for fr.entry_index >= 0 { +__dynamic_map_find :: proc "contextless" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr) -> Map_Find_Result #no_bounds_check { + fr := Map_Find_Result{MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL} + if n := uintptr(len(h.m.hashes)); n != 0 { + fr.hash_index = Map_Index(key_hash & (n-1)) + fr.entry_index = h.m.hashes[fr.hash_index] + for fr.entry_index != MAP_SENTINEL { entry := __dynamic_map_get_entry(h, fr.entry_index) - entry_hash := __get_map_hash_from_entry(h, entry) - if __dynamic_map_hash_equal(h, entry_hash, hash) { + entry_key_ptr := __get_map_entry_key_ptr(h, entry) + if entry.hash == key_hash && h.equal(entry_key_ptr, key_ptr) { return fr } - // assert(entry.next < m.entries.len) fr.entry_prev = fr.entry_index fr.entry_index = entry.next @@ -364,58 +368,38 @@ __dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Resu return fr } -__dynamic_map_add_entry :: proc(using h: Map_Header, hash: Map_Hash, loc := #caller_location) -> int { - prev := m.entries.len - c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc) - if c != prev { - end := __dynamic_map_get_entry(h, c-1) - end.hash = hash.hash - mem_copy(rawptr(uintptr(end) + key_offset), hash.key_ptr, key_size) - end.next = -1 - } - return prev +// Utility procedure used by other runtime procedures +__map_find :: proc "contextless" (h: Map_Header, key_ptr: ^$K) -> Map_Find_Result #no_bounds_check { + hash := __get_map_key_hash(key_ptr) + return #force_inline __dynamic_map_find(h, hash, key_ptr) } -__dynamic_map_delete_key :: proc(using h: Map_Header, hash: Map_Hash) { - fr := __dynamic_map_find(h, hash) - if fr.entry_index >= 0 { - __dynamic_map_erase(h, fr) - } +__dynamic_map_get_entry :: #force_inline proc "contextless" (h: Map_Header, index: Map_Index) -> ^Map_Entry_Header { + return (^Map_Entry_Header)(uintptr(h.m.entries.data) + uintptr(index*Map_Index(h.entry_size))) } -__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header { - // assert(0 <= index && index < m.entries.len) - return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size)) -} - -__dynamic_map_copy_entry :: proc(h: Map_Header, new, old: ^Map_Entry_Header) { - mem_copy(new, old, h.entry_size) -} - -__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds_check { - if fr.entry_prev < 0 { - m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next - } else { +__dynamic_map_erase :: proc "contextless" (h: Map_Header, fr: Map_Find_Result) #no_bounds_check { + if fr.entry_prev != MAP_SENTINEL { prev := __dynamic_map_get_entry(h, fr.entry_prev) curr := __dynamic_map_get_entry(h, fr.entry_index) prev.next = curr.next - } - if fr.entry_index == m.entries.len-1 { - // NOTE(bill): No need to do anything else, just pop } else { + h.m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next + } + last_index := Map_Index(h.m.entries.len-1) + if fr.entry_index != last_index { old := __dynamic_map_get_entry(h, fr.entry_index) - end := __dynamic_map_get_entry(h, m.entries.len-1) - __dynamic_map_copy_entry(h, old, end) + end := __dynamic_map_get_entry(h, last_index) + mem_copy(old, end, h.entry_size) - old_hash := __get_map_hash_from_entry(h, old) - - if last := __dynamic_map_find(h, old_hash); last.entry_prev >= 0 { - last_entry := __dynamic_map_get_entry(h, last.entry_prev) - last_entry.next = fr.entry_index + last := __dynamic_map_find_from_entry(h, old) + if last.entry_prev != MAP_SENTINEL { + e := __dynamic_map_get_entry(h, last.entry_prev) + e.next = fr.entry_index } else { - m.hashes[last.hash_index] = fr.entry_index + h.m.hashes[last.hash_index] = fr.entry_index } } - m.entries.len -= 1 + h.m.entries.len -= 1 } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index aa901d22f..142ecc348 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -502,48 +502,58 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type)); - lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later map_type = base_type(map_type); GB_ASSERT(map_type->kind == Type_Map); - Type *key_type = map_type->Map.key; - Type *val_type = map_type->Map.value; - gb_unused(val_type); + lbAddr h = {}; + lbAddr *found = map_get(&p->map_header_cache, map_val_ptr.value); + if (found != nullptr) { + h = *found; + } else { + h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later - GB_ASSERT(map_type->Map.entry_type->kind == Type_Struct); - map_type->Map.entry_type->cached_size = -1; - map_type->Map.entry_type->Struct.are_offsets_set = false; - - i64 entry_size = type_size_of (map_type->Map.entry_type); - i64 entry_align = type_align_of (map_type->Map.entry_type); - - i64 key_offset = type_offset_of(map_type->Map.entry_type, 2); - i64 key_size = type_size_of (map_type->Map.key); + Type *key_type = map_type->Map.key; + Type *val_type = map_type->Map.value; + gb_unused(val_type); - i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); - i64 value_size = type_size_of (map_type->Map.value); - - - Type *map_header_base = base_type(t_map_header); - GB_ASSERT(map_header_base->Struct.fields.count == 8); - Type *raw_map_ptr_type = map_header_base->Struct.fields[0]->type; - LLVMValueRef const_values[8] = {}; - const_values[0] = LLVMConstNull(lb_type(p->module, raw_map_ptr_type)); - const_values[1] = lb_get_equal_proc_for_type(p->module, key_type) .value; - const_values[2] = lb_const_int(p->module, t_int, entry_size) .value; - const_values[3] = lb_const_int(p->module, t_int, entry_align) .value; - const_values[4] = lb_const_int(p->module, t_uintptr, key_offset) .value; - const_values[5] = lb_const_int(p->module, t_int, key_size) .value; - const_values[6] = lb_const_int(p->module, t_uintptr, value_offset).value; - const_values[7] = lb_const_int(p->module, t_int, value_size) .value; - - LLVMValueRef const_value = llvm_const_named_struct(p->module, t_map_header, const_values, gb_count_of(const_values)); - LLVMBuildStore(p->builder, const_value, h.addr.value); - - // NOTE(bill): Removes unnecessary allocation if split gep - lbValue gep0 = lb_emit_struct_ep(p, h.addr, 0); - lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type)); - lb_emit_store(p, gep0, m); + GB_ASSERT(map_type->Map.entry_type->kind == Type_Struct); + map_type->Map.entry_type->cached_size = -1; + map_type->Map.entry_type->Struct.are_offsets_set = false; + + i64 entry_size = type_size_of (map_type->Map.entry_type); + i64 entry_align = type_align_of (map_type->Map.entry_type); + + i64 key_offset = type_offset_of(map_type->Map.entry_type, 2); + i64 key_size = type_size_of (map_type->Map.key); + + i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); + i64 value_size = type_size_of (map_type->Map.value); + + + Type *map_header_base = base_type(t_map_header); + GB_ASSERT(map_header_base->Struct.fields.count == 8); + Type *raw_map_ptr_type = map_header_base->Struct.fields[0]->type; + LLVMValueRef const_values[8] = {}; + const_values[0] = LLVMConstNull(lb_type(p->module, raw_map_ptr_type)); + const_values[1] = lb_get_equal_proc_for_type(p->module, key_type) .value; + const_values[2] = lb_const_int(p->module, t_int, entry_size) .value; + const_values[3] = lb_const_int(p->module, t_int, entry_align) .value; + const_values[4] = lb_const_int(p->module, t_uintptr, key_offset) .value; + const_values[5] = lb_const_int(p->module, t_int, key_size) .value; + const_values[6] = lb_const_int(p->module, t_uintptr, value_offset).value; + const_values[7] = lb_const_int(p->module, t_int, value_size) .value; + + LLVMValueRef const_value = llvm_const_named_struct(p->module, t_map_header, const_values, gb_count_of(const_values)); + LLVMBuildStore(p->builder, const_value, h.addr.value); + + // NOTE(bill): Removes unnecessary allocation if split gep + lbValue gep0 = lb_emit_struct_ep(p, h.addr, 0); + lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type)); + lb_emit_store(p, gep0, m); + + + map_set(&p->map_header_cache, map_val_ptr.value, h); + } return lb_addr_load(p, h); } @@ -595,14 +605,12 @@ lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) { return hashed_key; } -lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) { - lbAddr v = lb_add_local_generated(p, t_map_hash, true); - lbValue vp = lb_addr_get_ptr(p, v); - key = lb_emit_conv(p, key, key_type); - +lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) { lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); + if (key_ptr_) *key_ptr_ = key_ptr; + lbValue hashed_key = lb_const_hash(p->module, key, key_type); if (hashed_key.value == nullptr) { lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type); @@ -613,10 +621,7 @@ lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) { hashed_key = lb_emit_call(p, hasher, args); } - lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key); - lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr); - - return lb_addr_load(p, v); + return hashed_key; } void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, @@ -625,17 +630,19 @@ void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_ GB_ASSERT(map_type->kind == Type_Map); lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_hash(p, map_key, map_type->Map.key); + lbValue key_ptr = {}; + lbValue key_hash = lb_gen_map_key_hash(p, map_key, map_type->Map.key, &key_ptr); lbValue v = lb_emit_conv(p, map_value, map_type->Map.value); lbAddr value_addr = lb_add_local_generated(p, v.type, false); lb_addr_store(p, value_addr, v); - auto args = array_make(permanent_allocator(), 4); + auto args = array_make(permanent_allocator(), 5); args[0] = h; - args[1] = key; - args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr); - args[3] = lb_emit_source_code_location(p, node); + args[1] = key_hash; + args[2] = key_ptr; + args[3] = lb_emit_conv(p, value_addr.addr, t_rawptr); + args[4] = lb_emit_source_code_location(p, node); lb_emit_runtime_call(p, "__dynamic_map_set", args); } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 79f0f37e7..d622f3661 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -308,6 +308,7 @@ struct lbProcedure { PtrMap selector_values; PtrMap selector_addr; + PtrMap map_header_cache; }; @@ -444,7 +445,7 @@ String lb_get_const_string(lbModule *m, lbValue value); lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true); lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id); lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type); -lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type); +lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_); void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node); lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7c92c517c..3ab73a27b 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1423,15 +1423,9 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { switch (rt->kind) { case Type_Map: { - lbValue addr = lb_address_from_load_or_generate_local(p, right); - lbValue h = lb_gen_map_header(p, addr, rt); - lbValue key = lb_gen_map_hash(p, left, rt->Map.key); - - auto args = array_make(permanent_allocator(), 2); - args[0] = h; - args[1] = key; - - lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); + lbValue map_ptr = lb_address_from_load_or_generate_local(p, right); + lbValue key = left; + lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, key); if (be->op.kind == Token_in) { return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); } else { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 1f8fccdcb..55b09cbfc 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -383,6 +383,21 @@ Type *lb_addr_type(lbAddr const &addr) { return type_deref(addr.addr.type); } +lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key) { + Type *map_type = base_type(type_deref(map_ptr.type)); + lbValue h = lb_gen_map_header(p, map_ptr, map_type); + + lbValue key_ptr = {}; + auto args = array_make(permanent_allocator(), 3); + args[0] = h; + args[1] = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr); + args[2] = key_ptr; + + lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); + + return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value)); +} + lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { if (addr.addr.value == nullptr) { GB_PANIC("Illegal addr -> nullptr"); @@ -390,19 +405,8 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { } switch (addr.kind) { - case lbAddr_Map: { - Type *map_type = base_type(addr.map.type); - lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key); - - auto args = array_make(permanent_allocator(), 2); - args[0] = h; - args[1] = key; - - lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); - - return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value)); - } + case lbAddr_Map: + return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); case lbAddr_RelativePointer: { Type *rel_ptr = base_type(lb_addr_type(addr)); @@ -1059,16 +1063,11 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { } else if (addr.kind == lbAddr_Map) { - Type *map_type = base_type(addr.map.type); + Type *map_type = base_type(type_deref(addr.addr.type)); + GB_ASSERT(map_type->kind == Type_Map); lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true); - lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key); - auto args = array_make(permanent_allocator(), 2); - args[0] = h; - args[1] = key; - - lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); + lbValue ptr = lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 8bbbb0c56..17ed9c2a6 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -121,8 +121,9 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) p->branch_blocks.allocator = a; p->context_stack.allocator = a; p->scope_stack.allocator = a; - map_init(&p->selector_values, a, 0); - map_init(&p->selector_addr, a, 0); + map_init(&p->selector_values, a, 0); + map_init(&p->selector_addr, a, 0); + map_init(&p->map_header_cache, a, 0); if (p->is_foreign) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); @@ -380,6 +381,8 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture"); } + map_init(&p->map_header_cache, heap_allocator(), 0); + return p; }