From c126339090a57ab29a2c75d3ee79333cf3c88278 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 6 Feb 2017 20:23:51 +0000 Subject: [PATCH 1/7] dynamic `map` insertion and lookup --- code/demo.odin | 7 +++--- core/_preload.odin | 15 +++++++----- src/check_expr.c | 8 +------ src/check_stmt.c | 10 +++++--- src/ir.c | 60 ++++++++++++++++++++++++++-------------------- 5 files changed, 55 insertions(+), 45 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index e3e85769c..d44f7dca3 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -11,11 +11,12 @@ main :: proc() { - Value :: type f32; - m: map[int]Value; + m: map[int]u32; reserve(^m, 16); defer free(m); - // m[123] = 345.0; + + m[123] = 345; + fmt.println(m[123]); if x, ok := m[123]; ok { fmt.println(x); } diff --git a/core/_preload.odin b/core/_preload.odin index 18a7a4438..1fb821fea 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -511,25 +511,27 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) { __dynamic_map_grow(new_header); } } - free(header.m); + free_ptr_with_allocator(header.m.hashes.allocator, header.m.hashes.data); + free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data); header.m^ = nm; - } __dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { index := __dynamic_map_find(h, key).entry_index; if index >= 0 { data := cast(^byte)__dynamic_map_get_entry(h, index); - return data + h.value_offset; + val := data + h.value_offset; + return val; } return nil; } __dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) { + index: int; + if m.hashes.count == 0 { __dynamic_map_grow(h); } - index: int; fr := __dynamic_map_find(h, key); if fr.entry_index >= 0 { index = fr.entry_index; @@ -544,7 +546,8 @@ __dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) { } { data := cast(^byte)__dynamic_map_get_entry(h, index); - mem.copy(data+value_offset, value, entry_size-value_offset); + val := data+value_offset; + mem.copy(val, value, entry_size-value_offset); } if __dynamic_map_full(h) { @@ -598,7 +601,7 @@ __dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key) -> int { end.key = key; end.next = -1; } - return c; + return prev; } diff --git a/src/check_expr.c b/src/check_expr.c index 55563cb2d..20b041e08 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -3829,12 +3829,6 @@ void check_unpack_arguments(Checker *c, ArrayOperand *operands, AstNodeArray arg Operand o = {0}; check_multi_expr(c, &o, args.e[i]); - if (o.mode == Addressing_MapIndex) { - Type *tuple_type = make_map_tuple_type(c->allocator, o.type); - add_type_and_value(&c->info, o.expr, o.mode, tuple_type, (ExactValue){0}); - o.type = tuple_type; - } - if (o.type == NULL || o.type->kind != Type_Tuple) { array_add(operands, o); } else { @@ -4997,7 +4991,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint goto error; } o->mode = Addressing_MapIndex; - o->type = t->Map.value; + o->type = make_map_tuple_type(c->allocator, t->Map.value); o->expr = node; return Expr_Expr; } diff --git a/src/check_stmt.c b/src/check_stmt.c index 9b26adc5d..489b97fb4 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -256,13 +256,17 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { e->flags |= EntityFlag_Used; } + Type *assignment_type = op_b.type; switch (op_b.mode) { case Addressing_Invalid: return NULL; case Addressing_Variable: break; - case Addressing_MapIndex: - break; + case Addressing_MapIndex: { + Type *t = base_type(assignment_type); GB_ASSERT(is_type_tuple(t)); + t = t->Tuple.variables[0]->type; + assignment_type = t; + } break; default: { if (op_b.expr->kind == AstNode_SelectorExpr) { // NOTE(bill): Extra error checks @@ -287,7 +291,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { } break; } - check_assignment(c, op_a, op_b.type, str_lit("assignment")); + check_assignment(c, op_a, assignment_type, str_lit("assignment")); if (op_a->mode == Addressing_Invalid) { return NULL; } diff --git a/src/ir.c b/src/ir.c index 8c3767d91..d5f52a27a 100644 --- a/src/ir.c +++ b/src/ir.c @@ -372,6 +372,7 @@ typedef struct irAddr { struct { irValue *map_key; Type * map_type; + Type * map_result; }; }; // union { @@ -384,10 +385,11 @@ irAddr ir_make_addr(irValue *addr) { return v; } -irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type) { +irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *map_result) { irAddr v = {irAddr_Map, addr}; - v.map_key = map_key; - v.map_type = map_type; + v.map_key = map_key; + v.map_type = map_type; + v.map_result = map_result; return v; } @@ -589,23 +591,6 @@ Type *ir_type(irValue *value) { return NULL; } -Type *ir_addr_type(irAddr addr) { - if (addr.addr == NULL) { - return NULL; - } - - if (addr.kind == irAddr_Map) { - Type *t = base_type(addr.map_type); - GB_ASSERT(is_type_map(t)); - return t->Map.value; - } - - Type *t = ir_type(addr.addr); - GB_ASSERT(is_type_pointer(t)); - return type_deref(t); -} - - bool ir_is_blank_ident(AstNode *node) { if (node->kind == AstNode_Ident) { @@ -1461,6 +1446,23 @@ irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val) } +Type *ir_addr_type(irAddr addr) { + if (addr.addr == NULL) { + return NULL; + } + + if (addr.kind == irAddr_Map) { + Type *t = base_type(addr.map_type); + GB_ASSERT(is_type_map(t)); + return t->Map.value; + } + + Type *t = ir_type(addr.addr); + GB_ASSERT(is_type_pointer(t)); + return type_deref(t); +} + + irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { if (addr.addr == NULL) { return NULL; @@ -1469,7 +1471,8 @@ irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { Type *map_type = base_type(addr.map_type); 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); + irValue *v = ir_emit_conv(proc, value, map_type->Map.value); + irValue *ptr = ir_address_from_load_or_generate_local(proc, v); ptr = ir_emit_conv(proc, ptr, t_rawptr); irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); @@ -1487,7 +1490,7 @@ irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { // irValue *out = ir_emit(proc, ir_make_instr_insert_element(proc, v, elem, addr.Vector.index)); // return ir_emit_store(proc, addr.addr, out); // } else { - irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); + irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); return ir_emit_store(proc, addr.addr, v); // } } @@ -1527,7 +1530,12 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) { ir_start_block(proc, done); - return ir_emit_load(proc, v); + if (is_type_tuple(addr.map_result)) { + return ir_emit_load(proc, v); + } else { + irValue *single = ir_emit_struct_ep(proc, v, 0); + return ir_emit_load(proc, single); + } } // if (addr.kind == irAddr_Vector) { @@ -3778,7 +3786,8 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { irValue *key = ir_build_expr(proc, ie->index); key = ir_emit_conv(proc, key, t->Map.key); - return ir_make_addr_map(map_val, key, t); + Type *result_type = type_of_expr(proc->module->info, expr); + return ir_make_addr_map(map_val, key, t, result_type); } irValue *using_addr = NULL; @@ -4598,8 +4607,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { if (lvals.e[i].addr == NULL) { continue; } - irValue *v = ir_emit_conv(proc, inits.e[i], ir_addr_type(lvals.e[i])); - ir_addr_store(proc, lvals.e[i], v); + ir_addr_store(proc, lvals.e[i], inits.e[i]); } } From f11d73ffaa5df21437714e73bb72352ed17d57a9 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 6 Feb 2017 20:54:51 +0000 Subject: [PATCH 2/7] `map` string keys and `for` iterator --- code/demo.odin | 14 ++++++---- core/_preload.odin | 5 +++- src/check_expr.c | 8 +++--- src/check_stmt.c | 5 ++++ src/ir.c | 64 +++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 82 insertions(+), 14 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index d44f7dca3..c4e44aebd 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -11,14 +11,18 @@ main :: proc() { - m: map[int]u32; + m: map[string]u32; reserve(^m, 16); defer free(m); - m[123] = 345; - fmt.println(m[123]); - if x, ok := m[123]; ok { - fmt.println(x); + m["a"] = 56; + m["b"] = 13453; + m["c"] = 7654; + c, ok := m["c"]; + assert(ok && c == 7654); + + for val, key in m { + fmt.printf("m[\"%s\"] == %v\n", key, val); } diff --git a/core/_preload.odin b/core/_preload.odin index 1fb821fea..ec473348e 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -438,7 +438,10 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in __default_hash :: proc(data: []byte) -> u64 { - return hash.murmur64(data); + return hash.fnv64a(data); +} +__default_hash_string :: proc(s: string) -> u64 { + return __default_hash(cast([]byte)s); } Map_Key :: struct #ordered { diff --git a/src/check_expr.c b/src/check_expr.c index 20b041e08..112fae2af 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1136,7 +1136,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { /* struct { - hash: u64, + hash: Map_Key, next: int, key: Key_Type, value: Value_Type, @@ -1148,9 +1148,9 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { isize field_count = 3; Entity **fields = gb_alloc_array(a, Entity *, field_count); - 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[2] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value, false, false); + fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")), t_map_key, 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("value")), value, false, false); check_close_scope(c); diff --git a/src/check_stmt.c b/src/check_stmt.c index 489b97fb4..83d3939e8 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -723,6 +723,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { val = t->Vector.elem; idx = t_int; break; + + case Type_Map: + val = t->Map.value; + idx = t->Map.key; + break; } } diff --git a/src/ir.c b/src/ir.c index d5f52a27a..7d04a0dd4 100644 --- a/src/ir.c +++ b/src/ir.c @@ -975,6 +975,9 @@ irValue *ir_make_const_i32(gbAllocator a, i64 i) { irValue *ir_make_const_i64(gbAllocator a, i64 i) { return ir_make_value_constant(a, t_i64, make_exact_value_integer(i)); } +irValue *ir_make_const_u64(gbAllocator a, u64 i) { + return ir_make_value_constant(a, t_u64, make_exact_value_integer(i)); +} irValue *ir_make_const_f32(gbAllocator a, f32 f) { return ir_make_value_constant(a, t_f32, make_exact_value_float(f)); } @@ -1418,15 +1421,28 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) 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)); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), 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)); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, t_u64)); } else { - GB_PANIC("TODO(bill): Map Key type"); + irValue *str = ir_emit_conv(proc, key, t_string); + irValue *hashed_str = NULL; + + if (str->kind == irValue_Constant) { + ExactValue ev = str->Constant.value; + GB_ASSERT(ev.kind == ExactValue_String); + u64 hs = gb_fnv64a(ev.value_string.text, ev.value_string.len); + hashed_str = ir_make_const_u64(proc->module->allocator, hs); + } else { + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1); + args[0] = str; + hashed_str = ir_emit_global_call(proc, "__default_hash_string", args, 1); + } + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), str); } return ir_emit_load(proc, v); @@ -4355,6 +4371,7 @@ void ir_emit_increment(irProcedure *proc, irValue *addr) { } + void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, irValue *count_ptr, irValue **val_, irValue **idx_, irBlock **loop_, irBlock **done_) { irValue *count = NULL; @@ -4374,6 +4391,11 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir irBlock *done = NULL; irBlock *body = NULL; + irValue *key = NULL; + if (expr_type->kind == Type_Map) { + key = ir_add_local_generated(proc, expr_type->Map.key); + } + irValue *index = ir_add_local_generated(proc, t_int); ir_emit_store(proc, index, ir_make_const_int(proc->module->allocator, -1)); @@ -4410,6 +4432,26 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir irValue *elem = ir_emit_struct_ep(proc, expr, 0); elem = ir_emit_load(proc, elem); val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx)); + } break; + case Type_Map: { + irValue *entries = ir_emit_struct_ep(proc, expr, 1); + irValue *elem = ir_emit_struct_ep(proc, entries, 0); + elem = ir_emit_load(proc, elem); + + irValue *entry = ir_emit_ptr_offset(proc, elem, idx); + val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2)); + + irValue *hash = ir_emit_struct_ep(proc, entry, 0); + if (is_type_string(expr_type->Map.key)) { + irValue *str = ir_emit_struct_ep(proc, hash, 1); + ir_emit_store(proc, key, ir_emit_load(proc, str)); + } else { + irValue *hash_ptr = ir_emit_struct_ep(proc, hash, 0); + hash_ptr = ir_emit_conv(proc, hash_ptr, ir_type(key)); + ir_emit_store(proc, key, ir_emit_load(proc, hash_ptr)); + } + + } break; default: GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); @@ -4417,6 +4459,10 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir } } + if (key != NULL) { + idx = ir_emit_load(proc, key); + } + if (val_) *val_ = val; if (idx_) *idx_ = idx; if (loop_) *loop_ = loop; @@ -4965,6 +5011,16 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { Type *expr_type = type_of_expr(proc->module->info, rs->expr); Type *et = base_type(type_deref(expr_type)); switch (et->kind) { + case Type_Map: { + irAddr addr = ir_build_addr(proc, rs->expr); + irValue *map = addr.addr; + if (is_type_pointer(type_deref(ir_addr_type(addr)))) { + map = ir_addr_load(proc, addr); + } + irValue *entries_ptr = ir_emit_struct_ep(proc, map, 1); + irValue *count_ptr = ir_emit_struct_ep(proc, entries_ptr, 1); + ir_build_range_indexed(proc, map, val_type, count_ptr, &val, &index, &loop, &done); + } break; case Type_Array: { irValue *count_ptr = NULL; irValue *array = ir_build_addr(proc, rs->expr).addr; From df78b8ad3ebd263849eee6736fd78efe017522a4 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 6 Feb 2017 21:31:27 +0000 Subject: [PATCH 3/7] Make checking map key exists optional --- code/demo.odin | 4 ++-- src/check_decl.c | 2 +- src/check_expr.c | 24 ++++++++++++++++++++---- src/check_stmt.c | 7 ++----- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index c4e44aebd..90ac11858 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -18,14 +18,14 @@ main :: proc() { m["a"] = 56; m["b"] = 13453; m["c"] = 7654; - c, ok := m["c"]; + c := m["c"]; + _, ok := m["c"]; assert(ok && c == 7654); for val, key in m { fmt.printf("m[\"%s\"] == %v\n", key, val); } - // fm: map[128, int]f32; /* diff --git a/src/check_decl.c b/src/check_decl.c index 1cbfcacc6..b690799af 100644 --- a/src/check_decl.c +++ b/src/check_decl.c @@ -63,7 +63,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra // an extra allocation ArrayOperand operands = {0}; array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count); - check_unpack_arguments(c, &operands, inits); + check_unpack_arguments(c, lhs_count, &operands, inits, true); isize rhs_count = operands.count; for_array(i, operands) { diff --git a/src/check_expr.c b/src/check_expr.c index 112fae2af..b271a62f9 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -2676,7 +2676,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h gbString op_str = expr_to_string(op_expr); gbString type_str = type_to_string(operand->type); gbString sel_str = expr_to_string(selector); - error_node(op_expr, "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str); + error_node(op_expr, "`%s` of type `%s` has no field `%s`", op_str, type_str, sel_str); gb_string_free(sel_str); gb_string_free(type_str); gb_string_free(op_str); @@ -3824,12 +3824,28 @@ int valid_proc_and_score_cmp(void const *a, void const *b) { typedef Array(Operand) ArrayOperand; -void check_unpack_arguments(Checker *c, ArrayOperand *operands, AstNodeArray args) { +void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) { for_array(i, args) { Operand o = {0}; check_multi_expr(c, &o, args.e[i]); if (o.type == NULL || o.type->kind != Type_Tuple) { + if (o.mode == Addressing_MapIndex && + allow_map_ok && + lhs_count == 2 && + args.count == 1) { + Type *tuple = make_map_tuple_type(c->allocator, o.type); + add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value); + + Operand val = o; + Operand ok = o; + val.mode = Addressing_Value; + ok.mode = Addressing_Value; + ok.type = t_bool; + array_add(operands, val); + array_add(operands, ok); + continue; + } array_add(operands, o); } else { TypeTuple *tuple = &o.type->Tuple; @@ -3848,7 +3864,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod ArrayOperand operands; array_init_reserve(&operands, heap_allocator(), 2*ce->args.count); - check_unpack_arguments(c, &operands, ce->args); + check_unpack_arguments(c, -1, &operands, ce->args, false); if (operand->mode == Addressing_Overload) { GB_ASSERT(operand->overload_entities != NULL && @@ -4991,7 +5007,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint goto error; } o->mode = Addressing_MapIndex; - o->type = make_map_tuple_type(c->allocator, t->Map.value); + o->type = t->Map.value; o->expr = node; return Expr_Expr; } diff --git a/src/check_stmt.c b/src/check_stmt.c index 83d3939e8..a77120737 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -262,11 +262,8 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { return NULL; case Addressing_Variable: break; - case Addressing_MapIndex: { - Type *t = base_type(assignment_type); GB_ASSERT(is_type_tuple(t)); - t = t->Tuple.variables[0]->type; - assignment_type = t; - } break; + case Addressing_MapIndex: + break; default: { if (op_b.expr->kind == AstNode_SelectorExpr) { // NOTE(bill): Extra error checks From 8cfae17535518cd10ebe26eb5d4539805ce81295 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 6 Feb 2017 22:19:32 +0000 Subject: [PATCH 4/7] `map` literals --- code/demo.odin | 42 +++++++++++++----- src/check_expr.c | 31 ++++++++++++-- src/ir.c | 108 +++++++++++++++++++++++++++++++++-------------- src/parser.c | 1 + 4 files changed, 136 insertions(+), 46 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 90ac11858..d91d1d5c7 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -11,20 +11,40 @@ main :: proc() { - m: map[string]u32; - reserve(^m, 16); - defer free(m); + { + m := map[f32]int{}; + reserve(^m, 16); + defer free(m); - m["a"] = 56; - m["b"] = 13453; - m["c"] = 7654; - c := m["c"]; - _, ok := m["c"]; - assert(ok && c == 7654); + m[1.0] = 1278; + m[2.0] = 7643; + m[3.0] = 564; + c := m[3.0]; + _, ok := m[3.0]; + assert(ok && c == 564); - for val, key in m { - fmt.printf("m[\"%s\"] == %v\n", key, val); + for val, key in m { + fmt.printf("m[%f] == %v\n", key, val); + } } + { + m := map[string]u32{ + "a" = 56, + "b" = 13453, + "c" = 7654, + }; + defer free(m); + + c := m["c"]; + _, ok := m["c"]; + assert(ok && c == 7654); + + for val, key in m { + fmt.printf("m[\"%s\"] == %v\n", key, val); + } + } + + // fm: map[128, int]f32; diff --git a/src/check_expr.c b/src/check_expr.c index b271a62f9..13f66d060 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -2885,14 +2885,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id Type *type = operand->type; if (!is_type_pointer(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); return false; } type = type_deref(type); - if (!is_type_dynamic_array(type)) { + if (!is_type_dynamic_array(type) && !is_type_map(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 map or dynamic array, got `%s`", str); gb_string_free(str); return false; } @@ -4750,6 +4750,31 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } } break; + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + is_constant = false; + { // Checker values + for_array(i, cl->elems) { + AstNode *elem = cl->elems.e[i]; + if (elem->kind != AstNode_FieldValue) { + error_node(elem, "Only `field = value` elements are allowed in a map literal"); + continue; + } + ast_node(fv, FieldValue, elem); + check_expr_with_type_hint(c, o, fv->field, t->Map.key); + check_assignment(c, o, t->Map.key, str_lit("map literal")); + if (o->mode == Addressing_Invalid) { + continue; + } + + check_expr_with_type_hint(c, o, fv->value, t->Map.value); + check_assignment(c, o, t->Map.value, str_lit("map literal")); + } + } + } break; + default: { gbString str = type_to_string(type); error_node(node, "Invalid compound literal type `%s`", str); diff --git a/src/ir.c b/src/ir.c index 7d04a0dd4..c7d97fd15 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1386,6 +1386,10 @@ void ir_emit_startup_runtime(irProcedure *proc) { ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime)); } +irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { + return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); +} + irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right); @@ -1419,15 +1423,26 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) return ir_emit_load(proc, h); } -irValue *ir_gen_map_key(irProcedure *proc, irValue *key) { +irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { irValue *v = ir_add_local_generated(proc, t_map_key); Type *t = base_type(ir_type(key)); + key = ir_emit_conv(proc, key, key_type); if (is_type_integer(t)) { ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), 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, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, t_u64)); - } else { + } else if (is_type_float(t)) { + irValue *bits = NULL; + i64 size = type_size_of(proc->module->sizes, proc->module->allocator, t); + switch (8*size) { + case 32: bits = ir_emit_bitcast(proc, key, t_u32); break; + case 64: bits = ir_emit_bitcast(proc, key, t_u64); break; + default: GB_PANIC("Unhandled float size: %lld bits", size); break; + } + + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, bits, t_u64)); + } else if (is_type_string(t)) { irValue *str = ir_emit_conv(proc, key, t_string); irValue *hashed_str = NULL; @@ -1443,6 +1458,8 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key) { } ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), str); + } else { + GB_PANIC("Unhandled map key type"); } return ir_emit_load(proc, v); @@ -1478,37 +1495,35 @@ Type *ir_addr_type(irAddr addr) { return type_deref(t); } +irValue *ir_insert_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type, + irValue *map_key, irValue *map_value) { + map_type = base_type(map_type); + + irValue *h = ir_gen_map_header(proc, addr, map_type); + irValue *key = ir_gen_map_key(proc, map_key, map_type->Map.key); + irValue *v = ir_emit_conv(proc, map_value, map_type->Map.value); + irValue *ptr = ir_address_from_load_or_generate_local(proc, v); + 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); +} + irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { if (addr.addr == NULL) { return NULL; } if (addr.kind == irAddr_Map) { - Type *map_type = base_type(addr.map_type); - irValue *h = ir_gen_map_header(proc, addr.addr, map_type); - irValue *key = ir_gen_map_key(proc, addr.map_key); - irValue *v = ir_emit_conv(proc, value, map_type->Map.value); - irValue *ptr = ir_address_from_load_or_generate_local(proc, v); - 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); + return ir_insert_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value); } - // if (addr.kind == irAddr_Vector) { - // irValue *v = ir_emit_load(proc, addr.addr); - // Type *elem_type = base_type(ir_type(v))->Vector.elem; - // irValue *elem = ir_emit_conv(proc, value, elem_type); - // irValue *out = ir_emit(proc, ir_make_instr_insert_element(proc, v, elem, addr.Vector.index)); - // return ir_emit_store(proc, addr.addr, out); - // } else { - irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); - return ir_emit_store(proc, addr.addr, v); - // } + irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); + return ir_emit_store(proc, addr.addr, v); } irValue *ir_addr_load(irProcedure *proc, irAddr addr) { @@ -1522,7 +1537,7 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) { Type *map_type = base_type(addr.map_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 *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key); irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2); args[0] = h; @@ -2092,9 +2107,6 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { return str_lit(""); } -irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { - return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); -} irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { @@ -3183,9 +3195,19 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv case BuiltinProc_clear: { ir_emit_comment(proc, str_lit("reserve")); - irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]); - irValue *count_ptr = ir_emit_struct_ep(proc, array_ptr, 1); - ir_emit_store(proc, count_ptr, v_zero); + irValue *ptr = ir_build_expr(proc, ce->args.e[0]); + Type *t = base_type(type_deref(ir_type(ptr))); + if (is_type_dynamic_array(t)) { + irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, count_ptr, v_zero); + } else if (is_type_dynamic_map(t)) { + irValue *ha = ir_emit_struct_ep(proc, ptr, 0); + irValue *ea = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero); + ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero); + } else { + GB_PANIC("TODO(bill): ir clear for `%s`", type_to_string(t)); + } return NULL; } break; @@ -4152,6 +4174,28 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { } } } break; + + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + gbAllocator a = proc->module->allocator; + { + irValue **args = gb_alloc_array(a, irValue *, 4); + args[0] = ir_gen_map_header(proc, v, type); + args[1] = ir_make_const_int(a, 2*cl->elems.count); + ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + } + for_array(field_index, cl->elems) { + AstNode *elem = cl->elems.e[field_index]; + ast_node(fv, FieldValue, elem); + + irValue *key = ir_build_expr(proc, fv->field); + irValue *value = ir_build_expr(proc, fv->value); + ir_insert_map_key_and_value(proc, v, type, key, value); + } + } break; + case Type_Array: { if (cl->elems.count > 0) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr))); diff --git a/src/parser.c b/src/parser.c index 652181c90..079e39c2f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1854,6 +1854,7 @@ bool is_literal_type(AstNode *node) { case AstNode_ArrayType: case AstNode_VectorType: case AstNode_StructType: + case AstNode_MapType: return true; } return false; From 5796c413571140798d9ca597cda4d34c6762eabe Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 6 Feb 2017 22:53:48 +0000 Subject: [PATCH 5/7] `map` immutable fields: count, capacity, allocator --- core/fmt.odin | 11 ++++--- src/gb/gb.h | 86 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/ir.c | 20 ++++++++++-- src/types.c | 36 ++++++++++++++++++++- 4 files changed, 143 insertions(+), 10 deletions(-) diff --git a/core/fmt.odin b/core/fmt.odin index 1de2c2293..105888caf 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -142,10 +142,13 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { if info.params == nil { buffer_write_string(buf, "()"); } else { - count := (cast(^Tuple)info.params).fields.count; - if count == 1 { buffer_write_string(buf, "("); } - buffer_write_type(buf, info.params); - if count == 1 { buffer_write_string(buf, ")"); } + fields := (cast(^Tuple)info.params).fields; + buffer_write_string(buf, "("); + for f, i in fields { + if i > 0 { buffer_write_string(buf, ", "); } + buffer_write_type(buf, f.type_info); + } + buffer_write_string(buf, ")"); } if info.results != nil { buffer_write_string(buf, " -> "); diff --git a/src/gb/gb.h b/src/gb/gb.h index 8edd4b92f..e45ceb050 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -58,6 +58,7 @@ TODOS - More date & time functions VERSION HISTORY + 0.27 - OSX fixes and Linux gbAffinity 0.26d - Minor changes to how gbFile works 0.26c - gb_str_to_f* fix 0.26b - Minor fixes @@ -1008,7 +1009,12 @@ typedef struct gbAffinity { } gbAffinity; #elif defined(GB_SYSTEM_LINUX) -#error TODO(bill): Implement gbAffinity for linux +typedef struct gbAffinity { + b32 is_accurate; + isize core_count; + isize thread_count; + isize threads_per_core; +} gbAffinity; #else #error TODO(bill): Unknown system #endif @@ -4979,7 +4985,83 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { } #elif defined(GB_SYSTEM_LINUX) -#error TODO(bill): Implement gbAffinity for linux +// IMPORTANT TODO(bill): This gbAffinity stuff for linux needs be improved a lot! +// NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core. +#include + +void gb_affinity_init(gbAffinity *a) { + b32 accurate = true; + isize threads = 0; + + a->thread_count = 1; + a->core_count = sysconf(_SC_NPROCESSORS_ONLN); + a->threads_per_core = 1; + + + if(a->core_count <= 0) { + a->core_count = 1; + accurate = false; + } + + // Parsing /proc/cpuinfo to get the number of threads per core. + // NOTE(zangent): This calls the CPU's threads "cores", although the wording + // is kind of weird. This should be right, though. + if (fopen("/proc/cpuinfo", "r") != NULL) { + for (;;) { + // The 'temporary char'. Everything goes into this char, + // so that we can check against EOF at the end of this loop. + char c; + +#define AF__CHECK(letter) ((c = getc(cpu_info)) == letter) + if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') && + AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) { + // We're on a CPU info line. + while (!AF__CHECK(EOF)) { + if (c == '\n') { + break; + } else if (c < '0' || '9' > c) { + continue; + } + threads = threads * 10 + (c - '0'); + } + break; + } else { + while (!AF__CHECK('\n')) { + if (c==EOF) { + break; + } + } + } + if (c == EOF) { + break; + } +#undef AF__CHECK + } + } + + if (threads == 0) { + threads = 1; + accurate = false; + } + + a->threads_per_core = threads; + a->thread_count = a->threads_per_core * a->core_count; + a->is_accurate = accurate; + +} + +void gb_affinity_destroy(gbAffinity *a) { + gb_unused(a); +} + +b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { + return true; +} + +isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { + GB_ASSERT(0 <= core && core < a->core_count); + return a->threads_per_core; +} #else #error TODO(bill): Unknown system #endif diff --git a/src/ir.c b/src/ir.c index c7d97fd15..c6c834068 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1495,7 +1495,7 @@ Type *ir_addr_type(irAddr addr) { return type_deref(t); } -irValue *ir_insert_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type, +irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type, irValue *map_key, irValue *map_value) { map_type = base_type(map_type); @@ -1519,7 +1519,7 @@ irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { return NULL; } if (addr.kind == irAddr_Map) { - return ir_insert_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value); + return ir_insert_dynamic_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value); } irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); @@ -1925,6 +1925,13 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selec e = ir_emit_array_epi(proc, e, index); } else if (type->kind == Type_Array) { e = ir_emit_array_epi(proc, e, index); + } else if (type->kind == Type_Map) { + e = ir_emit_struct_ep(proc, e, 1); + switch (index) { + case 0: e = ir_emit_struct_ep(proc, e, 1); break; // count + case 1: e = ir_emit_struct_ep(proc, e, 2); break; // capacity + case 2: e = ir_emit_struct_ep(proc, e, 3); break; // allocator + } } else { GB_PANIC("un-gep-able type"); } @@ -1951,6 +1958,13 @@ irValue *ir_emit_deep_field_ev(irProcedure *proc, Type *type, irValue *e, Select GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?"); type = type->Record.fields[index]->type; e = ir_emit_conv(proc, e, type); + } else if (type->kind == Type_Map) { + e = ir_emit_struct_ev(proc, e, 1); + switch (index) { + case 0: e = ir_emit_struct_ev(proc, e, 1); break; // count + case 1: e = ir_emit_struct_ev(proc, e, 2); break; // capacity + case 2: e = ir_emit_struct_ev(proc, e, 3); break; // allocator + } } else { e = ir_emit_struct_ev(proc, e, index); } @@ -4192,7 +4206,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { irValue *key = ir_build_expr(proc, fv->field); irValue *value = ir_build_expr(proc, fv->value); - ir_insert_map_key_and_value(proc, v, type, key, value); + ir_insert_dynamic_map_key_and_value(proc, v, type, key, value); } } break; diff --git a/src/types.c b/src/types.c index 0402b2470..be28c82f0 100644 --- a/src/types.c +++ b/src/types.c @@ -1073,6 +1073,10 @@ gb_global Entity *entity__dynamic_array_count = NULL; gb_global Entity *entity__dynamic_array_capacity = NULL; gb_global Entity *entity__dynamic_array_allocator = NULL; +gb_global Entity *entity__dynamic_map_count = NULL; +gb_global Entity *entity__dynamic_map_capacity = NULL; +gb_global Entity *entity__dynamic_map_allocator = NULL; + Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel); Selection lookup_field(gbAllocator a, Type *type_, String field_name, bool is_type) { @@ -1240,7 +1244,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__slice_count; return sel; } - } else if (type->kind == Type_DynamicArray) { + } else if (type->kind == Type_DynamicArray) { String data_str = str_lit("data"); String count_str = str_lit("count"); String capacity_str = str_lit("capacity"); @@ -1273,6 +1277,36 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__dynamic_array_allocator; return sel; } + } else if (type->kind == Type_Map) { + String count_str = str_lit("count"); + String capacity_str = str_lit("capacity"); + String allocator_str = str_lit("allocator"); + + if (str_eq(field_name, count_str)) { + selection_add_index(&sel, 0); + if (entity__dynamic_map_count == NULL) { + entity__dynamic_map_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 0); + entity__dynamic_map_count->Variable.is_immutable = true; + } + sel.entity = entity__dynamic_map_count; + return sel; + } else if (str_eq(field_name, capacity_str)) { + selection_add_index(&sel, 1); + if (entity__dynamic_map_capacity == NULL) { + entity__dynamic_map_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 1); + entity__dynamic_map_capacity->Variable.is_immutable = true; + } + sel.entity = entity__dynamic_map_capacity; + return sel; + } else if (str_eq(field_name, allocator_str)) { + selection_add_index(&sel, 2); + if (entity__dynamic_map_allocator == NULL) { + entity__dynamic_map_allocator = make_entity_field(a, NULL, make_token_ident(allocator_str), t_allocator, false, 2); + entity__dynamic_map_allocator->Variable.is_immutable = true; + } + sel.entity = entity__dynamic_map_allocator; + return sel; + } } if (type->kind != Type_Record) { From 219ca0ac4677235d595d9bd6e1be08eedfdf7d66 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Tue, 7 Feb 2017 00:10:58 +0000 Subject: [PATCH 6/7] Map type info and fmt printing --- code/demo.odin | 6 ++-- core/_preload.odin | 74 ++++++++++++++++++++++++++++++---------------- core/fmt.odin | 49 ++++++++++++++++++++++++++++-- src/check_expr.c | 16 +++++----- src/checker.c | 14 +++++++-- src/ir.c | 24 ++++++++++++--- src/types.c | 8 ++--- 7 files changed, 139 insertions(+), 52 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index d91d1d5c7..45ae781a2 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -12,7 +12,7 @@ main :: proc() { { - m := map[f32]int{}; + m: map[f32]int; reserve(^m, 16); defer free(m); @@ -39,9 +39,7 @@ main :: proc() { _, ok := m["c"]; assert(ok && c == 7654); - for val, key in m { - fmt.printf("m[\"%s\"] == %v\n", key, val); - } + fmt.println(m); } diff --git a/core/_preload.odin b/core/_preload.odin index ec473348e..1eb8a2d06 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -20,11 +20,12 @@ Type_Info_Member :: struct #ordered { offset: int, // offsets are not used in tuples } Type_Info_Record :: struct #ordered { - fields: []Type_Info_Member, - size: int, // in bytes - align: int, // in bytes - packed: bool, - ordered: bool, + fields: []Type_Info_Member, + size: int, // in bytes + align: int, // in bytes + packed: bool, + ordered: bool, + custom_align: bool, } Type_Info_Enum_Value :: raw_union { f: f64, @@ -90,10 +91,16 @@ Type_Info :: union { Union: Type_Info_Record, Raw_Union: Type_Info_Record, Enum: struct #ordered { - base: ^Type_Info, - names: []string, + base: ^Type_Info, + names: []string, values: []Type_Info_Enum_Value, }, + Map: struct #ordered { + key: ^Type_Info, + value: ^Type_Info, + generated_struct: ^Type_Info, + count: int, // == 0 if dynamic + }, } // // NOTE(bill): only the ones that are needed (not all types) @@ -113,6 +120,21 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { } +type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info { + if info == nil { + return nil; + } + base := info; + match type i in base { + case Type_Info.Named: + base = i.base; + case Type_Info.Enum: + base = i.base; + } + return base; +} + + assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume"; @@ -444,26 +466,26 @@ __default_hash_string :: proc(s: string) -> u64 { return __default_hash(cast([]byte)s); } -Map_Key :: struct #ordered { +__Map_Key :: struct #ordered { hash: u64, str: string, } -Map_Find_Result :: struct #ordered { +__Map_Find_Result :: struct #ordered { hash_index: int, entry_prev: int, entry_index: int, } -Map_Entry_Header :: struct #ordered { - key: Map_Key, +__Map_Entry_Header :: struct #ordered { + key: __Map_Key, next: int, /* value: Value_Type, */ } -Map_Header :: struct #ordered { +__Map_Header :: struct #ordered { m: ^Raw_Dynamic_Map, is_key_string: bool, entry_size: int, @@ -471,13 +493,13 @@ Map_Header :: struct #ordered { 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 { h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), capacity); e := __dynamic_array_reserve(^m.entries, entry_size, entry_align, capacity); return h && e; } -__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) { +__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { new_header := header; nm: Raw_Dynamic_Map; new_header.m = ^nm; @@ -519,7 +541,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) { header.m^ = nm; } -__dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { +__dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr { index := __dynamic_map_find(h, key).entry_index; if index >= 0 { data := cast(^byte)__dynamic_map_get_entry(h, index); @@ -529,7 +551,7 @@ __dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { return nil; } -__dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) { +__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) { index: int; if m.hashes.count == 0 { @@ -559,17 +581,17 @@ __dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) { } -__dynamic_map_grow :: proc(using h: 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 h: 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 { +__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; @@ -579,8 +601,8 @@ __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool { return false; } -__dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result { - fr := Map_Find_Result{-1, -1, -1}; +__dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result { + fr := __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]; @@ -596,7 +618,7 @@ __dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result return fr; } -__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key) -> int { +__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int { prev := m.entries.count; c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align); if c != prev { @@ -608,19 +630,19 @@ __dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key) -> int { } -__dynamic_map_remove :: proc(using h: Map_Header, key: Map_Key) { +__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 { +__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; + return cast(^__Map_Entry_Header)data; } -__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) { +__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 { diff --git a/core/fmt.odin b/core/fmt.odin index 105888caf..91519167b 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -191,18 +191,30 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { buffer_write_string(buf, "]"); buffer_write_type(buf, info.elem); + case Map: + buffer_write_string(buf, "map["); + buffer_write_type(buf, info.key); + buffer_write_byte(buf, ']'); + buffer_write_type(buf, info.value); + case Struct: buffer_write_string(buf, "struct "); if info.packed { buffer_write_string(buf, "#packed "); } if info.ordered { buffer_write_string(buf, "#ordered "); } - buffer_write_string(buf, "{"); + if info.custom_align { + buffer_write_string(buf, "#align "); + fi := Fmt_Info{buf = buf}; + fmt_int(^fi, cast(u64)info.align, false, 'd'); + buffer_write_byte(buf, ' '); + } + buffer_write_byte(buf, '{'); for field, i in info.fields { buffer_write_string(buf, field.name); buffer_write_string(buf, ": "); buffer_write_type(buf, field.type_info); buffer_write_byte(buf, ','); } - buffer_write_string(buf, "}"); + buffer_write_byte(buf, '}'); case Union: buffer_write_string(buf, "union {"); @@ -778,6 +790,39 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v'); } + case Map: + if verb != 'v' { + fmt_bad_verb(fi, verb); + return; + } + + buffer_write_string(fi.buf, "map["); + defer buffer_write_byte(fi.buf, ']'); + entries := ^(cast(^Raw_Dynamic_Map)v.data).entries; + gs, _ := union_cast(^Struct)info.generated_struct; + ed, _ := union_cast(^Dynamic_Array)gs.fields[1].type_info; + entry_type, _ := union_cast(^Struct)ed.elem; + entry_size := ed.elem_size; + for i in 0.. 0 { + buffer_write_string(fi.buf, ", "); + } + data := cast(^byte)entries.data + i*entry_size; + + header := cast(^__Map_Entry_Header)data; + if types.is_string(info.key) { + buffer_write_string(fi.buf, header.key.str); + } else { + fi := Fmt_Info{buf = fi.buf}; + fmt_arg(^fi, any{info.key, cast(rawptr)^header.key.hash}, 'v'); + } + + buffer_write_string(fi.buf, "="); + + value := data + entry_type.fields[2].offset; + fmt_arg(fi, any{info.value, cast(rawptr)value}, 'v'); + } + case Slice: if verb != 'v' { fmt_bad_verb(fi, verb); diff --git a/src/check_expr.c b/src/check_expr.c index 13f66d060..a8f5fe55b 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1097,8 +1097,8 @@ Type *make_map_tuple_type(gbAllocator a, Type *value) { Type *t = make_type_tuple(a); t->Tuple.variables = gb_alloc_array(a, Entity *, 2); t->Tuple.variable_count = 2; - t->Tuple.variables[0] = make_entity_param(a, NULL, blank_token, value, false, false); - t->Tuple.variables[1] = make_entity_param(a, NULL, blank_token, t_bool, false, false); + t->Tuple.variables[0] = make_entity_field(a, NULL, blank_token, value, false, 0); + t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, t_bool, false, 1); return t; } @@ -1148,9 +1148,9 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { isize field_count = 3; Entity **fields = gb_alloc_array(a, Entity *, field_count); - fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")), t_map_key, 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("value")), value, false, false); + fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")), t_map_key, false, 0); + fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("next")), t_int, false, 1); + fields[2] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value, false, 2); check_close_scope(c); @@ -1159,7 +1159,6 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { entry_type->Record.field_count = field_count; type_set_offsets(c->sizes, a, entry_type); - type->Map.entry_type = entry_type; } @@ -1181,8 +1180,8 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { isize field_count = 2; Entity **fields = gb_alloc_array(a, Entity *, field_count); - fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("hashes")), hashes_type, false, false); - fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("entries")), entries_type, false, false); + fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("hashes")), hashes_type, false, 0); + fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("entries")), entries_type, false, 1); check_close_scope(c); @@ -1191,7 +1190,6 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { generated_struct_type->Record.field_count = field_count; type_set_offsets(c->sizes, a, generated_struct_type); - type->Map.generated_struct_type = generated_struct_type; } diff --git a/src/checker.c b/src/checker.c index 12915197a..78643e03c 100644 --- a/src/checker.c +++ b/src/checker.c @@ -958,6 +958,12 @@ void add_type_info_type(Checker *c, Type *t) { } } break; + case Type_Map: { + add_type_info_type(c, bt->Map.key); + add_type_info_type(c, bt->Map.value); + add_type_info_type(c, bt->Map.generated_struct_type); + } break; + case Type_Tuple: for (isize i = 0; i < bt->Tuple.variable_count; i++) { Entity *var = bt->Tuple.variables[i]; @@ -1093,7 +1099,7 @@ void init_preload(Checker *c) { - if (record->field_count != 19) { + if (record->field_count != 20) { compiler_error("Invalid `Type_Info` layout"); } t_type_info_named = record->fields[ 1]->type; @@ -1114,6 +1120,7 @@ void init_preload(Checker *c) { t_type_info_union = record->fields[16]->type; t_type_info_raw_union = record->fields[17]->type; t_type_info_enum = record->fields[18]->type; + t_type_info_map = record->fields[19]->type; t_type_info_named_ptr = make_type_pointer(heap_allocator(), t_type_info_named); t_type_info_integer_ptr = make_type_pointer(heap_allocator(), t_type_info_integer); @@ -1133,6 +1140,7 @@ void init_preload(Checker *c) { t_type_info_union_ptr = make_type_pointer(heap_allocator(), t_type_info_union); t_type_info_raw_union_ptr = make_type_pointer(heap_allocator(), t_type_info_raw_union); t_type_info_enum_ptr = make_type_pointer(heap_allocator(), t_type_info_enum); + t_type_info_map_ptr = make_type_pointer(heap_allocator(), t_type_info_map); } if (t_allocator == NULL) { @@ -1155,12 +1163,12 @@ void init_preload(Checker *c) { } if (t_map_key == NULL) { - Entity *e = find_core_entity(c, str_lit("Map_Key")); + 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")); + Entity *e = find_core_entity(c, str_lit("__Map_Header")); t_map_header = e->type; } diff --git a/src/ir.c b/src/ir.c index c6c834068..084191192 100644 --- a/src/ir.c +++ b/src/ir.c @@ -6286,14 +6286,16 @@ void ir_gen_tree(irGen *s) { tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr); { - irValue *packed = ir_make_const_bool(a, t->Record.struct_is_packed); - irValue *ordered = ir_make_const_bool(a, t->Record.struct_is_ordered); - irValue *size = ir_make_const_int(a, type_size_of(m->sizes, a, t)); - irValue *align = ir_make_const_int(a, type_align_of(m->sizes, a, t)); + irValue *size = ir_make_const_int(a, type_size_of(m->sizes, a, t)); + irValue *align = ir_make_const_int(a, type_align_of(m->sizes, a, t)); + irValue *packed = ir_make_const_bool(a, t->Record.struct_is_packed); + irValue *ordered = ir_make_const_bool(a, t->Record.struct_is_ordered); + irValue *custom_align = ir_make_const_bool(a, t->Record.custom_align); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), size); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), align); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), packed); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), ordered); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), custom_align); } irValue *memory = ir_type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index); @@ -6516,6 +6518,20 @@ void ir_gen_tree(irGen *s) { // TODO(bill): Type_Info for procedures } break; + + case Type_Map: { + tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr); + + irValue *key = ir_emit_struct_ep(proc, tag, 0); + irValue *value = ir_emit_struct_ep(proc, tag, 1); + irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2); + irValue *count = ir_emit_struct_ep(proc, tag, 3); + + ir_emit_store(proc, key, ir_get_type_info_ptr(proc, type_info_data, t->Map.key)); + ir_emit_store(proc, value, ir_get_type_info_ptr(proc, type_info_data, t->Map.value)); + ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, type_info_data, t->Map.generated_struct_type)); + ir_emit_store(proc, count, ir_make_const_int(a, t->Map.count)); + } break; } if (tag != NULL) { diff --git a/src/types.c b/src/types.c index be28c82f0..eae9ec556 100644 --- a/src/types.c +++ b/src/types.c @@ -300,6 +300,7 @@ gb_global Type *t_type_info_struct = NULL; gb_global Type *t_type_info_union = NULL; gb_global Type *t_type_info_raw_union = NULL; gb_global Type *t_type_info_enum = NULL; +gb_global Type *t_type_info_map = NULL; gb_global Type *t_type_info_named_ptr = NULL; @@ -320,6 +321,7 @@ gb_global Type *t_type_info_struct_ptr = NULL; gb_global Type *t_type_info_union_ptr = NULL; gb_global Type *t_type_info_raw_union_ptr = NULL; gb_global Type *t_type_info_enum_ptr = NULL; +gb_global Type *t_type_info_map_ptr = NULL; @@ -1561,8 +1563,7 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type case Type_Map: { if (t->Map.count == 0) { // Dynamic - // NOTE(bill): same as a dynamic array - return s.word_size; + return type_align_of_internal(s, allocator, t->Map.generated_struct_type, path); } GB_PANIC("TODO(bill): Fixed map alignment"); } break; @@ -1778,8 +1779,7 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP case Type_Map: { if (t->Map.count == 0) { // Dynamic - // NOTE(bill): same as a two dynamic arrays - return 2 * type_size_of_internal(s, allocator, t_raw_dynamic_array, path); + return type_size_of_internal(s, allocator, t->Map.generated_struct_type, path); } GB_PANIC("TODO(bill): Fixed map size"); } From 454d0b5cf5b109fda01b3380b1fab0434d7ff51d Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Tue, 7 Feb 2017 18:13:37 +0000 Subject: [PATCH 7/7] Fix global maps and initialize the preload types before --- code/demo.odin | 12 +++++++++--- src/check_expr.c | 6 ++++++ src/check_stmt.c | 1 - src/ir.c | 13 ++++--------- src/types.c | 8 ++++++++ 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 45ae781a2..bc193ef1f 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -9,7 +9,6 @@ #import "utf8.odin"; #import ht "http_test.odin"; - main :: proc() { { m: map[f32]int; @@ -21,11 +20,18 @@ main :: proc() { m[3.0] = 564; c := m[3.0]; _, ok := m[3.0]; - assert(ok && c == 564); + // assert(ok && c == 564); + fmt.print("map["); + i := 0; for val, key in m { - fmt.printf("m[%f] == %v\n", key, val); + if i > 0 { + fmt.print(", "); + } + fmt.printf("%f=%v", key, val); + i += 1; } + fmt.println("]"); } { m := map[string]u32{ diff --git a/src/check_expr.c b/src/check_expr.c index a8f5fe55b..04f246532 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1132,6 +1132,12 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { gbAllocator a = c->allocator; { + // NOTE(bill): The preload types may have not been set yet + if (t_map_key == NULL) { + init_preload(c); + } + GB_ASSERT(t_map_key != NULL); + Type *entry_type = make_type_struct(a); /* diff --git a/src/check_stmt.c b/src/check_stmt.c index a77120737..9155947fc 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -261,7 +261,6 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { case Addressing_Invalid: return NULL; case Addressing_Variable: - break; case Addressing_MapIndex: break; default: { diff --git a/src/ir.c b/src/ir.c index 084191192..117173ab3 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1395,7 +1395,7 @@ 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))); + GB_ASSERT_MSG(is_type_pointer(ir_type(map_val)), "%s", type_to_string(ir_type(map_val))); gbAllocator a = proc->module->allocator; irValue *h = ir_add_local_generated(proc, t_map_header); @@ -3027,7 +3027,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv case_ast_node(cl, CompoundLit, expr); - return ir_emit_load(proc, ir_build_addr(proc, expr).addr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; @@ -3597,11 +3597,11 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv case_end; case_ast_node(de, DemaybeExpr, expr); - return ir_emit_load(proc, ir_build_addr(proc, expr).addr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; case_ast_node(se, SliceExpr, expr); - return ir_emit_load(proc, ir_build_addr(proc, expr).addr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; case_ast_node(ie, IndexExpr, expr); @@ -3824,17 +3824,12 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { Type *t = base_type(type_of_expr(proc->module->info, ie->expr)); gbAllocator a = proc->module->allocator; - bool deref = is_type_pointer(t); t = base_type(type_deref(t)); if (is_type_map(t)) { irAddr map_addr = ir_build_addr(proc, ie->expr); irValue *map_val = map_addr.addr; - if (deref) { - map_val = ir_addr_load(proc, map_addr); - } - irValue *key = ir_build_expr(proc, ie->index); key = ir_emit_conv(proc, key, t->Map.key); diff --git a/src/types.c b/src/types.c index eae9ec556..dbded4a73 100644 --- a/src/types.c +++ b/src/types.c @@ -923,6 +923,14 @@ bool are_types_identical(Type *x, Type *y) { are_types_identical(x->Proc.results, y->Proc.results); } break; + + case Type_Map: + if (y->kind == Type_Map) { + return x->Map.count == y->Map.count && + are_types_identical(x->Map.key, y->Map.key) && + are_types_identical(x->Map.value, y->Map.value); + } + break; }