diff options
| author | Zac Pierson <zacpiersonhehe@gmail.com> | 2017-02-20 10:14:52 -0600 |
|---|---|---|
| committer | Zac Pierson <zacpiersonhehe@gmail.com> | 2017-02-20 10:14:52 -0600 |
| commit | 8d5896ab7e1b069135c25f7ae75ea8a806789a81 (patch) | |
| tree | 473e8a53fdc1c4324e5f06f0420b5b55a21a493f /src | |
| parent | 802b1a70f881968f4e96eb8bbec9f072b4de2892 (diff) | |
| parent | a94dfdf21d798bc72bbee0cc04b80149f0d4b8d2 (diff) | |
Merge https://github.com/gingerBill/Odin
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_expr.c | 339 | ||||
| -rw-r--r-- | src/checker.c | 9 | ||||
| -rw-r--r-- | src/entity.c | 1 | ||||
| -rw-r--r-- | src/gb/gb.h | 2 | ||||
| -rw-r--r-- | src/ir.c | 404 | ||||
| -rw-r--r-- | src/ir_print.c | 54 | ||||
| -rw-r--r-- | src/main.c | 9 | ||||
| -rw-r--r-- | src/parser.c | 275 | ||||
| -rw-r--r-- | src/types.c | 36 |
9 files changed, 732 insertions, 397 deletions
diff --git a/src/check_expr.c b/src/check_expr.c index 687f4ebea..d85c5100a 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -183,10 +183,7 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { // TODO(bill): Should I allow this implicit conversion at all?! // rawptr <- ^T - if (is_type_rawptr(dst) && is_type_pointer(src)) { - if (dst != type) { - return -1; - } + if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) { return 5; } #endif @@ -358,7 +355,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Token name_token = name->Ident; - if (str_eq(name_token.string, str_lit(""))) { + if (str_eq(name_token.string, str_lit("names"))) { error(name_token, "`names` is a reserved identifier for unions"); continue; } @@ -599,22 +596,76 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { GB_ASSERT(is_type_union(union_type)); ast_node(ut, UnionType, node); - isize field_count = 1; - for_array(field_index, ut->fields) { - AstNode *field = ut->fields.e[field_index]; - switch (field->kind) { - case_ast_node(f, Field, field); - field_count += f->names.count; - case_end; - } - } + isize field_count = ut->fields.count+1; + + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + + MapEntity entity_map = {0}; + map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count); Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count); - check_fields(c, node, ut->fields, fields, field_count, str_lit("union")); + isize field_index = 0; + fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL); + + for_array(i, ut->fields) { + AstNode *field = ut->fields.e[i]; + if (field->kind != AstNode_UnionField) { + continue; + } + ast_node(f, UnionField, ut->fields.e[i]); + Token name_token = f->name->Ident; + + if (str_eq(name_token.string, str_lit("names"))) { + error(name_token, "`names` is a reserved identifier for unions"); + continue; + } + + Type *base_type = make_type_struct(c->allocator); + { + ast_node(fl, FieldList, f->list); + isize field_count = 0; + for_array(j, fl->list) { + ast_node(f, Field, fl->list.e[j]); + field_count += f->names.count; + } + + Token token = name_token; + token.kind = Token_struct; + AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, fl->list, field_count, + false, true, NULL); + + check_open_scope(c, dummy_struct); + check_struct_type(c, base_type, dummy_struct); + check_close_scope(c); + base_type->Record.node = dummy_struct; + } + + Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL); + Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type); + type->Named.type_name = e; + add_entity(c, c->context.scope, f->name, e); + + if (str_eq(name_token.string, str_lit("_"))) { + error(name_token, "`_` cannot be used a union subtype"); + continue; + } + + HashKey key = hash_string(name_token.string); + if (map_entity_get(&entity_map, key) != NULL) { + // TODO(bill): Scope checking already checks the declaration + error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string)); + } else { + map_entity_set(&entity_map, key, e); + fields[field_index++] = e; + } + add_entity_use(c, f->name, e); + } + + gb_temp_arena_memory_end(tmp); - union_type->Record.fields = fields; - union_type->Record.field_count = field_count; + union_type->Record.fields = fields; + union_type->Record.field_count = field_index; union_type->Record.names = make_names_field_for_record(c, c->context.scope); } @@ -798,7 +849,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod } -Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) { +Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_) { + if (_params == NULL) { + return NULL; + } + ast_node(field_list, FieldList, _params); + AstNodeArray params = field_list->list; + if (params.count == 0) { return NULL; } @@ -808,7 +865,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v AstNode *field = params.e[i]; if (ast_node_expect(field, AstNode_Field)) { ast_node(f, Field, field); - variable_count += f->names.count; + variable_count += max(f->names.count, 1); } } @@ -877,26 +934,73 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v return tuple; } -Type *check_get_results(Checker *c, Scope *scope, AstNodeArray results) { +Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { + if (_results == NULL) { + return NULL; + } + ast_node(field_list, FieldList, _results); + AstNodeArray results = field_list->list; + if (results.count == 0) { return NULL; } Type *tuple = make_type_tuple(c->allocator); - Entity **variables = gb_alloc_array(c->allocator, Entity *, results.count); + isize variable_count = 0; + for_array(i, results) { + AstNode *field = results.e[i]; + if (ast_node_expect(field, AstNode_Field)) { + ast_node(f, Field, field); + variable_count += max(f->names.count, 1); + } + } + + Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count); isize variable_index = 0; for_array(i, results) { - AstNode *item = results.e[i]; - Type *type = check_type(c, item); - Token token = ast_node_token(item); - token.string = str_lit(""); // NOTE(bill): results are not named - // TODO(bill): Should I have named results? - Entity *param = make_entity_param(c->allocator, scope, token, type, false, false); - // NOTE(bill): No need to record - variables[variable_index++] = param; + ast_node(field, Field, results.e[i]); + Type *type = check_type(c, field->type); + if (field->names.count == 0) { + Token token = ast_node_token(field->type); + token.string = str_lit(""); + Entity *param = make_entity_param(c->allocator, scope, token, type, false, false); + variables[variable_index++] = param; + } else { + for_array(j, field->names) { + Token token = ast_node_token(field->type); + token.string = str_lit(""); + + AstNode *name = field->names.e[j]; + if (name->kind != AstNode_Ident) { + error_node(name, "Expected an identifer for as the field name"); + } else { + token = name->Ident; + } + + Entity *param = make_entity_param(c->allocator, scope, token, type, false, false); + variables[variable_index++] = param; + } + } + } + + for (isize i = 0; i < variable_index; i++) { + String x = variables[i]->token.string; + if (x.len == 0 || str_eq(x, str_lit("_"))) { + continue; + } + for (isize j = i+1; j < variable_index; j++) { + String y = variables[j]->token.string; + if (y.len == 0 || str_eq(y, str_lit("_"))) { + continue; + } + if (str_eq(x, y)) { + error(variables[j]->token, "Duplicate return value name `%.*s`", LIT(y)); + } + } } + tuple->Tuple.variables = variables; - tuple->Tuple.variable_count = results.count; + tuple->Tuple.variable_count = variable_index; return tuple; } @@ -2514,6 +2618,39 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val return true; } +isize entity_overload_count(Scope *s, String name) { + Entity *e = scope_lookup_entity(s, name); + if (e == NULL) { + return 0; + } + if (e->kind == Entity_Procedure) { + // NOTE(bill): Overloads are only allowed with the same scope + return map_entity_multi_count(&s->elements, hash_string(e->token.string)); + } + return 1; +} + +bool check_is_field_exported(Checker *c, Entity *field) { + if (field == NULL) { + // NOTE(bill): Just incase + return true; + } + if (field->kind != Entity_Variable) { + return true; + } + Scope *file_scope = field->scope; + if (file_scope == NULL) { + return true; + } + while (!file_scope->is_file) { + file_scope = file_scope->parent; + } + if (!is_entity_exported(field) && file_scope != c->context.file_scope) { + return false; + } + return true; +} + Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) { ast_node(se, SelectorExpr, node); @@ -2535,8 +2672,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h } if (op_expr->kind == AstNode_Ident) { - String name = op_expr->Ident.string; - Entity *e = scope_lookup_entity(c->context.scope, name); + String op_name = op_expr->Ident.string; + Entity *e = scope_lookup_entity(c->context.scope, op_name); add_entity_use(c, op_expr, e); expr_entity = e; @@ -2545,38 +2682,31 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h // IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile // It pretty much needs to be in this order and this way // If you can clean this up, please do but be really careful - - String sel_name = selector->Ident.string; + String import_name = op_name; + Scope *import_scope = e->ImportName.scope; + String entity_name = selector->Ident.string; check_op_expr = false; - entity = scope_lookup_entity(e->ImportName.scope, sel_name); + entity = scope_lookup_entity(import_scope, entity_name); bool is_declared = entity != NULL; if (is_declared) { if (entity->kind == Entity_Builtin) { + // NOTE(bill): Builtin's are in the universe scope which is part of every scopes hierarchy + // This means that we should just ignore the found result through it is_declared = false; - } else if (entity->scope->is_global && !e->ImportName.scope->is_global) { + } else if (entity->scope->is_global && !import_scope->is_global) { is_declared = false; } } if (!is_declared) { - error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name)); + error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(entity_name), LIT(import_name)); goto error; } check_entity_decl(c, entity, NULL, NULL); GB_ASSERT(entity->type != NULL); - bool is_overloaded = false; - isize overload_count = 0; - HashKey key = {0}; - if (entity->kind == Entity_Procedure) { - key = hash_string(entity->token.string); - // NOTE(bill): Overloads are only allowed with the same scope - Scope *s = entity->scope; - overload_count = map_entity_multi_count(&s->elements, key); - if (overload_count > 1) { - is_overloaded = true; - } - } + isize overload_count = entity_overload_count(import_scope, entity_name); + bool is_overloaded = overload_count > 1; bool implicit_is_found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity)) != NULL; bool is_not_exported = !is_entity_exported(entity); @@ -2588,28 +2718,28 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h if (is_not_exported) { gbString sel_str = expr_to_string(selector); - error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name)); + error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(import_name)); gb_string_free(sel_str); - // NOTE(bill): Not really an error so don't goto error goto error; } if (is_overloaded) { - Scope *s = entity->scope; + HashKey key = hash_string(entity_name); bool skip = false; Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); - map_entity_multi_get_all(&s->elements, key, procs); - for (isize i = 0; i < overload_count; /**/) { + map_entity_multi_get_all(&import_scope->elements, key, procs); + for (isize i = 0; i < overload_count; i++) { Type *t = base_type(procs[i]->type); if (t == t_invalid) { continue; } // NOTE(bill): Check to see if it's imported - if (map_bool_get(&e->ImportName.scope->implicit, hash_pointer(procs[i]))) { + if (map_bool_get(&import_scope->implicit, hash_pointer(procs[i]))) { gb_swap(Entity *, procs[i], procs[overload_count-1]); overload_count--; + i--; // NOTE(bill): Counteract the post event continue; } @@ -2623,8 +2753,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h break; } } - - i++; } if (overload_count > 0 && !skip) { @@ -2648,7 +2776,13 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h if (entity == NULL && selector->kind == AstNode_Ident) { - sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type); + String field_name = selector->Ident.string; + sel = lookup_field(c->allocator, operand->type, field_name, operand->mode == Addressing_Type); + + if (operand->mode != Addressing_Type && !check_is_field_exported(c, sel.entity)) { + error_node(op_expr, "`%.*s` is an unexported field", LIT(field_name)); + goto error; + } entity = sel.entity; // NOTE(bill): Add type info needed for fields like `names` @@ -2913,7 +3047,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } break; case BuiltinProc_append: { - // append :: proc([dynamic]Type, item: ...Type) { + // append :: proc([dynamic]Type, item: ...Type) Type *type = operand->type; type = base_type(type); if (!is_type_dynamic_array(type)) { @@ -2943,6 +3077,37 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->type = t_int; } break; + case BuiltinProc_delete: { + // delete :: proc(map[Key]Value, key: Key) + Type *type = operand->type; + if (!is_type_map(type)) { + gbString str = type_to_string(type); + error_node(operand->expr, "Expected a map, got `%s`", str); + gb_string_free(str); + return false; + } + + Type *key = base_type(type)->Map.key; + Operand x = {Addressing_Invalid}; + AstNode *key_node = ce->args.e[1]; + Operand op = {0}; + check_expr(c, &op, key_node); + if (op.mode == Addressing_Invalid) { + return false; + } + + if (!check_is_assignable_to(c, &op, key)) { + gbString kt = type_to_string(key); + gbString ot = type_to_string(op.type); + error_node(operand->expr, "Expected a key of type `%s`, got `%s`", key, ot); + gb_string_free(ot); + gb_string_free(kt); + return false; + } + + operand->mode = Addressing_NoValue; + } break; + case BuiltinProc_size_of: { // size_of :: proc(Type) -> untyped int @@ -4381,10 +4546,16 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint String name = fv->field->Ident.string; Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type); - if (sel.entity == NULL) { + bool is_unknown = sel.entity == NULL; + if (is_unknown) { error_node(elem, "Unknown field `%.*s` in structure literal", LIT(name)); continue; } + if (!is_unknown && !check_is_field_exported(c, sel.entity)) { + error_node(elem, "Cannot assign to an unexported field `%.*s` in structure literal", LIT(name)); + continue; + } + if (sel.index.count > 1) { error_node(elem, "Cannot assign to an anonymous field `%.*s` in a structure literal (at the moment)", LIT(name)); @@ -4427,6 +4598,14 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint break; } + if (!check_is_field_exported(c, field)) { + gbString t = type_to_string(type); + error_node(o->expr, "Implicit assignment to an unexported field `%.*s` in `%s` literal", + LIT(field->token.string), t); + gb_string_free(t); + continue; + } + if (base_type(field->type) == t_any) { is_constant = false; } @@ -5126,16 +5305,6 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) { gbString write_expr_to_string(gbString str, AstNode *node); -gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) { - for_array(i, params) { - if (i > 0) { - str = gb_string_appendc(str, sep); - } - str = write_expr_to_string(str, params.e[i]); - } - return str; -} - gbString write_record_fields_to_string(gbString str, AstNodeArray params) { for_array(i, params) { if (i > 0) { @@ -5301,6 +5470,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) { if (f->flags&FieldFlag_using) { str = gb_string_appendc(str, "using "); } + if (f->flags&FieldFlag_immutable) { + str = gb_string_appendc(str, "immutable "); + } + if (f->flags&FieldFlag_no_alias) { + str = gb_string_appendc(str, "no_alias "); + } + for_array(i, f->names) { AstNode *name = f->names.e[i]; if (i > 0) { @@ -5308,14 +5484,24 @@ gbString write_expr_to_string(gbString str, AstNode *node) { } str = write_expr_to_string(str, name); } - - str = gb_string_appendc(str, ": "); + if (f->names.count > 0) { + str = gb_string_appendc(str, ": "); + } if (f->flags&FieldFlag_ellipsis) { str = gb_string_appendc(str, "..."); } str = write_expr_to_string(str, f->type); case_end; + case_ast_node(f, FieldList, node); + for_array(i, f->list) { + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = write_expr_to_string(str, f->list.e[i]); + } + case_end; + case_ast_node(ce, CallExpr, node); str = write_expr_to_string(str, ce->proc); str = gb_string_appendc(str, "("); @@ -5332,7 +5518,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_ast_node(pt, ProcType, node); str = gb_string_appendc(str, "proc("); - str = write_params_to_string(str, pt->params, ", "); + str = write_expr_to_string(str, pt->params); str = gb_string_appendc(str, ")"); case_end; @@ -5366,7 +5552,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, " "); } str = gb_string_appendc(str, "{"); - str = write_params_to_string(str, et->fields, ", "); + for_array(i, et->fields) { + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = write_expr_to_string(str, et->fields.e[i]); + } str = gb_string_appendc(str, "}"); case_end; diff --git a/src/checker.c b/src/checker.c index 3bb76245f..5521abfda 100644 --- a/src/checker.c +++ b/src/checker.c @@ -30,6 +30,7 @@ typedef enum BuiltinProcId { BuiltinProc_reserve, BuiltinProc_clear, BuiltinProc_append, + BuiltinProc_delete, BuiltinProc_size_of, BuiltinProc_size_of_val, @@ -73,6 +74,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT("reserve"), 2, false, Expr_Stmt}, {STR_LIT("clear"), 1, false, Expr_Stmt}, {STR_LIT("append"), 1, true, Expr_Expr}, + {STR_LIT("delete"), 2, false, Expr_Stmt}, {STR_LIT("size_of"), 1, false, Expr_Expr}, {STR_LIT("size_of_val"), 1, false, Expr_Expr}, @@ -259,6 +261,7 @@ typedef struct DelayedDecl { } DelayedDecl; typedef struct CheckerContext { + Scope * file_scope; Scope * scope; DeclInfo * decl; u32 stmt_state_flags; @@ -1016,6 +1019,7 @@ void add_curr_ast_file(Checker *c, AstFile *file) { c->curr_ast_file = file; c->context.decl = file->decl_info; c->context.scope = file->scope; + c->context.file_scope = file->scope; } } @@ -1242,6 +1246,9 @@ void check_procedure_overloading(Checker *c, Entity *e) { ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type); switch (kind) { case ProcOverload_Identical: + error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name)); + is_invalid = true; + break; case ProcOverload_CallingConvention: error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name)); is_invalid = true; @@ -1746,6 +1753,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid, id->fullpath, id->import_name.string, scope); + + add_entity(c, parent_scope, NULL, e); } } diff --git a/src/entity.c b/src/entity.c index 99acef870..32d070953 100644 --- a/src/entity.c +++ b/src/entity.c @@ -113,6 +113,7 @@ bool is_entity_kind_exported(EntityKind kind) { } bool is_entity_exported(Entity *e) { + // TODO(bill): Determine the actual exportation rules for imports of entities GB_ASSERT(e != NULL); if (!is_entity_kind_exported(e->kind)) { return false; diff --git a/src/gb/gb.h b/src/gb/gb.h index c8b69b3ca..c2462f260 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -705,7 +705,7 @@ extern "C++" { #endif #ifndef gb_is_between -#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper))) +#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper))) #endif #ifndef gb_abs @@ -15,13 +15,14 @@ typedef Array(irValue *) irValueArray; #define MAP_NAME MapIrDebugInfo #include "map.c" + typedef struct irModule { CheckerInfo * info; gbArena arena; gbArena tmp_arena; gbAllocator allocator; gbAllocator tmp_allocator; - bool generate_debug_info; + // bool generate_debug_info; u32 stmt_state_flags; @@ -29,20 +30,20 @@ typedef struct irModule { String layout; // String triple; - MapEntity min_dep_map; // Key: Entity * - MapIrValue values; // Key: Entity * - MapIrValue members; // Key: String - MapString type_names; // Key: Type * - MapIrDebugInfo debug_info; // Key: Unique pointer - i32 global_string_index; - i32 global_array_index; // For ConstantSlice + MapEntity min_dep_map; // Key: Entity * + MapIrValue values; // Key: Entity * + MapIrValue members; // Key: String + MapString type_names; // Key: Type * + MapIrDebugInfo debug_info; // Key: Unique pointer + i32 global_string_index; + i32 global_array_index; // For ConstantSlice - Entity * entry_point_entity; + Entity * entry_point_entity; - Array(irProcedure *) procs; // NOTE(bill): All procedures with bodies - irValueArray procs_to_generate; // NOTE(bill): Procedures to generate + Array(irProcedure *) procs; // NOTE(bill): All procedures with bodies + irValueArray procs_to_generate; // NOTE(bill): Procedures to generate - Array(String) foreign_library_paths; // Only the ones that were used + Array(String) foreign_library_paths; // Only the ones that were used } irModule; // NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory) @@ -121,6 +122,7 @@ struct irProcedure { irTargetList * target_list; irValueArray referrers; + i32 local_count; i32 instr_count; i32 block_count; @@ -134,90 +136,99 @@ struct irProcedure { #define IR_INSTR_KINDS \ - IR_INSTR_KIND(Comment, struct { String text; }) \ - IR_INSTR_KIND(Local, struct { \ - Entity * entity; \ - Type * type; \ - bool zero_initialized; \ - irValueArray referrers; \ - }) \ - IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \ - IR_INSTR_KIND(Store, struct { irValue *address, *value; }) \ + IR_INSTR_KIND(Comment, struct { String text; }) \ + IR_INSTR_KIND(Local, struct { \ + Entity * entity; \ + Type * type; \ + bool zero_initialized; \ + irValueArray referrers; \ + }) \ + IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \ + IR_INSTR_KIND(Store, struct { irValue *address, *value; }) \ IR_INSTR_KIND(Load, struct { Type *type; irValue *address; }) \ - IR_INSTR_KIND(PtrOffset, struct { \ - irValue *address; \ - irValue *offset; \ - }) \ - IR_INSTR_KIND(ArrayElementPtr, struct { \ - irValue *address; \ - Type * result_type; \ - irValue *elem_index; \ - }) \ - IR_INSTR_KIND(StructElementPtr, struct { \ - irValue *address; \ - Type * result_type; \ - i32 elem_index; \ - }) \ - IR_INSTR_KIND(StructExtractValue, struct { \ - irValue *address; \ - Type * result_type; \ - i32 index; \ - }) \ - IR_INSTR_KIND(UnionTagPtr, struct { \ - irValue *address; \ - Type *type; /* ^int */ \ - }) \ - IR_INSTR_KIND(UnionTagValue, struct { \ - irValue *address; \ - Type *type; /* int */ \ - }) \ - IR_INSTR_KIND(Conv, struct { \ - irConvKind kind; \ - irValue *value; \ - Type *from, *to; \ - }) \ - IR_INSTR_KIND(Jump, struct { irBlock *block; }) \ - IR_INSTR_KIND(If, struct { \ - irValue *cond; \ - irBlock *true_block; \ - irBlock *false_block; \ - }) \ - IR_INSTR_KIND(Return, struct { irValue *value; }) \ - IR_INSTR_KIND(Select, struct { \ - irValue *cond; \ - irValue *true_value; \ - irValue *false_value; \ - }) \ - IR_INSTR_KIND(Phi, struct { irValueArray edges; Type *type; }) \ - IR_INSTR_KIND(Unreachable, i32) \ - IR_INSTR_KIND(UnaryOp, struct { \ - Type * type; \ - TokenKind op; \ - irValue *expr; \ - }) \ - IR_INSTR_KIND(BinaryOp, struct { \ - Type * type; \ - TokenKind op; \ - irValue *left, *right; \ + IR_INSTR_KIND(PtrOffset, struct { \ + irValue *address; \ + irValue *offset; \ + }) \ + IR_INSTR_KIND(ArrayElementPtr, struct { \ + irValue *address; \ + Type * result_type; \ + irValue *elem_index; \ + }) \ + IR_INSTR_KIND(StructElementPtr, struct { \ + irValue *address; \ + Type * result_type; \ + i32 elem_index; \ + }) \ + IR_INSTR_KIND(StructExtractValue, struct { \ + irValue *address; \ + Type * result_type; \ + i32 index; \ + }) \ + IR_INSTR_KIND(UnionTagPtr, struct { \ + irValue *address; \ + Type *type; /* ^int */ \ + }) \ + IR_INSTR_KIND(UnionTagValue, struct { \ + irValue *address; \ + Type *type; /* int */ \ + }) \ + IR_INSTR_KIND(Conv, struct { \ + irConvKind kind; \ + irValue *value; \ + Type *from, *to; \ + }) \ + IR_INSTR_KIND(Jump, struct { irBlock *block; }) \ + IR_INSTR_KIND(If, struct { \ + irValue *cond; \ + irBlock *true_block; \ + irBlock *false_block; \ + }) \ + IR_INSTR_KIND(Return, struct { irValue *value; }) \ + IR_INSTR_KIND(Select, struct { \ + irValue *cond; \ + irValue *true_value; \ + irValue *false_value; \ + }) \ + IR_INSTR_KIND(Phi, struct { irValueArray edges; Type *type; }) \ + IR_INSTR_KIND(Unreachable, i32) \ + IR_INSTR_KIND(UnaryOp, struct { \ + Type * type; \ + TokenKind op; \ + irValue * expr; \ + }) \ + IR_INSTR_KIND(BinaryOp, struct { \ + Type * type; \ + TokenKind op; \ + irValue * left, *right; \ + }) \ + IR_INSTR_KIND(Call, struct { \ + Type * type; /* return type */ \ + irValue * value; \ + irValue **args; \ + isize arg_count; \ + }) \ + IR_INSTR_KIND(StartupRuntime, i32) \ + IR_INSTR_KIND(BoundsCheck, struct { \ + TokenPos pos; \ + irValue *index; \ + irValue *len; \ + }) \ + IR_INSTR_KIND(SliceBoundsCheck, struct { \ + TokenPos pos; \ + irValue *low; \ + irValue *high; \ + bool is_substring; \ + }) \ + IR_INSTR_KIND(DebugDeclare, struct { \ + irDebugInfo *debug_info; \ + AstNode * expr; \ + Entity * entity; \ + bool is_addr; \ + irValue * value; \ }) \ - IR_INSTR_KIND(Call, struct { \ - Type * type; /* return type */ \ - irValue *value; \ - irValue **args; \ - isize arg_count; \ - }) \ - IR_INSTR_KIND(StartupRuntime, i32) \ - IR_INSTR_KIND(BoundsCheck, struct { \ - TokenPos pos; \ - irValue *index; \ - irValue *len; \ - }) \ - IR_INSTR_KIND(SliceBoundsCheck, struct { \ - TokenPos pos; \ - irValue *low; \ - irValue *high; \ - bool is_substring; \ - }) + + #define IR_CONV_KINDS \ IR_CONV_KIND(trunc) \ @@ -394,7 +405,6 @@ irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *m return v; } - typedef enum irDebugEncoding { irDebugBasicEncoding_Invalid = 0, @@ -519,14 +529,19 @@ struct irDebugInfo { }; }; + + typedef struct irGen { irModule module; - gbFile output_file; - bool opt_called; + gbFile output_file; + bool opt_called; } irGen; + + + Type *ir_type(irValue *value); Type *ir_instr_type(irInstr *instr) { switch (instr->kind) { @@ -948,6 +963,16 @@ irValue *ir_make_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue v->Instr.SliceBoundsCheck.is_substring = is_substring; return v; } +irValue *ir_make_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, AstNode *expr, Entity *entity, bool is_addr, irValue *value) { + irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare); + v->Instr.DebugDeclare.debug_info = debug_info; + v->Instr.DebugDeclare.expr = expr; + v->Instr.DebugDeclare.entity = entity; + v->Instr.DebugDeclare.is_addr = is_addr; + v->Instr.DebugDeclare.value = value; + return v; + +} @@ -967,6 +992,23 @@ irValue *ir_make_value_constant_slice(gbAllocator a, Type *type, irValue *backin return v; } + + +irValue *ir_emit(irProcedure *proc, irValue *instr) { + GB_ASSERT(instr->kind == irValue_Instr); + irBlock *b = proc->curr_block; + instr->Instr.parent = b; + if (b != NULL) { + irInstr *i = ir_get_last_instr(b); + if (!ir_is_instr_terminating(i)) { + array_add(&b->instrs, instr); + } + } + return instr; +} + + + irValue *ir_make_const_int(gbAllocator a, i64 i) { return ir_make_value_constant(a, t_int, make_exact_value_integer(i)); } @@ -1060,13 +1102,6 @@ void ir_add_block_to_proc(irProcedure *proc, irBlock *b) { b->index = proc->block_count++; } - -// irBlock *ir_add_block(irProcedure *proc, AstNode *node, char *label) { -// irBlock *block = ir_new_block(proc, node, label); -// ir_add_block_to_proc(proc, block); -// return block; -// } - void ir_start_block(irProcedure *proc, irBlock *block) { proc->curr_block = block; if (block != NULL) { @@ -1166,7 +1201,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) { -irValue *ir_add_local(irProcedure *proc, Entity *e) { +irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) { irBlock *b = proc->decl_block; // all variables must be in the first block irValue *instr = ir_make_instr_local(proc, e, true); instr->Instr.parent = b; @@ -1178,6 +1213,11 @@ irValue *ir_add_local(irProcedure *proc, Entity *e) { ir_emit_zero_init(proc, instr); // } + if (expr != NULL) { + irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity)); + ir_emit(proc, ir_make_instr_debug_declare(proc, di, expr, e, true, instr)); + } + return instr; } @@ -1186,7 +1226,7 @@ irValue *ir_add_local_for_identifier(irProcedure *proc, AstNode *name, bool zero if (found) { Entity *e = *found; ir_emit_comment(proc, e->token.string); - return ir_add_local(proc, e); + return ir_add_local(proc, e, name); } return NULL; } @@ -1202,14 +1242,14 @@ irValue *ir_add_local_generated(irProcedure *proc, Type *type) { scope, empty_token, type, false); - return ir_add_local(proc, e); + return ir_add_local(proc, e, NULL); } -irValue *ir_add_param(irProcedure *proc, Entity *e) { +irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr) { irValue *v = ir_make_value_param(proc->module->allocator, proc, e); #if 1 - irValue *l = ir_add_local(proc, e); + irValue *l = ir_add_local(proc, e, expr); ir_emit_store(proc, l, v); #else @@ -1227,9 +1267,9 @@ irValue *ir_add_param(irProcedure *proc, Entity *e) { //////////////////////////////////////////////////////////////// irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { - if (!proc->module->generate_debug_info) { - return NULL; - } + // if (!proc->module->generate_debug_info) { + // return NULL; + // } GB_ASSERT(file != NULL); irDebugInfo *di = ir_alloc_debug_info(proc->module->allocator, irDebugInfo_File); @@ -1259,9 +1299,9 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *file) { - if (!proc->module->generate_debug_info) { - return NULL; - } + // if (!proc->module->generate_debug_info) { + // return NULL; + // } GB_ASSERT(entity != NULL); irDebugInfo *di = ir_alloc_debug_info(proc->module->allocator, irDebugInfo_Proc); @@ -1281,18 +1321,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na //////////////////////////////////////////////////////////////// -irValue *ir_emit(irProcedure *proc, irValue *instr) { - GB_ASSERT(instr->kind == irValue_Instr); - irBlock *b = proc->curr_block; - instr->Instr.parent = b; - if (b != NULL) { - irInstr *i = ir_get_last_instr(b); - if (!ir_is_instr_terminating(i)) { - array_add(&b->instrs, instr); - } - } - return instr; -} + irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) { #if 1 // NOTE(bill): Sanity check @@ -3215,7 +3244,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv 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); + irValue **args = gb_alloc_array(a, irValue *, 2); args[0] = ir_gen_map_header(proc, ptr, type); args[1] = capacity; return ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); @@ -3331,6 +3360,23 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5); } break; + case BuiltinProc_delete: { + ir_emit_comment(proc, str_lit("delete")); + irValue *map = ir_build_expr(proc, ce->args.e[0]); + irValue *key = ir_build_expr(proc, ce->args.e[1]); + Type *map_type = ir_type(map); + GB_ASSERT(is_type_dynamic_map(map_type)); + Type *key_type = base_type(map_type)->Map.key; + + irValue *addr = ir_address_from_load_or_generate_local(proc, map); + + gbAllocator a = proc->module->allocator; + irValue **args = gb_alloc_array(a, irValue *, 2); + args[0] = ir_gen_map_header(proc, addr, map_type); + args[1] = ir_gen_map_key(proc, key, key_type); + return ir_emit_global_call(proc, "__dynamic_map_delete", args, 2); + } break; + case BuiltinProc_assert: { ir_emit_comment(proc, str_lit("assert")); @@ -5357,7 +5403,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irValue *tag_var = NULL; if (tag_var_entity != NULL) { - tag_var = ir_add_local(proc, tag_var_entity); + tag_var = ir_add_local(proc, tag_var_entity, NULL); } else { tag_var = ir_add_local_generated(proc, tag_var_type); } @@ -5385,7 +5431,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irValue *tag_var = NULL; if (tag_var_entity != NULL) { - tag_var = ir_add_local(proc, tag_var_entity); + tag_var = ir_add_local(proc, tag_var_entity, NULL); } else { tag_var = ir_add_local_generated(proc, tag_var_type); } @@ -5558,12 +5604,26 @@ void ir_begin_procedure_body(irProcedure *proc) { ir_start_block(proc, proc->entry_block); if (proc->type->Proc.params != NULL) { + ast_node(pt, ProcType, proc->type_expr); + isize param_index = 0; + isize q_index = 0; + TypeTuple *params = &proc->type->Proc.params->Tuple; for (isize i = 0; i < params->variable_count; i++) { + ast_node(fl, FieldList, pt->params); + GB_ASSERT(fl->list.count > 0); + GB_ASSERT(fl->list.e[0]->kind == AstNode_Field); + if (q_index == fl->list.e[param_index]->Field.names.count) { + q_index = 0; + param_index++; + } + ast_node(field, Field, fl->list.e[param_index]); + AstNode *name = field->names.e[q_index++]; + Entity *e = params->variables[i]; if (!str_eq(e->token.string, str_lit("")) && !str_eq(e->token.string, str_lit("_"))) { - irValue *param = ir_add_param(proc, e); + irValue *param = ir_add_param(proc, e, name); array_add(&proc->params, param); } } @@ -5790,7 +5850,7 @@ bool ir_gen_init(irGen *s, Checker *c) { } ir_init_module(&s->module, c); - s->module.generate_debug_info = false; + // s->module.generate_debug_info = false; // TODO(bill): generate appropriate output name int pos = cast(int)string_extension_position(c->parser->init_fullpath); @@ -6025,7 +6085,9 @@ void ir_gen_tree(irGen *s) { name = pd->link_name; } - irValue *p = ir_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name); + AstNode *type_expr = decl->proc_lit->ProcLit.type; + + irValue *p = ir_make_value_procedure(a, m, e, e->type, type_expr, body, name); p->Proc.tags = pd->tags; ir_module_add_value(m, e, p); @@ -6067,7 +6129,6 @@ void ir_gen_tree(irGen *s) { for_array(i, m->debug_info.entries) { MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i]; irDebugInfo *di = entry->value; - di->id = i; if (di->kind == irDebugInfo_Proc) { array_add(&all_procs->AllProcs.procs, di); } @@ -6406,10 +6467,11 @@ void ir_gen_tree(irGen *s) { case Type_Tuple: { ir_emit_comment(proc, str_lit("Type_Info_Tuple")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_tuple_ptr); + irValue *record = ir_emit_struct_ep(proc, tag, 0); { irValue *align = ir_make_const_int(a, type_align_of(a, t)); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align); } irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index); @@ -6429,14 +6491,15 @@ void ir_gen_tree(irGen *s) { } } - ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, ir_make_const_int(a, t->Record.field_count)); - ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count)); } break; case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: { ir_emit_comment(proc, str_lit("Type_Info_Struct")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr); + irValue *record = ir_emit_struct_ep(proc, tag, 0); { irValue *size = ir_make_const_int(a, type_size_of(a, t)); @@ -6444,11 +6507,11 @@ void ir_gen_tree(irGen *s) { 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, 3), size); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), packed); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), ordered); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), custom_align); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 5), packed); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 6), ordered); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 7), custom_align); } irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index); @@ -6475,28 +6538,52 @@ void ir_gen_tree(irGen *s) { ir_emit_store(proc, offset, ir_make_const_int(a, foffset)); } - ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, ir_make_const_int(a, t->Record.field_count)); - ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, ir_make_const_int(a, t->Record.field_count)); - ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count)); } break; - case TypeRecord_Union: + case TypeRecord_Union: { ir_emit_comment(proc, str_lit("Type_Info_Union")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr); + irValue *record = ir_emit_struct_ep(proc, tag, 0); { irValue *size = ir_make_const_int(a, type_size_of(a, t)); irValue *align = ir_make_const_int(a, type_align_of(a, t)); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align); } - break; + + irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index); + irValue *memory_names = ir_type_info_member_offset(proc, type_info_member_names, t->Record.field_count, &type_info_member_names_index); + + for (isize source_index = 1; source_index < t->Record.field_count; source_index++) { + // TODO(bill): Order fields in source order not layout order + Entity *f = t->Record.fields[source_index]; + irValue *tip = ir_get_type_info_ptr(proc, type_info_data, f->type); + irValue *index = ir_make_const_int(a, source_index); + irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); + + ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); + if (f->token.string.len > 0) { + irValue *name = ir_emit_ptr_offset(proc, memory_names, index); + ir_emit_store(proc, name, ir_make_const_string(a, f->token.string)); + } + } + + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count)); + + } break; case TypeRecord_RawUnion: { ir_emit_comment(proc, str_lit("Type_Info_RawUnion")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_raw_union_ptr); + irValue *record = ir_emit_struct_ep(proc, tag, 0); + { irValue *size = ir_make_const_int(a, type_size_of(a, t)); irValue *align = ir_make_const_int(a, type_align_of(a, t)); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align); } irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index); @@ -6516,9 +6603,9 @@ void ir_gen_tree(irGen *s) { } } - ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, ir_make_const_int(a, t->Record.field_count)); - ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, ir_make_const_int(a, t->Record.field_count)); - ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count)); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count)); } break; case TypeRecord_Enum: ir_emit_comment(proc, str_lit("Type_Info_Enum")); @@ -6607,7 +6694,7 @@ void ir_gen_tree(irGen *s) { break; } } - GB_ASSERT(found); + GB_ASSERT_MSG(found, "%s", type_to_string(tag_type)); } } } @@ -6619,6 +6706,13 @@ void ir_gen_tree(irGen *s) { ir_build_proc(m->procs_to_generate.e[i], m->procs_to_generate.e[i]->Proc.parent); } + // Number debug info + for_array(i, m->debug_info.entries) { + MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i]; + irDebugInfo *di = entry->value; + di->id = i; + } + // m->layout = str_lit("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"); } diff --git a/src/ir_print.c b/src/ir_print.c index e1b29a847..a35c4eb36 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -1254,6 +1254,29 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_fprintf(f, ")\n"); } break; + case irInstr_DebugDeclare: { + /* irInstrDebugDeclare *dd = &instr->DebugDeclare; + Type *vt = ir_type(dd->value); + irDebugInfo *di = dd->debug_info; + Entity *e = dd->entity; + String name = e->token.string; + TokenPos pos = e->token.pos; + // gb_printf("debug_declare %.*s\n", LIT(dd->entity->token.string)); + ir_fprintf(f, "call void @llvm.dbg.declare("); + ir_fprintf(f, "metadata "); + ir_print_type(f, m, vt); + ir_fprintf(f, " "); + ir_print_value(f, m, dd->value, vt); + ir_fprintf(f, ", metadata !DILocalVariable(name: \""); + ir_print_escape_string(f, name, false); + ir_fprintf(f, "\", scope: !%d, line: %td)", di->id, pos.line); + ir_fprintf(f, ", metadata !DIExpression()"); + ir_fprintf(f, ")"); + ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id); + + ir_fprintf(f, "\n"); */ + } break; + default: { GB_PANIC("<unknown instr> %d\n", instr->kind); @@ -1326,11 +1349,14 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { } - if (proc->module->generate_debug_info && proc->entity != NULL) { + if (proc->entity != NULL) { if (proc->body != NULL) { - irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity)); - GB_ASSERT(di->kind == irDebugInfo_Proc); - ir_fprintf(f, "!dbg !%d ", di->id); + irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity)); + if (di_ != NULL) { + irDebugInfo *di = *di_; + GB_ASSERT(di->kind == irDebugInfo_Proc); + // ir_fprintf(f, "!dbg !%d ", di->id); + } } } @@ -1396,6 +1422,8 @@ void print_llvm_ir(irGen *ir) { ir_print_type(f, m, t_rawptr); ir_fprintf(f, "} ; Basic_any\n"); + ir_fprintf(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n"); + for_array(member_index, m->members.entries) { MapIrValueEntry *entry = &m->members.entries.e[member_index]; @@ -1482,9 +1510,18 @@ void print_llvm_ir(irGen *ir) { #if 0 - if (m->generate_debug_info) { + // if (m->generate_debug_info) { + { ir_fprintf(f, "\n"); + + i32 diec = m->debug_info.entries.count; + ir_fprintf(f, "!llvm.dbg.cu = !{!0}\n"); + ir_fprintf(f, "!llvm.ident = !{!%d}\n", diec+3); + ir_fprintf(f, "!%d = !{i32 2, !\"Dwarf Version\", i32 4}\n", diec+0); + ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", diec+1); + ir_fprintf(f, "!%d = !{i32 1, !\"PIC Level\", i32 2}\n", diec+2); + ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3); for_array(di_index, m->debug_info.entries) { MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index]; @@ -1493,19 +1530,18 @@ void print_llvm_ir(irGen *ir) { switch (di->kind) { case irDebugInfo_CompileUnit: { - auto *cu = &di->CompileUnit; - irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(cu->file)); + irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file)); ir_fprintf(f, "distinct !DICompileUnit(" "language: DW_LANG_Go, " // Is this good enough? "file: !%d, " - "producer: \"%.*s\", " + "producer: \"clang version 3.9.0 (branches/release_39)\", " "flags: \"\", " "runtimeVersion: 0, " "isOptimized: false, " "emissionKind: FullDebug" ")", - file->id, LIT(cu->producer)); + file->id); } break; case irDebugInfo_File: diff --git a/src/main.c b/src/main.c index a8806aa4f..25ed2eb49 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ extern "C" { #endif + #include "common.c" #include "timings.c" #include "build_settings.c" @@ -223,10 +224,10 @@ int main(int argc, char **argv) { return 1; } - ssa_generate(&checker.info, &build_context); -#endif -#if 1 - + if (!ssa_generate(&checker.info)) { + return 1; + } +#else irGen ir_gen = {0}; if (!ir_gen_init(&ir_gen, &checker)) { return 1; diff --git a/src/parser.c b/src/parser.c index 52343b649..7c4814a68 100644 --- a/src/parser.c +++ b/src/parser.c @@ -302,16 +302,24 @@ AST_NODE_KIND(_DeclEnd, "", i32) \ AstNode * type; \ u32 flags; \ }) \ + AST_NODE_KIND(FieldList, "field list", struct { \ + Token token; \ + AstNodeArray list; \ + }) \ + AST_NODE_KIND(UnionField, "union field", struct { \ + AstNode *name; \ + AstNode *list; \ + }) \ AST_NODE_KIND(_TypeBegin, "", i32) \ AST_NODE_KIND(HelperType, "type", struct { \ Token token; \ AstNode *type; \ }) \ AST_NODE_KIND(ProcType, "procedure type", struct { \ - Token token; \ - AstNodeArray params; \ - AstNodeArray results; \ - u64 tags; \ + Token token; \ + AstNode *params; \ + AstNode *results; \ + u64 tags; \ ProcCallingConvention calling_convention; \ }) \ AST_NODE_KIND(PointerType, "pointer type", struct { \ @@ -478,11 +486,16 @@ Token ast_node_token(AstNode *node) { case AstNode_ImportDecl: return node->ImportDecl.token; case AstNode_ForeignLibrary: return node->ForeignLibrary.token; + case AstNode_Field: if (node->Field.names.count > 0) { return ast_node_token(node->Field.names.e[0]); } return ast_node_token(node->Field.type); + case AstNode_FieldList: + return node->FieldList.token; + case AstNode_UnionField: + return ast_node_token(node->UnionField.name); case AstNode_HelperType: return node->HelperType.token; case AstNode_ProcType: return node->ProcType.token; @@ -952,6 +965,19 @@ AstNode *ast_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) { return result; } +AstNode *ast_field_list(AstFile *f, Token token, AstNodeArray list) { + AstNode *result = make_ast_node(f, AstNode_FieldList); + result->FieldList.token = token; + result->FieldList.list = list; + return result; +} +AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) { + AstNode *result = make_ast_node(f, AstNode_UnionField); + result->UnionField.name = name; + result->UnionField.list = list; + return result; +} + AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) { AstNode *result = make_ast_node(f, AstNode_HelperType); @@ -961,7 +987,7 @@ AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) { } -AstNode *ast_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) { +AstNode *ast_proc_type(AstFile *f, Token token, AstNode *params, AstNode *results, u64 tags, ProcCallingConvention calling_convention) { AstNode *result = make_ast_node(f, AstNode_ProcType); result->ProcType.token = token; result->ProcType.params = params; @@ -1002,7 +1028,7 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem) } AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize field_count, - bool is_packed, bool is_ordered, AstNode *align) { + bool is_packed, bool is_ordered, AstNode *align) { AstNode *result = make_ast_node(f, AstNode_StructType); result->StructType.token = token; result->StructType.fields = fields; @@ -1308,7 +1334,6 @@ AstNode * parse_proc_type(AstFile *f, AstNode **foreign_library, String *fore AstNodeArray parse_stmt_list(AstFile *f); AstNode * parse_stmt(AstFile *f); AstNode * parse_body(AstFile *f); -void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results); @@ -1949,19 +1974,6 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) { } break; - case Token_Question: - if (!lhs && operand != NULL && f->expr_level >= 0) { - AstNode *cond = operand; - Token token_q = expect_token(f, Token_Question); - AstNode *x = parse_expr(f, false); - Token token_c = expect_token(f, Token_Colon); - AstNode *y = parse_expr(f, false); - operand = ast_ternary_expr(f, cond, x, y); - } else { - loop = false; - } - break; - default: loop = false; break; @@ -2016,22 +2028,24 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) { // NOTE(bill): result == priority i32 token_precedence(TokenKind t) { switch (t) { - case Token_CmpOr: + case Token_Question: return 1; - case Token_CmpAnd: + case Token_CmpOr: return 2; + case Token_CmpAnd: + return 3; case Token_CmpEq: case Token_NotEq: case Token_Lt: case Token_Gt: case Token_LtEq: case Token_GtEq: - return 3; + return 4; case Token_Add: case Token_Sub: case Token_Or: case Token_Xor: - return 4; + return 5; case Token_Mul: case Token_Quo: case Token_Mod: @@ -2039,51 +2053,42 @@ i32 token_precedence(TokenKind t) { case Token_AndNot: case Token_Shl: case Token_Shr: - return 5; - // case Token_as: - // case Token_transmute: - // case Token_down_cast: - // case Token_union_cast: - // return 6; + return 6; } return 0; } AstNode *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { - AstNode *expression = parse_unary_expr(f, lhs); + AstNode *expr = parse_unary_expr(f, lhs); for (i32 prec = token_precedence(f->curr_token.kind); prec >= prec_in; prec--) { for (;;) { - AstNode *right; Token op = f->curr_token; i32 op_prec = token_precedence(op.kind); if (op_prec != prec) { + // NOTE(bill): This will also catch operators that are not valid "binary" operators break; } expect_operator(f); // NOTE(bill): error checks too - if (lhs) { - // TODO(bill): error checking - lhs = false; - } - switch (op.kind) { - /* case Token_as: - case Token_transmute: - case Token_down_cast: - case Token_union_cast: - right = parse_type(f); - break; */ - - default: - right = parse_binary_expr(f, false, prec+1); + if (op.kind == Token_Question) { + AstNode *cond = expr; + // Token_Question + AstNode *x = parse_expr(f, lhs); + Token token_c = expect_token(f, Token_Colon); + AstNode *y = parse_expr(f, lhs); + expr = ast_ternary_expr(f, cond, x, y); + } else { + AstNode *right = parse_binary_expr(f, false, prec+1); if (!right) { - syntax_error(op, "Expected expression on the right hand side of the binary operator"); + syntax_error(op, "Expected expression on the right-hand side of the binary operator"); } - break; + expr = ast_binary_expr(f, op, expr, right); } - expression = ast_binary_expr(f, op, expression, right); + + lhs = false; } } - return expression; + return expr; } AstNode *parse_expr(AstFile *f, bool lhs) { @@ -2278,15 +2283,39 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) { return parse_body(f); } +AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow); + + +AstNode *parse_results(AstFile *f) { + if (!allow_token(f, Token_ArrowRight)) { + return NULL; + } + if (f->curr_token.kind != Token_OpenParen) { + Token begin_token = f->curr_token; + AstNodeArray empty_names = {0}; + AstNodeArray list = make_ast_node_array(f); + AstNode *type = parse_type(f); + array_add(&list, ast_field(f, empty_names, type, 0)); + return ast_field_list(f, begin_token, list); + } + AstNode *list = NULL; + expect_token(f, Token_OpenParen); + list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen); + expect_token_after(f, Token_CloseParen, "parameter list"); + return list; +} AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) { - AstNodeArray params = {0}; - AstNodeArray results = {0}; + AstNode *params = {0}; + AstNode *results = {0}; Token proc_token = expect_token(f, Token_proc); - parse_proc_signature(f, ¶ms, &results); + expect_token(f, Token_OpenParen); + params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen); + expect_token_after(f, Token_CloseParen, "parameter list"); + results = parse_results(f); u64 tags = 0; String foreign_name = {0}; @@ -2424,8 +2453,9 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i return idents; } -AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, - TokenKind separator, TokenKind follow) { +AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) { + Token start_token = f->curr_token; + AstNodeArray params = make_ast_node_array(f); AstNodeAndFlagsArray list = {0}; array_init(&list, heap_allocator()); // LEAK(bill): isize total_name_count = 0; @@ -2485,7 +2515,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, } if (name_count_) *name_count_ = total_name_count; - return params; + return ast_field_list(f, start_token, params); } for_array(i, list) { @@ -2503,11 +2533,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, } if (name_count_) *name_count_ = total_name_count; - return params; + return ast_field_list(f, start_token, params); } -AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) { +AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) { return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace); } @@ -2637,29 +2667,59 @@ AstNode *parse_type_or_ident(AstFile *f) { Token open = expect_token_after(f, Token_OpenBrace, "struct"); isize decl_count = 0; - AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct")); + AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct")); Token close = expect_token(f, Token_CloseBrace); + AstNodeArray decls = {0}; + if (fields != NULL) { + GB_ASSERT(fields->kind == AstNode_FieldList); + decls = fields->FieldList.list; + } + return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align); } break; case Token_union: { Token token = expect_token(f, Token_union); Token open = expect_token_after(f, Token_OpenBrace, "union"); - isize decl_count = 0; - AstNodeArray decls = parse_record_fields(f, &decl_count, 0, str_lit("union")); + AstNodeArray variants = make_ast_node_array(f); + + while (f->curr_token.kind != Token_CloseBrace && + f->curr_token.kind != Token_EOF) { + AstNode *name = parse_ident(f); + Token open = expect_token(f, Token_OpenBrace); + isize decl_count = 0; + AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union")); + Token close = expect_token(f, Token_CloseBrace); + + array_add(&variants, ast_union_field(f, name, list)); + + if (f->curr_token.kind != Token_Comma) { + break; + } + next_token(f); + } + + // AstNode *fields = parse_record_fields(f, &decl_count, 0, str_lit("union")); Token close = expect_token(f, Token_CloseBrace); - return ast_union_type(f, token, decls, decl_count); + + return ast_union_type(f, token, variants, variants.count); } case Token_raw_union: { Token token = expect_token(f, Token_raw_union); Token open = expect_token_after(f, Token_OpenBrace, "raw_union"); isize decl_count = 0; - AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union")); + AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union")); Token close = expect_token(f, Token_CloseBrace); + AstNodeArray decls = {0}; + if (fields != NULL) { + GB_ASSERT(fields->kind == AstNode_FieldList); + decls = fields->FieldList.list; + } + return ast_raw_union_type(f, token, decls, decl_count); } @@ -2699,39 +2759,6 @@ AstNode *parse_type_or_ident(AstFile *f) { } -AstNodeArray parse_results(AstFile *f) { - AstNodeArray results = make_ast_node_array(f); - if (allow_token(f, Token_ArrowRight)) { - if (f->curr_token.kind == Token_OpenParen) { - expect_token(f, Token_OpenParen); - while (f->curr_token.kind != Token_CloseParen && - f->curr_token.kind != Token_EOF) { - array_add(&results, parse_type(f)); - if (f->curr_token.kind != Token_Comma) { - break; - } - next_token(f); - } - expect_token(f, Token_CloseParen); - - return results; - } - - array_add(&results, parse_type(f)); - return results; - } - return results; -} - -void parse_proc_signature(AstFile *f, - AstNodeArray *params, - AstNodeArray *results) { - expect_token(f, Token_OpenParen); - *params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen); - expect_token_after(f, Token_CloseParen, "parameter list"); - *results = parse_results(f); -} - AstNode *parse_body(AstFile *f) { AstNodeArray stmts = {0}; Token open, close; @@ -2747,48 +2774,6 @@ AstNode *parse_body(AstFile *f) { return ast_block_stmt(f, stmts, open, close); } - -/* -AstNode *parse_proc_decl(AstFile *f) { - if (look_ahead_token_kind(f, 1) == Token_OpenParen) { - // NOTE(bill): It's an anonymous procedure - // NOTE(bill): This look-ahead technically makes the grammar LALR(2) - // but is that a problem in practice? - return ast_expr_stmt(f, parse_expr(f, true)); - } - - AstNodeArray params = {0}; - AstNodeArray results = {0}; - - Token proc_token = expect_token(f, Token_proc); - AstNode *name = parse_ident(f); - parse_proc_signature(f, ¶ms, &results); - - u64 tags = 0; - String foreign_name = {0}; - String link_name = {0}; - ProcCallingConvention cc = ProcCC_Odin; - - parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc); - - AstNode *proc_type = ast_proc_type(f, proc_token, params, results, tags, cc); - AstNode *body = NULL; - - if (f->curr_token.kind == Token_OpenBrace) { - if ((tags & ProcTag_foreign) != 0) { - syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body"); - } - AstNode *curr_proc = f->curr_proc; - f->curr_proc = proc_type; - body = parse_body(f); - f->curr_proc = curr_proc; - } else if ((tags & ProcTag_foreign) == 0) { - syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body"); - } - - return ast_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name); -} */ - AstNode *parse_if_stmt(AstFile *f) { if (f->curr_proc == NULL) { syntax_error(f->curr_token, "You cannot use an if statement in the file scope"); @@ -3458,8 +3443,18 @@ AstNode *parse_stmt(AstFile *f) { return s; } - expect_semicolon(f, s); - return ast_tag_stmt(f, hash_token, name, parse_stmt(f)); + + if (str_eq(tag, str_lit("include"))) { + syntax_error(token, "#include is not a valid import declaration kind. Use #load instead"); + s = ast_bad_stmt(f, token, f->curr_token); + } else { + syntax_error(token, "Unknown tag used: `%.*s`", LIT(tag)); + s = ast_bad_stmt(f, token, f->curr_token); + } + + fix_advance_to_next_stmt(f); + + return s; } break; case Token_OpenBrace: diff --git a/src/types.c b/src/types.c index 06a407576..72c9f19ce 100644 --- a/src/types.c +++ b/src/types.c @@ -888,7 +888,7 @@ bool are_types_identical(Type *x, Type *y) { case Type_Named: if (y->kind == Type_Named) { - return x->Named.base == y->Named.base; + return x->Named.type_name == y->Named.type_name; } break; @@ -923,7 +923,6 @@ bool are_types_identical(Type *x, Type *y) { break; } - return false; } @@ -1023,41 +1022,50 @@ typedef enum ProcTypeOverloadKind { ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { if (!is_type_proc(x)) return ProcOverload_NotProcedure; if (!is_type_proc(y)) return ProcOverload_NotProcedure; - TypeProc *px = &base_type(x)->Proc; - TypeProc *py = &base_type(y)->Proc; + TypeProc px = base_type(x)->Proc; + TypeProc py = base_type(y)->Proc; - if (px->calling_convention != py->calling_convention) { + if (px.calling_convention != py.calling_convention) { return ProcOverload_CallingConvention; } - if (px->param_count != py->param_count) { + if (px.param_count != py.param_count) { return ProcOverload_ParamCount; } - for (isize i = 0; i < px->param_count; i++) { - Entity *ex = px->params->Tuple.variables[i]; - Entity *ey = py->params->Tuple.variables[i]; + for (isize i = 0; i < px.param_count; i++) { + Entity *ex = px.params->Tuple.variables[i]; + Entity *ey = py.params->Tuple.variables[i]; if (!are_types_identical(ex->type, ey->type)) { return ProcOverload_ParamTypes; } } // IMPORTANT TODO(bill): Determine the rules for overloading procedures with variadic parameters - if (px->variadic != py->variadic) { + if (px.variadic != py.variadic) { return ProcOverload_ParamVariadic; } - if (px->result_count != py->result_count) { + if (px.result_count != py.result_count) { return ProcOverload_ResultCount; } - for (isize i = 0; i < px->result_count; i++) { - Entity *ex = px->results->Tuple.variables[i]; - Entity *ey = py->results->Tuple.variables[i]; + for (isize i = 0; i < px.result_count; i++) { + Entity *ex = px.results->Tuple.variables[i]; + Entity *ey = py.results->Tuple.variables[i]; if (!are_types_identical(ex->type, ey->type)) { return ProcOverload_ResultTypes; } } + { + Entity *ex = px.params->Tuple.variables[0]; + Entity *ey = py.params->Tuple.variables[0]; + bool ok = are_types_identical(ex->type, ey->type); + if (ok) { + gb_printf_err("Here\n"); + } + } + return ProcOverload_Identical; } |