mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 22:58:46 +00:00
Nearly implement dynamics map, missing insertion
This commit is contained in:
+4
-3
@@ -13,9 +13,10 @@
|
|||||||
main :: proc() {
|
main :: proc() {
|
||||||
Value :: type f32;
|
Value :: type f32;
|
||||||
m: map[int]Value;
|
m: map[int]Value;
|
||||||
m[123] = 345.0;
|
reserve(^m, 16);
|
||||||
x, ok := m[123];
|
defer free(m);
|
||||||
if ok {
|
// m[123] = 345.0;
|
||||||
|
if x, ok := m[123]; ok {
|
||||||
fmt.println(x);
|
fmt.println(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+131
-37
@@ -180,6 +180,16 @@ free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
|
|||||||
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
|
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__free_raw_dynamic_array :: proc(a: ^Raw_Dynamic_Array) {
|
||||||
|
if a.allocator.procedure == nil {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if a.data == nil {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free_ptr_with_allocator(a.allocator, a.data);
|
||||||
|
}
|
||||||
|
|
||||||
free_ptr :: proc(ptr: rawptr) #inline {
|
free_ptr :: proc(ptr: rawptr) #inline {
|
||||||
__check_context();
|
__check_context();
|
||||||
free_ptr_with_allocator(context.allocator, ptr);
|
free_ptr_with_allocator(context.allocator, ptr);
|
||||||
@@ -407,35 +417,55 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
|||||||
return array.count;
|
return array.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int) -> int {
|
||||||
|
array := cast(^Raw_Dynamic_Array)array_;
|
||||||
|
|
||||||
|
ok := true;
|
||||||
|
if array.capacity <= array.count+1 {
|
||||||
|
capacity := 2 * array.capacity + max(8, 1);
|
||||||
|
ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity);
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
// TODO(bill): Better error handling for failed reservation
|
||||||
|
return array.count;
|
||||||
|
}
|
||||||
|
data := cast(^byte)array.data;
|
||||||
|
assert(data != nil);
|
||||||
|
mem.zero(data + (elem_size*array.count), elem_size);
|
||||||
|
array.count += 1;
|
||||||
|
return array.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__default_hash :: proc(data: []byte) -> u64 {
|
__default_hash :: proc(data: []byte) -> u64 {
|
||||||
return hash.murmur64(data);
|
return hash.murmur64(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map_Find_Result :: struct {
|
Map_Key :: struct #ordered {
|
||||||
|
hash: u64,
|
||||||
|
str: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
Map_Find_Result :: struct #ordered {
|
||||||
hash_index: int,
|
hash_index: int,
|
||||||
entry_prev: int,
|
entry_prev: int,
|
||||||
entry_index: int,
|
entry_index: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Map_Entry_Header :: struct {
|
Map_Entry_Header :: struct #ordered {
|
||||||
hash: u64,
|
key: Map_Key,
|
||||||
next: int,
|
next: int,
|
||||||
/*
|
/*
|
||||||
key: Key_Type,
|
|
||||||
value: Value_Type,
|
value: Value_Type,
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
Map_Header :: struct {
|
Map_Header :: struct #ordered {
|
||||||
m: ^Raw_Dynamic_Map,
|
m: ^Raw_Dynamic_Map,
|
||||||
is_string: bool,
|
is_key_string: bool,
|
||||||
entry_size: int,
|
entry_size: int,
|
||||||
entry_align: int,
|
entry_align: int,
|
||||||
key_size: int,
|
value_offset: int,
|
||||||
key_align: int,
|
|
||||||
key_offset: int,
|
|
||||||
value_offset: int,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_reserve :: proc(using header: Map_Header, capacity: int) -> bool {
|
__dynamic_map_reserve :: proc(using header: Map_Header, capacity: int) -> bool {
|
||||||
@@ -457,26 +487,25 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < nm.entries.count; i += 1 {
|
for i := 0; i < nm.entries.count; i += 1 {
|
||||||
data := cast(^byte)nm.entries.data + i*entry_size;
|
entry_header := __dynamic_map_get_entry(new_header, i);
|
||||||
entry_header := cast(^Map_Entry_Header)data;
|
data := cast(^byte)entry_header;
|
||||||
|
|
||||||
if nm.hashes.count == 0 {
|
if nm.hashes.count == 0 {
|
||||||
__dynamic_map_grow(new_header);
|
__dynamic_map_grow(new_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
fr := __dynamic_map_find(new_header, entry_header);
|
fr := __dynamic_map_find(new_header, entry_header.key);
|
||||||
j := __dynamic_map_add_entry(new_header, entry_header);
|
j := __dynamic_map_add_entry(new_header, entry_header.key);
|
||||||
if fr.entry_prev < 0 {
|
if fr.entry_prev < 0 {
|
||||||
nm.hashes[fr.hash_index] = j;
|
nm.hashes[fr.hash_index] = j;
|
||||||
} else {
|
} else {
|
||||||
e := cast(^byte)nm.entries.data + fr.entry_prev*entry_size;
|
e := __dynamic_map_get_entry(new_header, fr.entry_prev);
|
||||||
eh := cast(^Map_Entry_Header)e;
|
e.next = j;
|
||||||
eh.next = j;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ndata := cast(^byte)nm.entries.data + j*entry_size;
|
e := __dynamic_map_get_entry(new_header, j);
|
||||||
e := cast(^Map_Entry_Header)ndata;
|
|
||||||
e.next = fr.entry_index;
|
e.next = fr.entry_index;
|
||||||
|
ndata := cast(^byte)e;
|
||||||
mem.copy(ndata+value_offset, data+value_offset, entry_size-value_offset);
|
mem.copy(ndata+value_offset, data+value_offset, entry_size-value_offset);
|
||||||
if __dynamic_map_full(new_header) {
|
if __dynamic_map_full(new_header) {
|
||||||
__dynamic_map_grow(new_header);
|
__dynamic_map_grow(new_header);
|
||||||
@@ -484,36 +513,37 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) {
|
|||||||
}
|
}
|
||||||
free(header.m);
|
free(header.m);
|
||||||
header.m^ = nm;
|
header.m^ = nm;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_get :: proc(h: Map_Header, entry_header: ^Map_Entry_Header) -> rawptr {
|
__dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr {
|
||||||
index := __dynamic_map_find(h, entry_header).entry_index;
|
index := __dynamic_map_find(h, key).entry_index;
|
||||||
if index >= 0 {
|
if index >= 0 {
|
||||||
data := cast(^byte)h.m.entries.data + index*h.entry_size;
|
data := cast(^byte)__dynamic_map_get_entry(h, index);
|
||||||
return data + h.value_offset;
|
return data + h.value_offset;
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_set :: proc(using h: Map_Header, entry_header: ^Map_Entry_Header, value: rawptr) {
|
__dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) {
|
||||||
if m.hashes.count == 0 {
|
if m.hashes.count == 0 {
|
||||||
__dynamic_map_grow(h);
|
__dynamic_map_grow(h);
|
||||||
}
|
}
|
||||||
index: int;
|
index: int;
|
||||||
fr := __dynamic_map_find(h, entry_header);
|
fr := __dynamic_map_find(h, key);
|
||||||
if fr.entry_index >= 0 {
|
if fr.entry_index >= 0 {
|
||||||
index = fr.entry_index;
|
index = fr.entry_index;
|
||||||
} else {
|
} else {
|
||||||
index = __dynamic_map_add_entry(h, entry_header);
|
index = __dynamic_map_add_entry(h, key);
|
||||||
if fr.entry_prev >= 0 {
|
if fr.entry_prev >= 0 {
|
||||||
entry := cast(^Map_Entry_Header)(cast(^byte)m.entries.data + fr.entry_prev*entry_size);
|
entry := __dynamic_map_get_entry(h, fr.entry_prev);
|
||||||
entry.next = index;
|
entry.next = index;
|
||||||
} else {
|
} else {
|
||||||
m.hashes[fr.hash_index] = index;
|
m.hashes[fr.hash_index] = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
data := cast(^byte)m.entries.data + index*entry_size;
|
data := cast(^byte)__dynamic_map_get_entry(h, index);
|
||||||
mem.copy(data+value_offset, value, entry_size-value_offset);
|
mem.copy(data+value_offset, value, entry_size-value_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,18 +553,82 @@ __dynamic_map_set :: proc(using h: Map_Header, entry_header: ^Map_Entry_Header,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__dynamic_map_grow :: proc(using header: Map_Header) {
|
__dynamic_map_grow :: proc(using h: Map_Header) {
|
||||||
|
new_count := 2*m.entries.count + 8;
|
||||||
|
__dynamic_map_rehash(h, new_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_full :: proc(using header: Map_Header) -> bool {
|
__dynamic_map_full :: proc(using h: Map_Header) -> bool {
|
||||||
|
return cast(int)(0.75 * cast(f64)m.hashes.count) <= m.entries.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool {
|
||||||
|
if a.hash == b.hash {
|
||||||
|
if h.is_key_string {
|
||||||
|
return a.str == b.str;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result {
|
||||||
__dynamic_map_find :: proc(using header: Map_Header, entry_header: ^Map_Entry_Header) -> Map_Find_Result {
|
fr := Map_Find_Result{-1, -1, -1};
|
||||||
return Map_Find_Result{-1, -1, -1};
|
if m.hashes.count > 0 {
|
||||||
|
fr.hash_index = cast(int)(key.hash % cast(u64)m.hashes.count);
|
||||||
|
fr.entry_index = m.hashes[fr.hash_index];
|
||||||
|
for fr.entry_index >= 0 {
|
||||||
|
entry := __dynamic_map_get_entry(h, fr.entry_index);
|
||||||
|
if __dynamic_map_hash_equal(h, entry.key, key) {
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
fr.entry_prev = fr.entry_index;
|
||||||
|
fr.entry_index = entry.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_add_entry :: proc(using header: Map_Header, entry_header: ^Map_Entry_Header) -> int {
|
__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key) -> int {
|
||||||
return 0;
|
prev := m.entries.count;
|
||||||
|
c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align);
|
||||||
|
if c != prev {
|
||||||
|
end := __dynamic_map_get_entry(h, c-1);
|
||||||
|
end.key = key;
|
||||||
|
end.next = -1;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__dynamic_map_remove :: proc(using h: Map_Header, key: Map_Key) {
|
||||||
|
fr := __dynamic_map_find(h, key);
|
||||||
|
if fr.entry_index >= 0 {
|
||||||
|
__dynamic_map_erase(h, fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header {
|
||||||
|
data := cast(^byte)m.entries.data + index*entry_size;
|
||||||
|
return cast(^Map_Entry_Header)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) {
|
||||||
|
if fr.entry_prev < 0 {
|
||||||
|
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
|
||||||
|
} else {
|
||||||
|
__dynamic_map_get_entry(h, fr.entry_prev).next = __dynamic_map_get_entry(h, fr.entry_index).next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if fr.entry_index == m.entries.count-1 {
|
||||||
|
m.entries.count -= 1;
|
||||||
|
}
|
||||||
|
mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
|
||||||
|
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
|
||||||
|
if last.entry_prev >= 0 {
|
||||||
|
__dynamic_map_get_entry(h, last.entry_prev).next = fr.entry_index;
|
||||||
|
} else {
|
||||||
|
m.hashes[last.hash_index] = fr.entry_index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-7
@@ -1146,12 +1146,11 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
|
|||||||
dummy_node->kind = AstNode_Invalid;
|
dummy_node->kind = AstNode_Invalid;
|
||||||
check_open_scope(c, dummy_node);
|
check_open_scope(c, dummy_node);
|
||||||
|
|
||||||
isize field_count = 4;
|
isize field_count = 3;
|
||||||
Entity **fields = gb_alloc_array(a, Entity *, field_count);
|
Entity **fields = gb_alloc_array(a, Entity *, field_count);
|
||||||
fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("hash")), t_u64, false, false);
|
fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")), t_u64, false, false);
|
||||||
fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("next")), t_int, false, false);
|
fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("next")), t_int, false, false);
|
||||||
fields[2] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")), key, false, false);
|
fields[2] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value, false, false);
|
||||||
fields[3] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value, false, false);
|
|
||||||
|
|
||||||
check_close_scope(c);
|
check_close_scope(c);
|
||||||
|
|
||||||
@@ -2821,6 +2820,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
// free :: proc(^Type)
|
// free :: proc(^Type)
|
||||||
// free :: proc([]Type)
|
// free :: proc([]Type)
|
||||||
// free :: proc(string)
|
// free :: proc(string)
|
||||||
|
// free :: proc(map[K]T)
|
||||||
Type *type = operand->type;
|
Type *type = operand->type;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (is_type_pointer(type)) {
|
if (is_type_pointer(type)) {
|
||||||
@@ -2831,6 +2831,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
ok = true;
|
ok = true;
|
||||||
} else if (is_type_dynamic_array(type)) {
|
} else if (is_type_dynamic_array(type)) {
|
||||||
ok = true;
|
ok = true;
|
||||||
|
} else if (is_type_dynamic_map(type)) {
|
||||||
|
ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -2847,17 +2849,18 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
|
|
||||||
case BuiltinProc_reserve: {
|
case BuiltinProc_reserve: {
|
||||||
// reserve :: proc(^[dynamic]Type, count: int) {
|
// reserve :: proc(^[dynamic]Type, count: int) {
|
||||||
|
// reserve :: proc(^map[Key]Type, count: int) {
|
||||||
Type *type = operand->type;
|
Type *type = operand->type;
|
||||||
if (!is_type_pointer(type)) {
|
if (!is_type_pointer(type)) {
|
||||||
gbString str = type_to_string(type);
|
gbString str = type_to_string(type);
|
||||||
error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str);
|
error_node(operand->expr, "Expected a pointer, got `%s`", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
type = type_deref(type);
|
type = type_deref(type);
|
||||||
if (!is_type_dynamic_array(type)) {
|
if (!is_type_dynamic_array(type) && !is_type_dynamic_map(type)) {
|
||||||
gbString str = type_to_string(type);
|
gbString str = type_to_string(type);
|
||||||
error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str);
|
error_node(operand->expr, "Expected a pointer to a dynamic array or dynamic map, got `%s`", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1151,6 +1151,17 @@ void init_preload(Checker *c) {
|
|||||||
if (t_raw_dynamic_array == NULL) {
|
if (t_raw_dynamic_array == NULL) {
|
||||||
Entity *e = find_core_entity(c, str_lit("Raw_Dynamic_Array"));
|
Entity *e = find_core_entity(c, str_lit("Raw_Dynamic_Array"));
|
||||||
t_raw_dynamic_array = e->type;
|
t_raw_dynamic_array = e->type;
|
||||||
|
t_raw_dynamic_array = make_type_pointer(c->allocator, t_raw_dynamic_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_map_key == NULL) {
|
||||||
|
Entity *e = find_core_entity(c, str_lit("Map_Key"));
|
||||||
|
t_map_key = e->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_map_header == NULL) {
|
||||||
|
Entity *e = find_core_entity(c, str_lit("Map_Header"));
|
||||||
|
t_map_header = e->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->done_preload = true;
|
c->done_preload = true;
|
||||||
|
|||||||
@@ -357,6 +357,7 @@ gb_global irValue *v_one32 = NULL;
|
|||||||
gb_global irValue *v_two32 = NULL;
|
gb_global irValue *v_two32 = NULL;
|
||||||
gb_global irValue *v_false = NULL;
|
gb_global irValue *v_false = NULL;
|
||||||
gb_global irValue *v_true = NULL;
|
gb_global irValue *v_true = NULL;
|
||||||
|
gb_global irValue *v_raw_nil = NULL;
|
||||||
|
|
||||||
typedef enum irAddrKind {
|
typedef enum irAddrKind {
|
||||||
irAddr_Default,
|
irAddr_Default,
|
||||||
@@ -1397,13 +1398,86 @@ void ir_emit_startup_runtime(irProcedure *proc) {
|
|||||||
ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
|
ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index);
|
||||||
|
irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right);
|
||||||
|
|
||||||
|
irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) {
|
||||||
|
GB_ASSERT(is_type_pointer(ir_type(map_val)));
|
||||||
|
gbAllocator a = proc->module->allocator;
|
||||||
|
irValue *h = ir_add_local_generated(proc, t_map_header);
|
||||||
|
|
||||||
|
Type *key_type = map_type->Map.key;
|
||||||
|
Type *val_type = map_type->Map.value;
|
||||||
|
|
||||||
|
// NOTE(bill): Removes unnecessary allocation if split gep
|
||||||
|
irValue *gep0 = ir_emit_struct_ep(proc, h, 0);
|
||||||
|
irValue *m = ir_emit_conv(proc, map_val, type_deref(ir_type(gep0)));
|
||||||
|
ir_emit_store(proc, gep0, m);
|
||||||
|
|
||||||
|
if (is_type_string(key_type)) {
|
||||||
|
// GB_PANIC("TODO(bill): string map keys");
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 1), v_true);
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 entry_size = type_size_of(proc->module->sizes, a, map_type->Map.entry_type);
|
||||||
|
i64 entry_align = type_align_of(proc->module->sizes, a, map_type->Map.entry_type);
|
||||||
|
i64 value_offset = type_offset_of(proc->module->sizes, a, map_type->Map.entry_type, 2);
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 2), ir_make_const_int(a, entry_size));
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 3), ir_make_const_int(a, entry_align));
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_make_const_int(a, value_offset));
|
||||||
|
|
||||||
|
|
||||||
|
return ir_emit_load(proc, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
irValue *ir_gen_map_key(irProcedure *proc, irValue *key) {
|
||||||
|
irValue *v = ir_add_local_generated(proc, t_map_key);
|
||||||
|
irValue *hash = ir_emit_struct_ep(proc, v, 0);
|
||||||
|
Type *t = base_type(ir_type(key));
|
||||||
|
if (is_type_integer(t)) {
|
||||||
|
ir_emit_store(proc, hash, ir_emit_conv(proc, key, t_u64));
|
||||||
|
} else if (is_type_pointer(t)) {
|
||||||
|
irValue *p = ir_emit_conv(proc, key, t_uint);
|
||||||
|
ir_emit_store(proc, hash, ir_emit_conv(proc, p, t_u64));
|
||||||
|
} else {
|
||||||
|
GB_PANIC("TODO(bill): Map Key type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ir_emit_load(proc, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): Returns NULL if not possible
|
||||||
|
irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val) {
|
||||||
|
if (val->kind == irValue_Instr) {
|
||||||
|
if (val->Instr.kind == irInstr_Load) {
|
||||||
|
return val->Instr.Load.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type *type = ir_type(val);
|
||||||
|
irValue *local = ir_add_local_generated(proc, type);
|
||||||
|
ir_emit_store(proc, local, val);
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
|
irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
|
||||||
if (addr.addr == NULL) {
|
if (addr.addr == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (addr.kind == irAddr_Map) {
|
if (addr.kind == irAddr_Map) {
|
||||||
// IMPORTANT TODO(bill): map insertion
|
Type *map_type = base_type(addr.map_type);
|
||||||
return NULL;
|
irValue *h = ir_gen_map_header(proc, addr.addr, map_type);
|
||||||
|
irValue *key = ir_gen_map_key(proc, addr.map_key);
|
||||||
|
irValue *ptr =ir_address_from_load_or_generate_local(proc, value);
|
||||||
|
ptr = ir_emit_conv(proc, ptr, t_rawptr);
|
||||||
|
|
||||||
|
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
|
||||||
|
args[0] = h;
|
||||||
|
args[1] = key;
|
||||||
|
args[2] = ptr;
|
||||||
|
|
||||||
|
return ir_emit_global_call(proc, "__dynamic_map_set", args, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (addr.kind == irAddr_Vector) {
|
// if (addr.kind == irAddr_Vector) {
|
||||||
@@ -1417,6 +1491,7 @@ irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
|
|||||||
return ir_emit_store(proc, addr.addr, v);
|
return ir_emit_store(proc, addr.addr, v);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
irValue *ir_addr_load(irProcedure *proc, irAddr addr) {
|
irValue *ir_addr_load(irProcedure *proc, irAddr addr) {
|
||||||
if (addr.addr == NULL) {
|
if (addr.addr == NULL) {
|
||||||
GB_PANIC("Illegal addr load");
|
GB_PANIC("Illegal addr load");
|
||||||
@@ -1427,6 +1502,31 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) {
|
|||||||
// TODO(bill): map lookup
|
// TODO(bill): map lookup
|
||||||
Type *map_type = base_type(addr.map_type);
|
Type *map_type = base_type(addr.map_type);
|
||||||
irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type);
|
irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type);
|
||||||
|
irValue *h = ir_gen_map_header(proc, addr.addr, map_type);
|
||||||
|
irValue *key = ir_gen_map_key(proc, addr.map_key);
|
||||||
|
|
||||||
|
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2);
|
||||||
|
args[0] = h;
|
||||||
|
args[1] = key;
|
||||||
|
|
||||||
|
irValue *ptr = ir_emit_global_call(proc, "__dynamic_map_get", args, 2);
|
||||||
|
irValue *ok = ir_emit_comp(proc, Token_NotEq, ptr, v_raw_nil);
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), ok);
|
||||||
|
|
||||||
|
irBlock *then = ir_new_block(proc, NULL, "map.get.then");
|
||||||
|
irBlock *done = ir_new_block(proc, NULL, "map.get.done");
|
||||||
|
ir_emit_if(proc, ok, then, done);
|
||||||
|
ir_start_block(proc, then);
|
||||||
|
{
|
||||||
|
// TODO(bill): mem copy it instead?
|
||||||
|
irValue *gep0 = ir_emit_struct_ep(proc, v, 0);
|
||||||
|
irValue *value = ir_emit_conv(proc, ptr, ir_type(gep0));
|
||||||
|
ir_emit_store(proc, gep0, ir_emit_load(proc, value));
|
||||||
|
}
|
||||||
|
ir_emit_jump(proc, done);
|
||||||
|
ir_start_block(proc, done);
|
||||||
|
|
||||||
|
|
||||||
return ir_emit_load(proc, v);
|
return ir_emit_load(proc, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1449,19 +1549,6 @@ irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset) {
|
|||||||
return ir_emit(proc, ir_make_instr_ptr_offset(proc, ptr, offset));
|
return ir_emit(proc, ir_make_instr_ptr_offset(proc, ptr, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Returns NULL if not possible
|
|
||||||
irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val) {
|
|
||||||
if (val->kind == irValue_Instr) {
|
|
||||||
if (val->Instr.kind == irInstr_Load) {
|
|
||||||
return val->Instr.Load.address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type *type = ir_type(val);
|
|
||||||
irValue *local = ir_add_local_generated(proc, type);
|
|
||||||
ir_emit_store(proc, local, val);
|
|
||||||
return local;
|
|
||||||
}
|
|
||||||
|
|
||||||
irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type) {
|
irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type) {
|
||||||
Type *t_left = ir_type(left);
|
Type *t_left = ir_type(left);
|
||||||
Type *t_right = ir_type(right);
|
Type *t_right = ir_type(right);
|
||||||
@@ -1674,7 +1761,13 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
|
|||||||
case 2: result_type = t_int_ptr; break;
|
case 2: result_type = t_int_ptr; break;
|
||||||
case 3: result_type = t_allocator_ptr; break;
|
case 3: result_type = t_allocator_ptr; break;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (is_type_dynamic_map(t)) {
|
||||||
|
Type *gst = t->Map.generated_struct_type;
|
||||||
|
switch (index) {
|
||||||
|
case 0: result_type = make_type_pointer(a, gst->Record.fields[0]->type); break;
|
||||||
|
case 1: result_type = make_type_pointer(a, gst->Record.fields[1]->type); break;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index);
|
GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1728,6 +1821,12 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
|
|||||||
case 2: result_type = t_int; break;
|
case 2: result_type = t_int; break;
|
||||||
case 3: result_type = t_allocator; break;
|
case 3: result_type = t_allocator; break;
|
||||||
}
|
}
|
||||||
|
} else if (is_type_dynamic_map(t)) {
|
||||||
|
Type *gst = t->Map.generated_struct_type;
|
||||||
|
switch (index) {
|
||||||
|
case 0: result_type = gst->Record.fields[0]->type; break;
|
||||||
|
case 1: result_type = gst->Record.fields[1]->type; break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ir_type(s)), index);
|
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ir_type(s)), index);
|
||||||
}
|
}
|
||||||
@@ -1824,6 +1923,7 @@ irValue *ir_emit_deep_field_ev(irProcedure *proc, Type *type, irValue *e, Select
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
irValue *ir_array_elem(irProcedure *proc, irValue *array) {
|
irValue *ir_array_elem(irProcedure *proc, irValue *array) {
|
||||||
return ir_emit_array_ep(proc, array, v_zero32);
|
return ir_emit_array_ep(proc, array, v_zero32);
|
||||||
}
|
}
|
||||||
@@ -2967,9 +3067,9 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
AstNode *node = ce->args.e[0];
|
AstNode *node = ce->args.e[0];
|
||||||
TypeAndValue tav = *type_and_value_of_expression(proc->module->info, node);
|
TypeAndValue tav = *type_and_value_of_expression(proc->module->info, node);
|
||||||
Type *type = base_type(tav.type);
|
Type *type = base_type(tav.type);
|
||||||
irValue *val = ir_build_expr(proc, node);
|
|
||||||
|
|
||||||
if (is_type_dynamic_array(type)) {
|
if (is_type_dynamic_array(type)) {
|
||||||
|
irValue *val = ir_build_expr(proc, node);
|
||||||
irValue *da_allocator = ir_emit_struct_ev(proc, val, 3);
|
irValue *da_allocator = ir_emit_struct_ev(proc, val, 3);
|
||||||
|
|
||||||
irValue *ptr = ir_emit_struct_ev(proc, val, 0);
|
irValue *ptr = ir_emit_struct_ev(proc, val, 0);
|
||||||
@@ -2979,8 +3079,27 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
args[0] = da_allocator;
|
args[0] = da_allocator;
|
||||||
args[1] = ptr;
|
args[1] = ptr;
|
||||||
return ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
|
return ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
|
||||||
|
} else if (is_type_dynamic_map(type)) {
|
||||||
|
// irValue *val = ir_build_expr(proc, node);
|
||||||
|
// irValue *map_ptr = ir_address_from_load_or_generate_local(proc, val);
|
||||||
|
|
||||||
|
// {
|
||||||
|
// irValue *array = ir_emit_conv(proc, ir_emit_struct_ep(proc, map_ptr, 0), t_raw_dynamic_array_ptr);
|
||||||
|
// irValue **args = gb_alloc_array(a, irValue *, 1);
|
||||||
|
// args[0] = array;
|
||||||
|
// ir_emit_global_call(proc, "__free_raw_dynamic_array", args, 1);
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// irValue *array = ir_emit_conv(proc, ir_emit_struct_ep(proc, map_ptr, 1), t_raw_dynamic_array_ptr);
|
||||||
|
// irValue **args = gb_alloc_array(a, irValue *, 1);
|
||||||
|
// args[0] = array;
|
||||||
|
// ir_emit_global_call(proc, "__free_raw_dynamic_array", args, 1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irValue *val = ir_build_expr(proc, node);
|
||||||
irValue *ptr = NULL;
|
irValue *ptr = NULL;
|
||||||
if (is_type_pointer(type)) {
|
if (is_type_pointer(type)) {
|
||||||
ptr = val;
|
ptr = val;
|
||||||
@@ -3007,26 +3126,35 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
ir_emit_comment(proc, str_lit("reserve"));
|
ir_emit_comment(proc, str_lit("reserve"));
|
||||||
gbAllocator a = proc->module->allocator;
|
gbAllocator a = proc->module->allocator;
|
||||||
|
|
||||||
irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]);
|
irValue *ptr = ir_build_expr(proc, ce->args.e[0]);
|
||||||
Type *type = ir_type(array_ptr);
|
Type *type = ir_type(ptr);
|
||||||
GB_ASSERT(is_type_pointer(type));
|
GB_ASSERT(is_type_pointer(type));
|
||||||
type = base_type(type_deref(type));
|
type = base_type(type_deref(type));
|
||||||
GB_ASSERT(is_type_dynamic_array(type));
|
|
||||||
Type *elem = type->DynamicArray.elem;
|
|
||||||
|
|
||||||
irValue *elem_size = ir_make_const_int(a, type_size_of(proc->module->sizes, a, elem));
|
|
||||||
irValue *elem_align = ir_make_const_int(a, type_align_of(proc->module->sizes, a, elem));
|
|
||||||
|
|
||||||
array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr);
|
|
||||||
|
|
||||||
irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int);
|
irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int);
|
||||||
|
|
||||||
irValue **args = gb_alloc_array(a, irValue *, 4);
|
if (is_type_dynamic_array(type)) {
|
||||||
args[0] = array_ptr;
|
Type *elem = type->DynamicArray.elem;
|
||||||
args[1] = elem_size;
|
|
||||||
args[2] = elem_align;
|
irValue *elem_size = ir_make_const_int(a, type_size_of(proc->module->sizes, a, elem));
|
||||||
args[3] = capacity;
|
irValue *elem_align = ir_make_const_int(a, type_align_of(proc->module->sizes, a, elem));
|
||||||
return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
|
|
||||||
|
ptr = ir_emit_conv(proc, ptr, t_rawptr);
|
||||||
|
|
||||||
|
irValue **args = gb_alloc_array(a, irValue *, 4);
|
||||||
|
args[0] = ptr;
|
||||||
|
args[1] = elem_size;
|
||||||
|
args[2] = elem_align;
|
||||||
|
args[3] = capacity;
|
||||||
|
return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
|
||||||
|
} else if (is_type_dynamic_map(type)) {
|
||||||
|
irValue **args = gb_alloc_array(a, irValue *, 4);
|
||||||
|
args[0] = ir_gen_map_header(proc, ptr, type);
|
||||||
|
args[1] = capacity;
|
||||||
|
return ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
|
||||||
|
} else {
|
||||||
|
GB_PANIC("Unknown type for `reserve`");
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case BuiltinProc_clear: {
|
case BuiltinProc_clear: {
|
||||||
@@ -3491,7 +3619,7 @@ irAddr ir_build_addr_from_entity(irProcedure *proc, Entity *e, AstNode *expr) {
|
|||||||
if (found) {
|
if (found) {
|
||||||
v = *found;
|
v = *found;
|
||||||
} else if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
|
} else if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
|
||||||
// NOTE(bill): never store the using variable
|
// NOTE(bill): Calculate the using variable every time
|
||||||
v = ir_get_using_variable(proc, e);
|
v = ir_get_using_variable(proc, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5554,13 +5682,14 @@ void ir_gen_tree(irGen *s) {
|
|||||||
gbAllocator a = m->allocator;
|
gbAllocator a = m->allocator;
|
||||||
|
|
||||||
if (v_zero == NULL) {
|
if (v_zero == NULL) {
|
||||||
v_zero = ir_make_const_int (m->allocator, 0);
|
v_zero = ir_make_const_int (m->allocator, 0);
|
||||||
v_one = ir_make_const_int (m->allocator, 1);
|
v_one = ir_make_const_int (m->allocator, 1);
|
||||||
v_zero32 = ir_make_const_i32 (m->allocator, 0);
|
v_zero32 = ir_make_const_i32 (m->allocator, 0);
|
||||||
v_one32 = ir_make_const_i32 (m->allocator, 1);
|
v_one32 = ir_make_const_i32 (m->allocator, 1);
|
||||||
v_two32 = ir_make_const_i32 (m->allocator, 2);
|
v_two32 = ir_make_const_i32 (m->allocator, 2);
|
||||||
v_false = ir_make_const_bool(m->allocator, false);
|
v_false = ir_make_const_bool(m->allocator, false);
|
||||||
v_true = ir_make_const_bool(m->allocator, true);
|
v_true = ir_make_const_bool(m->allocator, true);
|
||||||
|
v_raw_nil = ir_make_value_constant(m->allocator, t_rawptr, make_exact_value_pointer(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
isize global_variable_max_count = 0;
|
isize global_variable_max_count = 0;
|
||||||
|
|||||||
+4
-1
@@ -328,7 +328,10 @@ gb_global Type *t_allocator_ptr = NULL;
|
|||||||
gb_global Type *t_context = NULL;
|
gb_global Type *t_context = NULL;
|
||||||
gb_global Type *t_context_ptr = NULL;
|
gb_global Type *t_context_ptr = NULL;
|
||||||
|
|
||||||
gb_global Type *t_raw_dynamic_array = NULL;
|
gb_global Type *t_raw_dynamic_array = NULL;
|
||||||
|
gb_global Type *t_raw_dynamic_array_ptr = NULL;
|
||||||
|
gb_global Type *t_map_key = NULL;
|
||||||
|
gb_global Type *t_map_header = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user