From 046dd5503211c617a88d7de7d089dd5b74e63500 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Nov 2022 13:02:32 +0000 Subject: [PATCH] Change `__dynamic_map_get` signature --- core/runtime/dynamic_map_internal.odin | 173 +++++++++++++------------ src/checker.cpp | 1 + src/llvm_backend.cpp | 19 ++- src/llvm_backend_expr.cpp | 4 +- src/llvm_backend_general.cpp | 4 +- src/llvm_backend_utility.cpp | 23 ++-- src/types.cpp | 3 +- 7 files changed, 113 insertions(+), 114 deletions(-) diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 4218912c9..7e453b4b8 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -217,6 +217,9 @@ map_probe_distance :: #force_inline proc "contextless" (m: Raw_Map, hash: Map_Ha // about the map to make working with it possible. This info structure stores // that. // +// `Map_Info` and `Map_Cell_Info` are read only data structures and cannot be +// modified after creation +// // 32-bytes on 64-bit // 16-bytes on 32-bit Map_Info :: struct { @@ -255,7 +258,7 @@ map_kvh_data_values_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^ // The only procedure which needs access to the context is the one which allocates the map. -map_alloc_dynamic :: proc(info: ^Map_Info, log2_capacity: uintptr, allocator := context.allocator) -> (result: Raw_Map, err: Allocator_Error) { +map_alloc_dynamic :: proc "odin" (info: ^Map_Info, log2_capacity: uintptr, allocator := context.allocator, loc := #caller_location) -> (result: Raw_Map, err: Allocator_Error) { if log2_capacity == 0 { // Empty map, but set the allocator. return { 0, 0, allocator }, nil @@ -268,8 +271,9 @@ map_alloc_dynamic :: proc(info: ^Map_Info, log2_capacity: uintptr, allocator := capacity := uintptr(1) << max(log2_capacity, MAP_MIN_LOG2_CAPACITY) + CACHE_MASK :: MAP_CACHE_LINE_SIZE - 1 round :: #force_inline proc "contextless" (value: uintptr) -> uintptr { - return (value + MAP_CACHE_LINE_SIZE - 1) &~ uintptr(MAP_CACHE_LINE_SIZE - 1) + return (value + CACHE_MASK) &~ CACHE_MASK } INFO_HS := intrinsics.type_map_cell_info(Map_Hash) @@ -281,19 +285,20 @@ map_alloc_dynamic :: proc(info: ^Map_Info, log2_capacity: uintptr, allocator := size = round(map_cell_index_dynamic(size, info.ks, 2)) // Two additional ks for scratch storage size = round(map_cell_index_dynamic(size, info.vs, 2)) // Two additional vs for scratch storage - data := mem_alloc(int(size), MAP_CACHE_LINE_SIZE, allocator) or_return + data := mem_alloc_non_zeroed(int(size), MAP_CACHE_LINE_SIZE, allocator, loc) or_return data_ptr := uintptr(raw_data(data)) - assert(data_ptr & 63 == 0) + if intrinsics.expect(data_ptr & CACHE_MASK != 0, false) { + panic("allocation not aligned to a cache line", loc) + } else { + result = { + // Tagged pointer representation for capacity. + data_ptr | log2_capacity, + 0, + allocator, + } - result = { - // Tagged pointer representation for capacity. - data_ptr | log2_capacity, - 0, - allocator, + map_clear_dynamic(&result, info) } - - map_clear_dynamic(&result, info) - return } @@ -305,10 +310,7 @@ map_alloc_dynamic :: proc(info: ^Map_Info, log2_capacity: uintptr, allocator := // // This procedure returns the address of the just inserted value. @(optimization_mode="speed") -map_insert_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ik: uintptr, iv: uintptr) -> (result: uintptr) { - info_ks := info.ks - info_vs := info.vs - +map_insert_hash_dynamic :: proc "odin" (m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ik: uintptr, iv: uintptr) -> (result: uintptr) { p := map_desired_position(m, h) d := uintptr(0) c := (uintptr(1) << map_log2_cap(m)) - 1 // Saturating arithmetic mask @@ -316,8 +318,8 @@ map_insert_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Ha ks, vs, hs, sk, sv := map_kvh_data_dynamic(m, info) // Avoid redundant loads of these values - size_of_k := info_ks.size_of_type - size_of_v := info_vs.size_of_type + size_of_k := info.ks.size_of_type + size_of_v := info.vs.size_of_type // Use sk and sv scratch storage space for dynamic k and v storage here. // @@ -325,23 +327,23 @@ map_insert_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Ha // k = ik // v = iv // h = h - k := map_cell_index_dynamic_const(sk, info_ks, 0) - v := map_cell_index_dynamic_const(sv, info_vs, 0) + k := map_cell_index_dynamic_const(sk, info.ks, 0) + v := map_cell_index_dynamic_const(sv, info.vs, 0) intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(ik), size_of_k) intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(iv), size_of_v) h := h // Temporary k and v dynamic storage for swap below - tk := map_cell_index_dynamic_const(sk, info_ks, 1) - tv := map_cell_index_dynamic_const(sv, info_vs, 1) + tk := map_cell_index_dynamic_const(sk, info.ks, 1) + tv := map_cell_index_dynamic_const(sv, info.vs, 1) for { hp := &hs[p] element_hash := hp^ if map_hash_is_empty(element_hash) { - k_dst := map_cell_index_dynamic(ks, info_ks, p) - v_dst := map_cell_index_dynamic(vs, info_vs, p) + k_dst := map_cell_index_dynamic(ks, info.ks, p) + v_dst := map_cell_index_dynamic(vs, info.vs, p) intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) hp^ = h @@ -350,8 +352,8 @@ map_insert_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Ha if pd := map_probe_distance(m, element_hash, p); pd < d { if map_hash_is_deleted(element_hash) { - k_dst := map_cell_index_dynamic(ks, info_ks, p) - v_dst := map_cell_index_dynamic(vs, info_vs, p) + k_dst := map_cell_index_dynamic(ks, info.ks, p) + v_dst := map_cell_index_dynamic(vs, info.vs, p) intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) hp^ = h @@ -359,11 +361,11 @@ map_insert_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Ha } if result == 0 { - result = map_cell_index_dynamic(vs, info_vs, p) + result = map_cell_index_dynamic(vs, info.vs, p) } - kp := map_cell_index_dynamic(ks, info_vs, p) - vp := map_cell_index_dynamic(vs, info_ks, p) + kp := map_cell_index_dynamic(ks, info.vs, p) + vp := map_cell_index_dynamic(vs, info.ks, p) // Simulate the following at runtime with dynamic storage // @@ -387,10 +389,7 @@ map_insert_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Ha } @(optimization_mode="speed") -map_add_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ik: uintptr, iv: uintptr) { - info_ks := info.ks - info_vs := info.vs - +map_add_hash_dynamic :: proc "odin" (m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ik: uintptr, iv: uintptr) { capacity := uintptr(1) << map_log2_cap(m) p := map_desired_position(m, h) d := uintptr(0) @@ -399,8 +398,8 @@ map_add_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ks, vs, hs, sk, sv := map_kvh_data_dynamic(m, info) // Avoid redundant loads of these values - size_of_k := info_ks.size_of_type - size_of_v := info_vs.size_of_type + size_of_k := info.ks.size_of_type + size_of_v := info.vs.size_of_type // Use sk and sv scratch storage space for dynamic k and v storage here. // @@ -408,23 +407,23 @@ map_add_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, // k = ik // v = iv // h = h - k := map_cell_index_dynamic_const(sk, info_ks, 0) - v := map_cell_index_dynamic_const(sv, info_vs, 0) + k := map_cell_index_dynamic_const(sk, info.ks, 0) + v := map_cell_index_dynamic_const(sv, info.vs, 0) intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(ik), size_of_k) intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(iv), size_of_v) h := h // Temporary k and v dynamic storage for swap below - tk := map_cell_index_dynamic_const(sk, info_ks, 1) - tv := map_cell_index_dynamic_const(sv, info_vs, 1) + tk := map_cell_index_dynamic_const(sk, info.ks, 1) + tv := map_cell_index_dynamic_const(sv, info.vs, 1) for { hp := &hs[p] element_hash := hp^ if map_hash_is_empty(element_hash) { - k_dst := map_cell_index_dynamic(ks, info_ks, p) - v_dst := map_cell_index_dynamic(vs, info_vs, p) + k_dst := map_cell_index_dynamic(ks, info.ks, p) + v_dst := map_cell_index_dynamic(vs, info.vs, p) intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) hp^ = h @@ -433,16 +432,16 @@ map_add_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, if pd := map_probe_distance(m, element_hash, p); pd < d { if map_hash_is_deleted(element_hash) { - k_dst := map_cell_index_dynamic(ks, info_ks, p) - v_dst := map_cell_index_dynamic(vs, info_vs, p) + k_dst := map_cell_index_dynamic(ks, info.ks, p) + v_dst := map_cell_index_dynamic(vs, info.vs, p) intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) hp^ = h return } - kp := map_cell_index_dynamic(ks, info_vs, p) - vp := map_cell_index_dynamic(vs, info_ks, p) + kp := map_cell_index_dynamic(ks, info.vs, p) + vp := map_cell_index_dynamic(vs, info.ks, p) // Simulate the following at runtime with dynamic storage // @@ -466,7 +465,7 @@ map_add_hash_dynamic :: proc(m: Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, } @(optimization_mode="size") -map_grow_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info) -> Allocator_Error { +map_grow_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error { allocator := m.allocator if allocator.procedure == nil { allocator = context.allocator @@ -475,23 +474,20 @@ map_grow_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info) -> Al log2_capacity := map_log2_cap(m^) if m.data == 0 { - n := map_alloc_dynamic(info, MAP_MIN_LOG2_CAPACITY, allocator) or_return + n := map_alloc_dynamic(info, MAP_MIN_LOG2_CAPACITY, allocator, loc) or_return m.data = n.data return nil } - resized := map_alloc_dynamic(info, log2_capacity + 1, allocator) or_return + resized := map_alloc_dynamic(info, log2_capacity + 1, allocator, loc) or_return old_capacity := uintptr(1) << log2_capacity ks, vs, hs, _, _ := map_kvh_data_dynamic(m^, info) // Cache these loads to avoid hitting them in the for loop. - info_ks := info.ks - info_vs := info.vs - n := map_len(m^) - for i := uintptr(0); i < old_capacity; i += 1 { + for i in 0.. Al if map_hash_is_deleted(hash) { continue } - k := map_cell_index_dynamic(ks, info_ks, i) - v := map_cell_index_dynamic(vs, info_vs, i) + k := map_cell_index_dynamic(ks, info.ks, i) + v := map_cell_index_dynamic(vs, info.vs, i) map_insert_hash_dynamic(resized, info, hash, k, v) // Only need to do this comparison on each actually added pair, so do not // fold it into the for loop comparator as a micro-optimization. @@ -510,7 +506,7 @@ map_grow_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info) -> Al } } - mem_free(rawptr(ks), allocator) + mem_free(rawptr(ks), allocator, loc) m.data = resized.data // Should copy the capacity too @@ -519,7 +515,7 @@ map_grow_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info) -> Al @(optimization_mode="size") -map_reserve_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uintptr) -> Allocator_Error { +map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uintptr) -> Allocator_Error { allocator := m.allocator if allocator.procedure == nil { allocator = context.allocator @@ -544,15 +540,11 @@ map_reserve_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, ne resized := map_alloc_dynamic(info, log2_new_capacity, allocator) or_return - ks, vs, hs, _, _ := map_kvh_data_dynamic(m^, info) // Cache these loads to avoid hitting them in the for loop. - info_ks := info.ks - info_vs := info.vs - n := map_len(m^) - for i := uintptr(0); i < capacity; i += 1 { + for i in 0.. Allocator_Error { +map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info) -> Allocator_Error { allocator := m.allocator if allocator.procedure == nil { // TODO(bill): is this correct behaviour? @@ -601,11 +593,8 @@ map_shrink_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info) -> ks, vs, hs, _, _ := map_kvh_data_dynamic(m^, info) - info_ks := info.ks - info_vs := info.vs - n := map_len(m^) - for i := uintptr(0); i < capacity; i += 1 { + for i in 0.. continue } - k := map_cell_index_dynamic(ks, info_ks, i) - v := map_cell_index_dynamic(vs, info_vs, i) + k := map_cell_index_dynamic(ks, info.ks, i) + v := map_cell_index_dynamic(vs, info.vs, i) map_insert_hash_dynamic(shrinked, info, hash, k, v) @@ -636,7 +625,7 @@ map_shrink_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info) -> // Single procedure for static and dynamic paths. @(require_results) -map_free :: proc(m: Raw_Map, loc := #caller_location) -> Allocator_Error { +map_free :: proc "odin" (m: Raw_Map, loc := #caller_location) -> Allocator_Error { return mem_free(rawptr(map_data(m)), m.allocator, loc) } @@ -650,14 +639,13 @@ map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, d := uintptr(0) c := (uintptr(1) << map_log2_cap(m)) - 1 ks, _, hs, _, _ := map_kvh_data_dynamic(m, info) - info_ks := info.ks for { element_hash := hs[p] if map_hash_is_empty(element_hash) { return 0, false } else if d > map_probe_distance(m, element_hash, p) { return 0, false - } else if element_hash == h && info.key_equal(rawptr(k), rawptr(map_cell_index_dynamic(ks, info_ks, p))) { + } else if element_hash == h && info.key_equal(rawptr(k), rawptr(map_cell_index_dynamic(ks, info.ks, p))) { return p, true } p = (p + 1) & c @@ -674,14 +662,13 @@ map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, d := uintptr(0) c := (uintptr(1) << map_log2_cap(m)) - 1 ks, _, hs, _, _ := map_kvh_data_dynamic(m, info) - info_ks := info.ks for { element_hash := hs[p] if map_hash_is_empty(element_hash) { return false } else if d > map_probe_distance(m, element_hash, p) { return false - } else if element_hash == h && info.key_equal(rawptr(k), rawptr(map_cell_index_dynamic(ks, info_ks, p))) { + } else if element_hash == h && info.key_equal(rawptr(k), rawptr(map_cell_index_dynamic(ks, info.ks, p))) { return true } p = (p + 1) & c @@ -693,9 +680,9 @@ map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, @(optimization_mode="speed") -map_insert_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, k, v: uintptr) -> (value: uintptr, err: Allocator_Error) { +map_insert_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, k, v: uintptr, loc := #caller_location) -> (value: uintptr, err: Allocator_Error) { if map_len(m^) + 1 >= map_resize_threshold(m^) { - map_grow_dynamic(m, info) or_return + map_grow_dynamic(m, info, loc) or_return } hashed := info.key_hasher(rawptr(k), 0) value = map_insert_hash_dynamic(m^, info, hashed, k, v) @@ -705,9 +692,9 @@ map_insert_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, k, // Same as map_insert_dynamic but does not return address to the inserted element. @(optimization_mode="speed") -map_add_dynamic :: proc(#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, k, v: uintptr) -> Allocator_Error { +map_add_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, k, v: uintptr, loc := #caller_location) -> Allocator_Error { if map_len(m^) + 1 >= map_resize_threshold(m^) { - map_grow_dynamic(m, info) or_return + map_grow_dynamic(m, info, loc) or_return } map_add_hash_dynamic(m^, info, info.key_hasher(rawptr(k), 0), k, v) m.len += 1 @@ -734,13 +721,28 @@ map_clear_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n } -__dynamic_map_get :: proc "contextless" (m: rawptr, #no_alias info: ^Map_Info, key: rawptr) -> (ptr: rawptr) { - rm := (^Raw_Map)(m)^ - if index, ok := map_lookup_dynamic(rm, info, uintptr(key)); ok { - vs := map_kvh_data_values_dynamic(rm, info) - ptr = rawptr(map_cell_index_dynamic(vs, info.vs, index)) +__dynamic_map_get :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, key: rawptr) -> (ptr: rawptr) { + if m.len == 0 { + return nil + } + + h := info.key_hasher(key, 0) + p := map_desired_position(m, h) + d := uintptr(0) + c := (uintptr(1) << map_log2_cap(m)) - 1 + ks, vs, hs, _, _ := map_kvh_data_dynamic(m, info) + for { + element_hash := hs[p] + if map_hash_is_empty(element_hash) { + return nil + } else if d > map_probe_distance(m, element_hash, p) { + return nil + } else if element_hash == h && info.key_equal(key, rawptr(map_cell_index_dynamic(ks, info.ks, p))) { + return rawptr(map_cell_index_dynamic(vs, info.vs, p)) + } + p = (p + 1) & c + d += 1 } - return } __dynamic_map_set :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key, value: rawptr, loc := #caller_location) -> rawptr { @@ -748,6 +750,7 @@ __dynamic_map_set :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_In return rawptr(value) if err == nil else nil } +@(private) __dynamic_map_reserve :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uint, loc := #caller_location) { map_reserve_dynamic(m, info, uintptr(new_capacity)) } diff --git a/src/checker.cpp b/src/checker.cpp index 5b9e83bda..75a6da6fa 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2854,6 +2854,7 @@ void init_core_map_type(Checker *c) { t_map_info_ptr = alloc_type_pointer(t_map_info); t_map_cell_info_ptr = alloc_type_pointer(t_map_cell_info); + t_raw_map_ptr = alloc_type_pointer(t_raw_map); } void init_preload(Checker *c) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index bce1fa1d1..629daf1c9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -622,14 +622,15 @@ lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue return hashed_key; } -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 lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map, lbValue const &key) { + Type *map_type = base_type(map.type); + GB_ASSERT(map_type->kind == Type_Map); lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); auto args = array_make(permanent_allocator(), 3); - args[0] = lb_emit_conv(p, map_ptr, t_rawptr); + args[0] = lb_emit_transmute(p, map, t_raw_map); args[1] = lb_gen_map_info_ptr(p->module, map_type); args[2] = key_ptr; @@ -644,17 +645,15 @@ void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbValue const &map_ptr, GB_ASSERT(map_type->kind == Type_Map); lbValue key_ptr = lb_address_from_load_or_generate_local(p, map_key); - key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); - 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); + lbValue v = lb_emit_conv(p, map_value, map_type->Map.value); + lbValue value_ptr = lb_address_from_load_or_generate_local(p, v); auto args = array_make(permanent_allocator(), 5); - args[0] = lb_emit_conv(p, map_ptr, t_rawptr); + args[0] = lb_emit_conv(p, map_ptr, t_raw_map_ptr); args[1] = lb_gen_map_info_ptr(p->module, map_type); - args[2] = key_ptr; - args[3] = lb_emit_conv(p, value_addr.addr, t_rawptr); + args[2] = lb_emit_conv(p, key_ptr, t_rawptr); + args[3] = lb_emit_conv(p, value_ptr, t_rawptr); args[4] = lb_emit_source_code_location_as_global(p, node); lb_emit_runtime_call(p, "__dynamic_map_set", args); } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 05a9fdfbf..7e9aa3a78 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1423,9 +1423,9 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { switch (rt->kind) { case Type_Map: { - lbValue map_ptr = lb_address_from_load_or_generate_local(p, right); + lbValue map = right; lbValue key = left; - lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, key); + lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map, 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 b7654614e..e1a926255 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -417,7 +417,7 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { switch (addr.kind) { case lbAddr_Map: - return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); + return lb_internal_dynamic_map_get_ptr(p, lb_emit_load(p, addr.addr), addr.map.key); case lbAddr_RelativePointer: { Type *rel_ptr = base_type(lb_addr_type(addr)); @@ -1074,7 +1074,7 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { GB_ASSERT(map_type->kind == Type_Map); lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true); - lbValue ptr = lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); + lbValue ptr = lb_internal_dynamic_map_get_ptr(p, lb_emit_load(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_utility.cpp b/src/llvm_backend_utility.cpp index f4d17c7a2..a3493f864 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -203,26 +203,19 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { if (is_type_uintptr(src) && is_type_internally_pointer_like(dst)) { res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); return res; - } - if (is_type_internally_pointer_like(src) && is_type_uintptr(dst)) { + } else if (is_type_internally_pointer_like(src) && is_type_uintptr(dst)) { res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); return res; - } - - if (is_type_integer(src) && is_type_internally_pointer_like(dst)) { + } else if (is_type_integer(src) && is_type_internally_pointer_like(dst)) { res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); return res; } else if (is_type_internally_pointer_like(src) && is_type_integer(dst)) { res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); return res; - } - - if (is_type_internally_pointer_like(src) && is_type_internally_pointer_like(dst)) { + } else if (is_type_internally_pointer_like(src) && is_type_internally_pointer_like(dst)) { res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(p->module, t), ""); return res; - } - - if (is_type_simd_vector(src) && is_type_simd_vector(dst)) { + } else if (is_type_simd_vector(src) && is_type_simd_vector(dst)) { res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), ""); return res; } else if (is_type_array_like(src) && is_type_simd_vector(dst)) { @@ -239,9 +232,11 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { ap = lb_emit_conv(p, ap, alloc_type_pointer(value.type)); lb_emit_store(p, ap, value); return lb_addr_load(p, addr); - } - - if (lb_is_type_aggregate(src) || lb_is_type_aggregate(dst)) { + } else if (is_type_map(src) && are_types_identical(t_raw_map, t)) { + res.value = value.value; + res.type = t; + return res; + } else if (lb_is_type_aggregate(src) || lb_is_type_aggregate(dst)) { lbValue s = lb_address_from_load_or_generate_local(p, value); lbValue d = lb_emit_transmute(p, s, alloc_type_pointer(t)); return lb_emit_load(p, d); diff --git a/src/types.cpp b/src/types.cpp index ca15531dd..ab82e87b8 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -685,9 +685,10 @@ gb_global Type *t_source_code_location_ptr = nullptr; gb_global Type *t_map_info = nullptr; gb_global Type *t_map_cell_info = nullptr; +gb_global Type *t_raw_map = nullptr; gb_global Type *t_map_info_ptr = nullptr; gb_global Type *t_map_cell_info_ptr = nullptr; -gb_global Type *t_raw_map = nullptr; +gb_global Type *t_raw_map_ptr = nullptr; gb_global Type *t_equal_proc = nullptr;