From 593563d8eabf725ac851f4c3c72cd32b5a71aa7c Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 28 Aug 2016 01:06:42 +0100 Subject: [PATCH] new, new_slice, delete --- examples/demo.odin | 56 ++++++++++----- examples/file.odin | 8 +-- examples/game.odin | 2 +- examples/runtime.odin | 146 +++++++++++++++++++++++----------------- src/checker/checker.cpp | 49 ++++++++------ src/checker/expr.cpp | 136 ++++++++++++++++++++++++++++--------- src/checker/stmt.cpp | 4 +- src/codegen/ssa.cpp | 87 +++++++++++++++++++++++- 8 files changed, 348 insertions(+), 140 deletions(-) diff --git a/examples/demo.odin b/examples/demo.odin index 01c77a809..698e570cd 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -3,13 +3,36 @@ #load "game.odin" main :: proc() { - _ = hellope(); - procedures(); - variables(); - constants(); - types(); - data_control(); - using_fields(); + // _ = hellope(); + // variables(); + // procedures(); + // constants(); + // types(); + // data_control(); + // using_fields(); + + Entity :: type struct { + guid: u64; + name: string; + } + + Frog :: type struct { + using entity: Entity; + jump_height: f32; + } + + + e: Entity; + frog : Frog; + frog.name = "Ribbit"; + + a: [16]u32; + x := ^a[1]; + y := ^a[5]; + d := ptr_sub(y, ptr_offset(x, 1)); + print_int(d); nl(); + + // run_game(); } @@ -35,7 +58,7 @@ hellope :: proc() -> int { apple, banana, carrot: bool; box, carboard: bool = true, false; -// hellope_value: int = hellope(); // The procedure is ran just before `main` +hellope_value: int = hellope(); // The procedure is ran just before `main` variables :: proc() { i: int; // initialized with zero value @@ -176,7 +199,7 @@ constants :: proc() { DIFF :: (PI - CLOSE_TO_PI) / PI; // Evaluated at compile time - a := TAU; // the constant's value becomes typed as f32 + a := TAU; // the constant's value becomes typed as f64 b := CLOSE_TO_PI; // the constant's value becomes typed as int c := DIFF; } @@ -205,7 +228,6 @@ types :: proc() { - f32_array: [12]f32; // Array of 12 f32 f32_array[0] = 2; f32_array[1] = 3; @@ -219,7 +241,6 @@ types :: proc() { // mda[x][y][z] - api: [2]^f32; papi: ^[2]^f32; @@ -246,7 +267,6 @@ types :: proc() { - s := "Hellope World"; sub_string: string = s[5:10]; @@ -382,7 +402,7 @@ types :: proc() { } b: BitHack; b.f = 123; - print_int(b.i as int); print_nl(); + print_int_base(b.i as int, 16); print_nl(); @@ -623,14 +643,17 @@ data_control :: proc() { // handle error } defer close_file(^f); + + // Rest of code!!! } for i := 0; i < 100; i++ { - blah := alloc(100 * size_of(int)) as ^int; + blah := new(int); defer { defer print_string("!"); + defer print_int(i); defer print_string("dealloc"); - dealloc(blah); + delete(blah); } if i == 3 { @@ -704,7 +727,8 @@ using_fields :: proc() { name: string; } t: Entity; - t.pos = alloc(size_of(Vec2)) as ^Vec2; // TODO(bill): make an alloc type? i.e. new(Type)? + t.pos = new(Vec2); + defer delete(t.pos); t.x = 123; print_f32(t._xy.x); print_nl(); print_f32(t.pos.x); print_nl(); diff --git a/examples/file.odin b/examples/file.odin index f007b380a..3e827b3dd 100644 --- a/examples/file.odin +++ b/examples/file.odin @@ -75,8 +75,8 @@ read_entire_file :: proc(name: string) -> (string, bool) { return "", false; } - data: ^u8 = alloc(length as int); - if data == null { + data := new_slice(u8, length); + if ^data[0] == null { return "", false; } @@ -95,12 +95,12 @@ read_entire_file :: proc(name: string) -> (string, bool) { ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null); if single_read_length <= 0 { - dealloc(data); + delete(data); return "", false; } total_read += single_read_length as i64; } - return data[:length] as string, true; + return data as string, true; } diff --git a/examples/game.odin b/examples/game.odin index b4e97a2ce..6451bb8aa 100644 --- a/examples/game.odin +++ b/examples/game.odin @@ -28,7 +28,7 @@ win32_print_last_error :: proc() { to_c_string :: proc(s: string) -> ^u8 { c_str: ^u8 = alloc(len(s)+1); memory_copy(c_str, ^s[0], len(s)); - c_str[len(s)] = 0; + ptr_offset(c_str, len(s))^ = 0; return c_str; } diff --git a/examples/runtime.odin b/examples/runtime.odin index 3c2c5daf9..d6a6e354f 100644 --- a/examples/runtime.odin +++ b/examples/runtime.odin @@ -14,8 +14,10 @@ heap_free :: proc(ptr: rawptr) { memory_compare :: proc(dst, src: rawptr, len: int) -> int { s1, s2: ^u8 = dst, src; for i := 0; i < len; i++ { - if s1[i] != s2[i] { - return (s1[i] - s2[i]) as int; + a := ptr_offset(s1, i)^; + b := ptr_offset(s2, i)^; + if a != b { + return (a - b) as int; } } return 0; @@ -32,30 +34,30 @@ memory_copy :: proc(dst, src: rawptr, n: int) #inline { d, s: ^u8 = dst, src; for ; s as uint % 16 != 0 && n != 0; n-- { - d[0] = s[0]; - d, s = ^d[1], ^s[1]; + d^ = s^; + d, s = ptr_offset(d, 1), ptr_offset(s, 1); } if d as uint % 16 == 0 { - for ; n >= 16; d, s, n = ^d[16], ^s[16], n-16 { - (d as ^v128b)[0] = (s as ^v128b)[0]; + for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 { + (d as ^v128b)^ = (s as ^v128b)^; } if n&8 != 0 { - (d as ^u64)[0] = (s as ^u64)[0]; - d, s = ^d[8], ^s[8]; + (d as ^u64)^ = (s as ^u64)^; + d, s = ptr_offset(d, 8), ptr_offset(s, 8); } if n&4 != 0 { - (d as ^u32)[0] = (s as ^u32)[0]; - d, s = ^d[4], ^s[4]; + (d as ^u32)^ = (s as ^u32)^; + d, s = ptr_offset(d, 4), ptr_offset(s, 4); } if n&2 != 0 { - (d as ^u16)[0] = (s as ^u16)[0]; - d, s = ^d[2], ^s[2]; + (d as ^u16)^ = (s as ^u16)^; + d, s = ptr_offset(d, 2), ptr_offset(s, 2); } if n&1 != 0 { - d[0] = s[0]; - d, s = ^d[1], ^s[1]; + d^ = s^; + d, s = ptr_offset(d, 1), ptr_offset(s, 1); } return; } @@ -72,71 +74,86 @@ memory_copy :: proc(dst, src: rawptr, n: int) #inline { if d as uint % 4 == 1 { w = (s as ^u32)^; - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d, s, n = ^d[3], ^s[3], n-3; + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); + n -= 3; for n > 16 { d32 := d as ^u32; - x = (^s[1] as ^u32)^; d32[0] = LS(w, 24) | RS(x, 8); - w = (^s[5] as ^u32)^; d32[1] = LS(x, 24) | RS(w, 8); - x = (^s[9] as ^u32)^; d32[2] = LS(w, 24) | RS(x, 8); - w = (^s[13] as ^u32)^; d32[3] = LS(x, 24) | RS(w, 8); + s32 := ptr_offset(s, 1) as ^u32; + x = s32^; d32^ = LS(w, 24) | RS(x, 8); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + w = s32^; d32^ = LS(x, 24) | RS(w, 8); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + x = s32^; d32^ = LS(w, 24) | RS(x, 8); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + w = s32^; d32^ = LS(x, 24) | RS(w, 8); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - d, s, n = ^d[16], ^s[16], n-16; + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16; } } else if d as uint % 4 == 2 { w = (s as ^u32)^; - d[0] = s[0]; - d[1] = s[1]; - d, s, n = ^d[2], ^s[2], n-2; + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); + n -= 2 for n > 17 { d32 := d as ^u32; - x = (^s[2] as ^u32)^; d32[0] = LS(w, 16) | RS(x, 16); - w = (^s[6] as ^u32)^; d32[1] = LS(x, 16) | RS(w, 16); - x = (^s[10] as ^u32)^; d32[2] = LS(w, 16) | RS(x, 16); - w = (^s[14] as ^u32)^; d32[3] = LS(x, 16) | RS(w, 16); + s32 := ptr_offset(s, 2) as ^u32; + x = s32^; d32^ = LS(w, 16) | RS(x, 16); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + w = s32^; d32^ = LS(x, 16) | RS(w, 16); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + x = s32^; d32^ = LS(w, 16) | RS(x, 16); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + w = s32^; d32^ = LS(x, 16) | RS(w, 16); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - d, s, n = ^d[16], ^s[16], n-16; + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16; } } else if d as uint % 4 == 3 { w = (s as ^u32)^; - d[0] = s[0]; - d, s, n = ^d[1], ^s[1], n-1; + d^ = s^; + n -= 1; for n > 18 { d32 := d as ^u32; - x = (^s[3] as ^u32)^; d32[0] = LS(w, 8) | RS(x, 24); - w = (^s[7] as ^u32)^; d32[1] = LS(x, 8) | RS(w, 24); - x = (^s[11] as ^u32)^; d32[2] = LS(w, 8) | RS(x, 24); - w = (^s[15] as ^u32)^; d32[3] = LS(x, 8) | RS(w, 24); + s32 := ptr_offset(s, 3) as ^u32; + x = s32^; d32^ = LS(w, 8) | RS(x, 24); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + w = s32^; d32^ = LS(x, 8) | RS(w, 24); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + x = s32^; d32^ = LS(w, 8) | RS(x, 24); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + w = s32^; d32^ = LS(x, 8) | RS(w, 24); + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - d, s, n = ^d[16], ^s[16], n-16; + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16; } } if n&16 != 0 { - (d as ^v128b)[0] = (s as ^v128b)[0]; - d, s = ^d[16], ^s[16]; + (d as ^v128b)^ = (s as ^v128b)^; + d, s = ptr_offset(d, 16), ptr_offset(s, 16); } if n&8 != 0 { - (d as ^u64)[0] = (s as ^u64)[0]; - d, s = ^d[8], ^s[8]; + (d as ^u64)^ = (s as ^u64)^; + d, s = ptr_offset(d, 8), ptr_offset(s, 8); } if n&4 != 0 { - (d as ^u32)[0] = (s as ^u32)[0]; - d, s = ^d[4], ^s[4]; + (d as ^u32)^ = (s as ^u32)^; + d, s = ptr_offset(d, 4), ptr_offset(s, 4); } if n&2 != 0 { - (d as ^u16)[0] = (s as ^u16)[0]; - d, s = ^d[2], ^s[2]; + (d as ^u16)^ = (s as ^u16)^; + d, s = ptr_offset(d, 2), ptr_offset(s, 2); } if n&1 != 0 { - d[0] = s[0]; + d^ = s^; } } @@ -145,7 +162,7 @@ memory_move :: proc(dst, src: rawptr, n: int) #inline { if d == s { return; } - if d >= ^s[n] || ^d[n] <= s { + if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s { memory_copy(d, s, n); return; } @@ -158,43 +175,46 @@ memory_move :: proc(dst, src: rawptr, n: int) #inline { return; } n--; - d[0] = s[0]; - d, s = ^d[1], ^s[1]; + d^ = s^; + d, s = ptr_offset(d, 1), ptr_offset(s, 1); } di, si := d as ^int, s as ^int; for n >= size_of(int) { - di[0] = si[0]; - di, si = ^di[1], ^si[1]; + di^ = si^; + di, si = ptr_offset(di, 1), ptr_offset(si, 1); n -= size_of(int); } } for ; n > 0; n-- { - d[0] = s[0]; - d, s = ^d[1], ^s[1]; + d^ = s^; + d, s = ptr_offset(d, 1), ptr_offset(s, 1); } } else { if s as int % size_of(int) == d as int % size_of(int) { - for ^d[n] as int % size_of(int) != 0 { + for ptr_offset(d, n) as int % size_of(int) != 0 { if n == 0 { return; } n--; - d[0] = s[0]; - d, s = ^d[1], ^s[1]; + d^ = s^; + d, s = ptr_offset(d, 1), ptr_offset(s, 1); } for n >= size_of(int) { n -= size_of(int); - di, si := ^d[n] as ^int, ^s[n] as ^int; - di[0] = si[0]; + di := ptr_offset(d, n) as ^int; + si := ptr_offset(s, n) as ^int; + di^ = si^; } for ; n > 0; n-- { - d[0] = s[0]; - d, s = ^d[1], ^s[1]; + d^ = s^; + d, s = ptr_offset(d, 1), ptr_offset(s, 1); } } for n > 0 { n--; - d[n] = s[n]; + dn := ptr_offset(d, n); + sn := ptr_offset(s, n); + dn^ = sn^; } } } @@ -340,7 +360,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: if new_memory == null { return null; } - _ = copy((new_memory as ^u8)[:new_size], (old_memory as ^u8)[:old_size]); + _ = copy(slice_ptr(new_memory as ^u8, new_size), slice_ptr(old_memory as ^u8, old_size)); dealloc(old_memory); return new_memory; } diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 27d4d2c8a..5bb2e53bb 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -104,15 +104,18 @@ struct Scope { Map elements; // Key: String }; -enum ExpressionKind { - Expression_Expression, - Expression_Conversion, - Expression_Statement, +enum ExprKind { + Expr_Expr, + Expr_Stmt, }; enum BuiltinProcId { BuiltinProc_Invalid, + BuiltinProc_new, + BuiltinProc_new_slice, + BuiltinProc_delete, + BuiltinProc_size_of, BuiltinProc_size_of_val, BuiltinProc_align_of, @@ -138,29 +141,33 @@ struct BuiltinProc { String name; isize arg_count; b32 variadic; - ExpressionKind kind; + ExprKind kind; }; gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { - {STR_LIT(""), 0, false, Expression_Statement}, + {STR_LIT(""), 0, false, Expr_Stmt}, - {STR_LIT("size_of"), 1, false, Expression_Expression}, - {STR_LIT("size_of_val"), 1, false, Expression_Expression}, - {STR_LIT("align_of"), 1, false, Expression_Expression}, - {STR_LIT("align_of_val"), 1, false, Expression_Expression}, - {STR_LIT("offset_of"), 2, false, Expression_Expression}, - {STR_LIT("offset_of_val"), 1, false, Expression_Expression}, - {STR_LIT("static_assert"), 1, false, Expression_Statement}, + {STR_LIT("new"), 1, false, Expr_Expr}, + {STR_LIT("new_slice"), 2, true, Expr_Expr}, + {STR_LIT("delete"), 1, false, Expr_Stmt}, - {STR_LIT("len"), 1, false, Expression_Expression}, - {STR_LIT("cap"), 1, false, Expression_Expression}, - {STR_LIT("copy"), 2, false, Expression_Expression}, - {STR_LIT("append"), 2, false, Expression_Expression}, + {STR_LIT("size_of"), 1, false, Expr_Expr}, + {STR_LIT("size_of_val"), 1, false, Expr_Expr}, + {STR_LIT("align_of"), 1, false, Expr_Expr}, + {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("swizzle"), 1, true, Expression_Expression}, + {STR_LIT("len"), 1, false, Expr_Expr}, + {STR_LIT("cap"), 1, false, Expr_Expr}, + {STR_LIT("copy"), 2, false, Expr_Expr}, + {STR_LIT("append"), 2, false, Expr_Expr}, - {STR_LIT("ptr_offset"), 2, false, Expression_Expression}, - {STR_LIT("ptr_sub"), 2, false, Expression_Expression}, - {STR_LIT("slice_ptr"), 2, true, Expression_Expression}, + {STR_LIT("swizzle"), 1, true, Expr_Expr}, + + {STR_LIT("ptr_offset"), 2, false, Expr_Expr}, + {STR_LIT("ptr_sub"), 2, false, Expr_Expr}, + {STR_LIT("slice_ptr"), 2, true, Expr_Expr}, }; struct CheckerContext { diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 8cf42c022..2319131bc 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -1,16 +1,16 @@ -void check_expr (Checker *c, Operand *operand, AstNode *expression); -void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); -void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); -ExpressionKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL); -Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL); -void check_selector (Checker *c, Operand *operand, AstNode *node); -void check_not_tuple (Checker *c, Operand *operand); -b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); -void convert_to_typed (Checker *c, Operand *operand, Type *target_type); -gbString expr_to_string (AstNode *expression); -void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type, CycleChecker *cycle_checker = NULL); -void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); -void update_expr_type (Checker *c, AstNode *e, Type *type, b32 final); +void check_expr (Checker *c, Operand *operand, AstNode *expression); +void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); +void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); +ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL); +Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL); +void check_selector (Checker *c, Operand *operand, AstNode *node); +void check_not_tuple (Checker *c, Operand *operand); +b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); +void convert_to_typed (Checker *c, Operand *operand, Type *target_type); +gbString expr_to_string (AstNode *expression); +void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type, CycleChecker *cycle_checker = NULL); +void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); +void update_expr_type (Checker *c, AstNode *e, Type *type, b32 final); @@ -1691,6 +1691,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } switch (id) { + case BuiltinProc_new: + case BuiltinProc_new_slice: case BuiltinProc_size_of: case BuiltinProc_align_of: case BuiltinProc_offset_of: @@ -1701,8 +1703,80 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } switch (id) { + case BuiltinProc_new: { + // new :: proc(Type) -> ^Type + Type *type = check_type(c, ce->arg_list); + if (type == NULL || type == t_invalid) { + error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `size_of`"); + return false; + } + operand->mode = Addressing_Value; + operand->type = make_type_pointer(c->allocator, type); + } break; + case BuiltinProc_new_slice: { + // new_slice :: proc(Type, len: int[, cap: int]) -> []Type + Type *type = check_type(c, ce->arg_list); + if (type == NULL || type == t_invalid) { + error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `size_of`"); + return false; + } + + AstNode *len = ce->arg_list->next; + AstNode *cap = len->next; + + Operand op = {}; + check_expr(c, &op, len); + if (op.mode == Addressing_Invalid) + return false; + if (!is_type_integer(op.type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Length for `new_slice` must be an integer, got `%s`", + type_str); + return false; + } + + if (cap != NULL) { + check_expr(c, &op, len); + if (op.mode == Addressing_Invalid) + return false; + if (!is_type_integer(op.type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Capacity for `new_slice` must be an integer, got `%s`", + type_str); + return false; + } + if (cap->next != NULL) { + error(&c->error_collector, ast_node_token(call), + "Too many arguments to `new_slice`, expected either 2 or 3"); + return false; + } + } + + operand->mode = Addressing_Value; + operand->type = make_type_slice(c->allocator, type); + } break; + case BuiltinProc_delete: { + // delete :: proc(ptr: ^T) + Type *type = get_base_type(operand->type); + if (!is_type_pointer(type) && !is_type_slice(type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a pointer or slice to `delete`, got `%s`", + type_str); + return false; + } + + operand->mode = Addressing_Value; + operand->type = NULL; + } break; + case BuiltinProc_size_of: { - // size_of :: proc(Type) + // size_of :: proc(Type) -> int Type *type = check_type(c, ce->arg_list); if (!type) { error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `size_of`"); @@ -1716,7 +1790,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } break; case BuiltinProc_size_of_val: - // size_of_val :: proc(val) + // size_of_val :: proc(val: Type) -> int check_assignment(c, operand, NULL, make_string("argument of `size_of`")); if (operand->mode == Addressing_Invalid) return false; @@ -1727,7 +1801,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) break; case BuiltinProc_align_of: { - // align_of :: proc(Type) + // align_of :: proc(Type) -> int Type *type = check_type(c, ce->arg_list); if (!type) { error(&c->error_collector, ast_node_token(ce->arg_list), "Expected a type for `align_of`"); @@ -1739,7 +1813,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } break; case BuiltinProc_align_of_val: - // align_of_val :: proc(val) + // align_of_val :: proc(val: Type) -> int check_assignment(c, operand, NULL, make_string("argument of `align_of`")); if (operand->mode == Addressing_Invalid) return false; @@ -1750,7 +1824,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) break; case BuiltinProc_offset_of: { - // offset_val :: proc(Type, field) + // offset_val :: proc(Type, field) -> int Type *type = get_base_type(check_type(c, ce->arg_list)); AstNode *field_arg = unparen_expr(ce->arg_list->next); if (type) { @@ -1782,7 +1856,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } break; case BuiltinProc_offset_of_val: { - // offset_val :: proc(val) + // offset_val :: proc(val: expression) -> int AstNode *arg = unparen_expr(ce->arg_list); if (arg->kind != AstNode_SelectorExpr) { gbString str = expr_to_string(arg); @@ -2125,7 +2199,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); error(&c->error_collector, ast_node_token(call), - "Expected a pointer to `ptr_add`, got `%s`", + "Expected a pointer to `slice_ptr`, got `%s`", type_str); return false; } @@ -2135,7 +2209,10 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) "`rawptr` cannot have pointer arithmetic"); return false; } + AstNode *len = ce->arg_list->next; + AstNode *cap = len->next; + Operand op = {}; check_expr(c, &op, len); if (op.mode == Addressing_Invalid) @@ -2149,7 +2226,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; } - AstNode *cap = len->next; if (cap != NULL) { check_expr(c, &op, len); if (op.mode == Addressing_Invalid) @@ -2254,7 +2330,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode } -ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { +ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { GB_ASSERT(call->kind == AstNode_CallExpr); ast_node(ce, CallExpr, call); check_expr_or_type(c, operand, ce->proc); @@ -2264,7 +2340,7 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { check_expr_base(c, operand, arg); operand->mode = Addressing_Invalid; operand->expr = call; - return Expression_Statement; + return Expr_Stmt; } @@ -2286,7 +2362,7 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { operand->mode = Addressing_Invalid; operand->expr = call; - return Expression_Statement; + return Expr_Stmt; } check_call_arguments(c, operand, proc_type, call); @@ -2303,7 +2379,7 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { } operand->expr = call; - return Expression_Statement; + return Expr_Stmt; } void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) { @@ -2329,8 +2405,8 @@ void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) { } } -ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { - ExpressionKind kind = Expression_Statement; +ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { + ExprKind kind = Expr_Stmt; o->mode = Addressing_Invalid; o->type = t_invalid; @@ -2781,7 +2857,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ break; } - kind = Expression_Expression; + kind = Expr_Expr; o->expr = node; return kind; @@ -2791,8 +2867,8 @@ error: return kind; } -ExpressionKind check_expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { - ExpressionKind kind = check__expr_base(c, o, node, type_hint); +ExprKind check_expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { + ExprKind kind = check__expr_base(c, o, node, type_hint); Type *type = NULL; ExactValue value = {ExactValue_Invalid}; switch (o->mode) { diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 31a824f5a..9e54a73e3 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -445,13 +445,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(es, ExprStmt, node) Operand operand = {Addressing_Invalid}; - ExpressionKind kind = check_expr_base(c, &operand, es->expr); + ExprKind kind = check_expr_base(c, &operand, es->expr); switch (operand.mode) { case Addressing_Type: error(&c->error_collector, ast_node_token(node), "Is not an expression"); break; default: - if (kind == Expression_Statement) + if (kind == Expr_Stmt) return; error(&c->error_collector, ast_node_token(node), "Expression is not used"); break; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 181fb8d5b..d52aff90d 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -536,7 +536,7 @@ ssaValue *ssa_make_instr_extract_value(ssaProcedure *p, ssaValue *address, i32 i i->ExtractValue.result_type = result_type; Type *et = ssa_type(address); i->ExtractValue.elem_type = et; - GB_ASSERT(et->kind == Type_Struct || et->kind == Type_Array || et->kind == Type_Tuple); + // GB_ASSERT(et->kind == Type_Struct || et->kind == Type_Array || et->kind == Type_Tuple); return v; } @@ -1675,8 +1675,89 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue if (found && (*found)->kind == Entity_Builtin) { Entity *e = *found; switch (e->Builtin.id) { + case BuiltinProc_new: { + // new :: proc(Type) -> ^Type + gbAllocator allocator = proc->module->allocator; + + Type *type = type_of_expr(proc->module->info, ce->arg_list); + Type *ptr_type = make_type_pointer(allocator, type); + + 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 *v = ssa_emit_conv(proc, call, ptr_type); + return v; + } break; + + case BuiltinProc_new_slice: { + // new_slice :: proc(Type, len: int[, cap: int]) -> ^Type + gbAllocator allocator = proc->module->allocator; + + Type *type = type_of_expr(proc->module->info, ce->arg_list); + Type *ptr_type = make_type_pointer(allocator, type); + Type *slice_type = make_type_slice(allocator, type); + + 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)); + + AstNode *len_node = ce->arg_list->next; + AstNode *cap_node = len_node->next; + + ssaValue *len = ssa_build_expr(proc, len_node); + ssaValue *cap = len; + if (cap_node != NULL) { + cap = ssa_build_expr(proc, cap_node); + } + + Token mul = {Token_Mul}; + ssaValue *slice_size = ssa_emit_arith(proc, mul, elem_size, cap, t_int); + + ssaValue **args = gb_alloc_array(allocator, ssaValue *, 2); + args[0] = slice_size; + args[1] = elem_align; + + 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); + ssaValue *slice = ssa_add_local_generated(proc, slice_type); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_zero32, ptr_type), ptr); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_one32, t_int), len); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_two32, t_int), cap); + return ssa_emit_load(proc, slice); + } break; + + case BuiltinProc_delete: { + // delete :: proc(ptr: ^Type) + // delete :: proc(slice: []Type) + 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)); + etp = make_type_pointer(allocator, etp->Slice.elem); + value = ssa_emit(proc, ssa_make_instr_extract_value(proc, value, 0, etp)); + } + + ssaValue **args = gb_alloc_array(allocator, ssaValue *, 1); + args[0] = ssa_emit_conv(proc, value, t_rawptr); + + return ssa_emit(proc, ssa_make_instr_call(proc, dealloc_proc, args, 1, NULL)); + } break; + case BuiltinProc_len: { - // len :: proc(Type) -> int + // len :: proc(v: Type) -> int // NOTE(bill): len of an array is a constant expression ssaValue *v = ssa_build_addr(proc, ce->arg_list).addr; Type *t = get_base_type(ssa_type(v)); @@ -1686,7 +1767,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue return ssa_slice_len(proc, v); } break; case BuiltinProc_cap: { - // cap :: proc(Type) -> int + // cap :: proc(v: Type) -> int // NOTE(bill): cap of an array is a constant expression ssaValue *v = ssa_build_addr(proc, ce->arg_list).addr; Type *t = get_base_type(ssa_type(v));