diff --git a/examples/demo.odin b/examples/demo.odin index 4d2344185..79cd9643b 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -3,17 +3,16 @@ #load "game.odin" main :: proc() { - print_int(min(1, 2)); nl() print_int(max(1, 2)); nl() print_int(abs(-1337)); nl() a, b, c := 1, 2, -1337 + print_int(min(a, b)); nl() print_int(max(a, b)); nl() print_int(abs(c) as int); nl() - nl() /* Vec3 :: type struct { x, y, z: f32 } diff --git a/examples/runtime.odin b/examples/runtime.odin index a512a9b8e..7a76a3bff 100644 --- a/examples/runtime.odin +++ b/examples/runtime.odin @@ -36,7 +36,7 @@ memory_copy :: proc(dst, src: rawptr, n: int) #inline { } v128b :: type {4}u32 - static_assert(align_of(v128b) == 16) + assert(align_of(v128b) == 16) d, s: ^byte = dst, src @@ -236,10 +236,6 @@ __string_eq :: proc(a, b: string) -> bool { return memory_compare(^a[0], ^b[0], len(a)) == 0 } -__string_ne :: proc(a, b : string) -> bool #inline { - return !__string_eq(a, b) -} - __string_cmp :: proc(a, b : string) -> int { min_len := len(a) if len(b) < min_len { @@ -263,6 +259,7 @@ __string_cmp :: proc(a, b : string) -> int { return 0 } +__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) } __string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 } __string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 } __string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 } @@ -291,9 +288,9 @@ Allocator :: type struct { Context :: type struct { - thread_id: i32 + thread_id: int - user_index: i32 + user_index: int user_data: rawptr allocator: Allocator @@ -350,11 +347,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: return null } - if new_size < old_size { - new_size = old_size - } - - if old_size == new_size { + if new_size == old_size { return old_memory } @@ -362,11 +355,8 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: if new_memory == null { return null } - min_size := old_size; - if min_size > new_size { - min_size = new_size; - } - memory_copy(new_memory, old_memory, min_size); + + memory_copy(new_memory, old_memory, min(old_size, new_size)); dealloc(old_memory) return new_memory } @@ -399,3 +389,10 @@ __default_allocator :: proc() -> Allocator { } } + + + +__assert :: proc(msg: string) { + file_write(file_get_standard(File_Standard.ERROR), msg as []byte) + debug_trap() +} diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 8dfce197c..50d122209 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -132,7 +132,7 @@ enum BuiltinProcId { BuiltinProc_align_of_val, BuiltinProc_offset_of, BuiltinProc_offset_of_val, - BuiltinProc_static_assert, + BuiltinProc_assert, BuiltinProc_len, BuiltinProc_cap, @@ -170,7 +170,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT("align_of_val"), 1, false, Expr_Expr}, {STR_LIT("offset_of"), 2, false, Expr_Expr}, {STR_LIT("offset_of_val"), 1, false, Expr_Expr}, - {STR_LIT("static_assert"), 1, false, Expr_Stmt}, + {STR_LIT("assert"), 1, false, Expr_Stmt}, {STR_LIT("len"), 1, false, Expr_Expr}, {STR_LIT("cap"), 1, false, Expr_Expr}, diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 36f3f50fc..ca3667108 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -123,6 +123,8 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n return; } + + if (type != NULL) { if (!check_is_assignable_to(c, operand, type, is_argument)) { gbString type_string = type_to_string(type); @@ -132,16 +134,23 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n defer (gb_string_free(op_type_string)); defer (gb_string_free(expr_str)); - - // TODO(bill): is this a good enough error message? - error(&c->error_collector, ast_node_token(operand->expr), - "Cannot assign value `%s` of type `%s` to `%s` in %.*s", - expr_str, - op_type_string, - type_string, - LIT(context_name)); - + if (operand->mode == Addressing_Builtin) { + // TODO(bill): is this a good enough error message? + error(&c->error_collector, ast_node_token(operand->expr), + "Cannot assign builtin procedure `%s` in %.*s", + expr_str, + LIT(context_name)); + } else { + // TODO(bill): is this a good enough error message? + error(&c->error_collector, ast_node_token(operand->expr), + "Cannot assign value `%s` of type `%s` to `%s` in %.*s", + expr_str, + op_type_string, + type_string, + LIT(context_name)); + } operand->mode = Addressing_Invalid; + return; } } } @@ -1987,24 +1996,27 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->type = t_int; } break; - case BuiltinProc_static_assert: - // static_assert :: proc(cond: bool) + case BuiltinProc_assert: + // assert :: proc(cond: bool) - if (operand->mode != Addressing_Constant || - !is_type_boolean(operand->type)) { + if (!is_type_boolean(operand->type)) { gbString str = expr_to_string(ce->arg_list); defer (gb_string_free(str)); error(&c->error_collector, ast_node_token(call), - "`%s` is not a constant boolean", str); + "`%s` is not a boolean", str); return false; } - if (!operand->value.value_bool) { + if (operand->mode == Addressing_Constant && + !operand->value.value_bool) { gbString str = expr_to_string(ce->arg_list); defer (gb_string_free(str)); error(&c->error_collector, ast_node_token(call), "Static assertion: `%s`", str); return true; } + if (operand->mode != Addressing_Constant) { + operand->mode = Addressing_NoValue; + } break; // TODO(bill): Should these be procedures and are their names appropriate? diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index ed8b340d8..3508321c7 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -203,6 +203,21 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex if (operand->mode == Addressing_Invalid || operand->type == t_invalid || e->type == t_invalid) { + + if (operand->mode == Addressing_Builtin) { + gbString expr_str = expr_to_string(operand->expr); + defer (gb_string_free(expr_str)); + + // TODO(bill): is this a good enough error message? + error(&c->error_collector, ast_node_token(operand->expr), + "Cannot assign builtin procedure `%s` in %.*s", + expr_str, + LIT(context_name)); + + operand->mode = Addressing_Invalid; + } + + if (e->type == NULL) e->type = t_invalid; return NULL; @@ -530,7 +545,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc -void check_var_decl(Checker *c, AstNode *node) { +void check_var_decl_node(Checker *c, AstNode *node) { ast_node(vd, VarDecl, node); isize entity_count = vd->name_count; isize entity_index = 0; @@ -1150,7 +1165,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { if (vd->name_count > 1 && vd->type != NULL) { error(&c->error_collector, us->token, "`using` can only be applied to one variable of the same type"); } - check_var_decl(c, us->node); + check_var_decl_node(c, us->node); for (AstNode *item = vd->name_list; item != NULL; item = item->next) { ast_node(i, Ident, item); @@ -1191,7 +1206,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(vd, VarDecl, node); - check_var_decl(c, node); + check_var_decl_node(c, node); case_end; case_ast_node(pd, ProcDecl, node); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 077a4f218..0616a9302 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -761,6 +761,20 @@ ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) { } +ssaValue *ssa_emit_call(ssaProcedure *p, ssaValue *value, ssaValue **args, isize arg_count) { + Type *pt = get_base_type(ssa_type(value)); + GB_ASSERT(pt->kind == Type_Proc); + Type *results = pt->Proc.results; + return ssa_emit(p, ssa_make_instr_call(p, value, args, arg_count, results)); +} + +ssaValue *ssa_emit_global_call(ssaProcedure *proc, char *name, ssaValue **args, isize arg_count) { + ssaValue **found = map_get(&proc->module->members, hash_string(make_string(name))); + GB_ASSERT_MSG(found != NULL, "%s", name); + ssaValue *gp = *found; + return ssa_emit_call(proc, gp, args, arg_count); +} + Type *ssa_type(ssaAddr lval) { if (lval.addr != NULL) { @@ -1558,8 +1572,6 @@ ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) { } - - ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) { switch (expr->kind) { case_ast_node(bl, BasicLit, expr); @@ -1826,14 +1838,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue i64 s = type_size_of(proc->module->sizes, allocator, type); i64 a = type_align_of(proc->module->sizes, allocator, type); - // TODO(bill): Make procedure for: ssa_get_global_procedure() - ssaValue *alloc_align_proc = *map_get(&proc->module->members, hash_string(make_string("alloc_align"))); ssaValue **args = gb_alloc_array(allocator, ssaValue *, 2); args[0] = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(s)); args[1] = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(a)); - - ssaValue *call = ssa_emit(proc, ssa_make_instr_call(proc, alloc_align_proc, args, 2, t_rawptr)); + ssaValue *call = ssa_emit_global_call(proc, "alloc_align", args, 2); ssaValue *v = ssa_emit_conv(proc, call, ptr_type); return v; } break; @@ -1848,7 +1857,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue i64 s = type_size_of(proc->module->sizes, allocator, type); i64 a = type_align_of(proc->module->sizes, allocator, type); - ssaValue *alloc_align_proc = *map_get(&proc->module->members, hash_string(make_string("alloc_align"))); ssaValue *elem_size = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(s)); ssaValue *elem_align = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(a)); @@ -1868,8 +1876,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssaValue **args = gb_alloc_array(allocator, ssaValue *, 2); args[0] = slice_size; args[1] = elem_align; + ssaValue *call = ssa_emit_global_call(proc, "alloc_align", args, 2); - ssaValue *call = ssa_emit(proc, ssa_make_instr_call(proc, alloc_align_proc, args, 2, t_rawptr)); ssaValue *ptr = ssa_emit_conv(proc, call, ptr_type, true); ssaValue *slice = ssa_add_local_generated(proc, slice_type); ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_zero32, ptr_type), ptr); @@ -1884,7 +1892,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue gbAllocator allocator = proc->module->allocator; ssaValue *value = ssa_build_expr(proc, ce->arg_list); - ssaValue *dealloc_proc = *map_get(&proc->module->members, hash_string(make_string("dealloc"))); if (is_type_slice(ssa_type(value))) { Type *etp = get_base_type(ssa_type(value)); @@ -1894,8 +1901,50 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssaValue **args = gb_alloc_array(allocator, ssaValue *, 1); args[0] = ssa_emit_conv(proc, value, t_rawptr, true); + return ssa_emit_global_call(proc, "dealloc", args, 1); + } break; - return ssa_emit(proc, ssa_make_instr_call(proc, dealloc_proc, args, 1, NULL)); + + case BuiltinProc_assert: { + ssaValue *cond = ssa_build_expr(proc, ce->arg_list); + GB_ASSERT(is_type_boolean(ssa_type(cond))); + + Token eq = {Token_CmpEq}; + cond = ssa_emit_comp(proc, eq, cond, v_false); + ssaBlock *err = ssa_add_block(proc, NULL, make_string("builtin.assert.err")); + ssaBlock *done = ssa__make_block(proc, NULL, make_string("builtin.assert.done")); + + ssa_emit_if(proc, cond, err, done); + proc->curr_block = err; + + Token token = ast_node_token(ce->arg_list); + TokenPos pos = token.pos; + gbString expr = expr_to_string(ce->arg_list); + defer (gb_string_free(expr)); + + isize err_len = pos.file.len + 1 + 10 + 1 + 10 + 1; + err_len += 20; + err_len += gb_string_length(expr); + err_len += 2; + // HACK(bill): memory leaks + u8 *err_str = gb_alloc_array(gb_heap_allocator(), u8, err_len); + isize len = gb_snprintf(cast(char *)err_str, err_len, + "%.*s(%td:%td) Runtime assertion: %s\n", + LIT(pos.file), pos.line, pos.column, expr); + + ssaValue *array = ssa_add_global_string_array(proc, make_exact_value_string(make_string(err_str, len-1))); + ssaValue *elem = ssa_array_elem(proc, array); + ssaValue *string = ssa_emit_load(proc, ssa_emit_string(proc, elem, ssa_array_len(proc, array))); + + ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 1); + args[0] = string; + ssa_emit_global_call(proc, "__assert", args, 1); + + ssa_emit_jump(proc, done); + gb_array_append(proc->blocks, done); + proc->curr_block = done; + + return NULL; } break; case BuiltinProc_len: { @@ -2132,8 +2181,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue args[i] = ssa_emit_conv(proc, args[i], pt->variables[i]->type, true); } - ssaValue *call = ssa_make_instr_call(proc, value, args, arg_count, type->results); - return ssa_emit(proc, call); + return ssa_emit_call(proc, value, args, arg_count); case_end; case_ast_node(se, SliceExpr, expr);