diff --git a/code/demo.odin b/code/demo.odin index 29a96fbb9..9a4d522cc 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,5 +1,15 @@ #import "fmt.odin" main :: proc() { + Vec3 :: struct { + x, y: i16 + z: ?i32 + } + a := [..]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + offset: u8 = 2 + ptr := ^a[4] + + + fmt.println((ptr+offset) - ptr) } diff --git a/core/_preload.odin b/core/_preload.odin index e837aea63..586604b22 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -31,6 +31,7 @@ Type_Info :: union { Float: struct #ordered { size: int // in bytes } + Any: struct #ordered {} String: struct #ordered {} Boolean: struct #ordered {} Pointer: struct #ordered { @@ -142,7 +143,7 @@ __check_context :: proc() { c := ^__context if c.allocator.procedure == nil { - c.allocator = __default_allocator() + c.allocator = default_allocator() } if c.thread_id == 0 { c.thread_id = os.current_thread_id() @@ -173,6 +174,7 @@ free_all :: proc() #inline { resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) } resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline { + __check_context() a := context.allocator return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0) } @@ -204,16 +206,16 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: } -__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64) -> rawptr { +default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64) -> rawptr { using Allocator.Mode match mode { case ALLOC: total_size := size + alignment + size_of(mem.AllocationHeader) ptr := os.heap_alloc(total_size) header := ptr as ^mem.AllocationHeader - ptr = mem.align_forward(ptr_offset(header, 1), alignment) + ptr = mem.align_forward(header+1, alignment) mem.allocation_header_fill(header, ptr, size) return mem.zero(ptr, size) @@ -228,7 +230,7 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode, total_size := size + alignment + size_of(mem.AllocationHeader) ptr := os.heap_resize(mem.allocation_header(old_memory), total_size) header := ptr as ^mem.AllocationHeader - ptr = mem.align_forward(ptr_offset(header, 1), alignment) + ptr = mem.align_forward(header+1, alignment) mem.allocation_header_fill(header, ptr, size) return mem.zero(ptr, size) } @@ -236,9 +238,9 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode, return nil } -__default_allocator :: proc() -> Allocator { +default_allocator :: proc() -> Allocator { return Allocator{ - procedure = __default_allocator_proc, + procedure = default_allocator_proc, data = nil, } } diff --git a/core/fmt.odin b/core/fmt.odin index c0b68317b..c9c8d85e4 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -50,8 +50,7 @@ print_byte_buffer :: proc(buf: ^[]byte, b: []byte) { if buf.count < buf.capacity { n := min(buf.capacity-buf.count, b.count) if n > 0 { - offset := ptr_offset(buf.data, buf.count) - mem.copy(offset, ^b[0], n) + mem.copy(buf.data + buf.count, ^b[0], n) buf.count += n } } @@ -77,64 +76,8 @@ print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) { print_space_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune " ") } print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune "\n") } -print_int_to_buffer :: proc(buf: ^[]byte, i: int) { - print_int_base_to_buffer(buf, i, 10); -} - __NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" -print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) { - - buf: [65]byte - len := 0 - negative := false - if i < 0 { - negative = true - i = -i - } - if i == 0 { - buf[len] = #rune "0" - len++ - } - for i > 0 { - buf[len] = __NUM_TO_CHAR_TABLE[i % base] - len++ - i /= base - } - - if negative { - buf[len] = #rune "-" - len++ - } - - byte_reverse(buf[:len]) - print_string_to_buffer(buffer, buf[:len] as string) -} - -print_uint_to_buffer :: proc(buffer: ^[]byte, i: uint) { - print_uint_base_to_buffer(buffer, i, 10, 0, #rune " ") -} -print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int, pad_char: byte) { - buf: [65]byte - len := 0 - if i == 0 { - buf[len] = #rune "0" - len++ - } - for i > 0 { - buf[len] = __NUM_TO_CHAR_TABLE[i % base] - len++ - i /= base - } - for len < min_width { - buf[len] = pad_char - len++ - } - - byte_reverse(buf[:len]) - print_string_to_buffer(buffer, buf[:len] as string) -} - print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) { if b { print_string_to_buffer(buffer, "true") } else { print_string_to_buffer(buffer, "false") } @@ -142,7 +85,7 @@ print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) { print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { print_string_to_buffer(buffer, "0x") - print_uint_base_to_buffer(buffer, p as uint, 16, size_of(int), #rune "0") + print_u64_to_buffer(buffer, p as uint as u64) } print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) } @@ -215,7 +158,7 @@ print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) { } else { print_string_to_buffer(buf, "u") } - print_int_to_buffer(buf, 8*info.size) + print_u64_to_buffer(buf, 8*info.size as u64) } case Float: @@ -267,7 +210,7 @@ print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) { case Array: print_string_to_buffer(buf, "[") - print_int_to_buffer(buf, info.count) + print_i64_to_buffer(buf, info.count as i64) print_string_to_buffer(buf, "]") print_type_to_buffer(buf, info.elem) case Slice: @@ -276,7 +219,7 @@ print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) { print_type_to_buffer(buf, info.elem) case Vector: print_string_to_buffer(buf, "{") - print_int_to_buffer(buf, info.count) + print_i64_to_buffer(buf, info.count as i64) print_string_to_buffer(buf, "}") print_type_to_buffer(buf, info.elem) @@ -327,6 +270,13 @@ print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) { } +make_any :: proc(type_info: ^Type_Info, data: rawptr) -> any { + a: any + a.type_info = type_info + a.data = data + return a +} + print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { if arg.type_info == nil { print_string_to_buffer(buf, "") @@ -347,12 +297,11 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { if i > 0 { print_string_to_buffer(buf, ", ") } - print_any_to_buffer(buf, f.name) + print_string_to_buffer(buf, f.name) + // print_any_to_buffer(buf, f.offset) print_string_to_buffer(buf, " = ") - v: any - v.type_info = f.type_info - v.data = ptr_offset(arg.data as ^byte, f.offset) - print_any_to_buffer(buf, v) + data := arg.data as ^byte + f.offset + print_any_to_buffer(buf, make_any(f.type_info, data)) } print_string_to_buffer(buf, "}") @@ -421,10 +370,12 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { } case Maybe: - if arg.data != nil { - // TODO(bill): print maybe + size := mem.size_of_type_info(info.elem) + data := slice_ptr(arg.data as ^byte, size+1) + if data[size] != 0 && arg.data != nil { + print_any_to_buffer(buf, make_any(info.elem, arg.data)) } else { - print_string_to_buffer(buf, "") + print_string_to_buffer(buf, "nil") } case Enum: @@ -463,10 +414,8 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { print_string_to_buffer(buf, ", ") } - elem: any - elem.data = (arg.data as int + i*info.elem_size) as rawptr - elem.type_info = info.elem - print_any_to_buffer(buf, elem) + data := arg.data as ^byte + i*info.elem_size + print_any_to_buffer(buf, make_any(info.elem, data)) } case Slice: @@ -479,25 +428,35 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { print_string_to_buffer(buf, ", ") } - elem: any - elem.data = ptr_offset(slice.data, i*info.elem_size) - elem.type_info = info.elem - print_any_to_buffer(buf, elem) + data := slice.data + i*info.elem_size + print_any_to_buffer(buf, make_any(info.elem, data)) } case Vector: + is_bool :: proc(type_info: ^Type_Info) -> bool { + match type info : type_info { + case Named: + return is_bool(info.base) + case Boolean: + return true + } + return false + } + print_string_to_buffer(buf, "<") defer print_string_to_buffer(buf, ">") + if is_bool(info.elem) { + return + } + for i := 0; i < info.count; i++ { if i > 0 { print_string_to_buffer(buf, ", ") } - elem: any - elem.data = ptr_offset(arg.data as ^byte, i*info.elem_size) - elem.type_info = info.elem - print_any_to_buffer(buf, elem) + data := arg.data as ^byte + i*info.elem_size + print_any_to_buffer(buf, make_any(info.elem, data)) } @@ -510,12 +469,11 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { if i > 0 { print_string_to_buffer(buf, ", ") } - print_any_to_buffer(buf, info.fields[i].name) + print_string_to_buffer(buf, info.fields[i].name) print_string_to_buffer(buf, " = ") - a: any - a.data = ptr_offset(arg.data as ^byte, info.fields[i].offset) - a.type_info = info.fields[i].type_info - print_any_to_buffer(buf, a) + data := arg.data as ^byte + info.fields[i].offset + ti := info.fields[i].type_info + print_any_to_buffer(buf, make_any(ti, data)) } case Union: @@ -526,8 +484,6 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { print_type_to_buffer(buf, arg.type_info) print_string_to_buffer(buf, " @ 0x") print_pointer_to_buffer(buf, (arg.data as ^rawptr)^) - - default: } } diff --git a/core/mem.odin b/core/mem.odin index aa0025310..8a049daa9 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -93,18 +93,18 @@ AllocationHeader :: struct { } allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) { header.size = size - ptr := ptr_offset(header, 1) as ^int + ptr := (header+1) as ^int for i := 0; ptr as rawptr < data; i++ { - ptr_offset(ptr, i)^ = -1 + (ptr+i)^ = -1 } } allocation_header :: proc(data: rawptr) -> ^AllocationHeader { p := data as ^int - for ptr_offset(p, -1)^ == -1 { - p = ptr_offset(p, -1) + for (p-1)^ == -1 { + p = (p-1) } - return ptr_offset(p as ^AllocationHeader, -1) + return (p as ^AllocationHeader)-1 } @@ -207,3 +207,127 @@ end_temp_arena_memory :: proc(using tmp: Temp_Arena_Memory) { arena.memory.count = original_count arena.temp_count-- } + + + + + + + +align_of_type_info :: proc(type_info: ^Type_Info) -> int { + WORD_SIZE :: size_of(int) + using Type_Info + + match type info : type_info { + case Named: + return align_of_type_info(info.base) + case Integer: + return info.size + case Float: + return info.size + case String: + return WORD_SIZE + case Boolean: + return 1 + case Pointer: + return WORD_SIZE + case Maybe: + return align_of_type_info(info.elem) + case Procedure: + return WORD_SIZE + case Array: + return align_of_type_info(info.elem) + case Slice: + return WORD_SIZE + case Vector: + return align_of_type_info(info.elem) + case Struct: + return info.align + case Union: + return info.align + case Raw_Union: + return info.align + case Enum: + return align_of_type_info(info.base) + } + + return 0 +} + +align_formula :: proc(size, align: int) -> int { + result := size + align-1 + return result - result%align +} + +size_of_type_info :: proc(type_info: ^Type_Info) -> int { + WORD_SIZE :: size_of(int) + using Type_Info + + match type info : type_info { + case Named: + return size_of_type_info(info.base) + case Integer: + return info.size + case Float: + return info.size + case Any: + return 2*WORD_SIZE + case String: + return 2*WORD_SIZE + case Boolean: + return 1 + case Pointer: + return WORD_SIZE + case Maybe: + return size_of_type_info(info.elem) + 1 + case Procedure: + return WORD_SIZE + case Array: + count := info.count + if count == 0 { + return 0 + } + size := size_of_type_info(info.elem) + align := align_of_type_info(info.elem) + alignment := align_formula(size, align) + return alignment*(count-1) + size + case Slice: + return 3*WORD_SIZE + case Vector: + is_bool :: proc(type_info: ^Type_Info) -> bool { + match type info : type_info { + case Named: + return is_bool(info.base) + case Boolean: + return true + } + return false + } + + count := info.count + if count == 0 { + return 0 + } + bit_size := 8*size_of_type_info(info.elem) + if is_bool(info.elem) { + // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1` + // Silly LLVM spec + bit_size = 1 + } + total_size_in_bits := bit_size * count + total_size := (total_size_in_bits+7)/8 + return total_size + + case Struct: + return info.size + case Union: + return info.size + case Raw_Union: + return info.size + case Enum: + return size_of_type_info(info.base) + } + + return 0 +} + diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index a62d95042..f044b6f36 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -126,8 +126,8 @@ enum BuiltinProcId { BuiltinProc_swizzle, - BuiltinProc_ptr_offset, - BuiltinProc_ptr_sub, + // BuiltinProc_ptr_offset, + // BuiltinProc_ptr_sub, BuiltinProc_slice_ptr, BuiltinProc_min, @@ -170,8 +170,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {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("ptr_offset"), 2, false, Expr_Expr}, + // {STR_LIT("ptr_sub"), 2, false, Expr_Expr}, {STR_LIT("slice_ptr"), 2, true, Expr_Expr}, {STR_LIT("min"), 2, false, Expr_Expr}, @@ -757,6 +757,10 @@ void add_type_info_type(Checker *c, Type *t) { } } break; + case Type_Maybe: + add_type_info_type(c, bt->Maybe.elem); + break; + case Type_Pointer: add_type_info_type(c, bt->Pointer.elem); break; @@ -905,25 +909,26 @@ void init_preload_types(Checker *c) { t_type_info_member = record->other_fields[0]->type; t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member); - if (record->field_count != 17) { + if (record->field_count != 18) { compiler_error("Invalid `Type_Info` layout"); } t_type_info_named = record->fields[ 1]->type; t_type_info_integer = record->fields[ 2]->type; t_type_info_float = record->fields[ 3]->type; - t_type_info_string = record->fields[ 4]->type; - t_type_info_boolean = record->fields[ 5]->type; - t_type_info_pointer = record->fields[ 6]->type; - t_type_info_maybe = record->fields[ 7]->type; - t_type_info_procedure = record->fields[ 8]->type; - t_type_info_array = record->fields[ 9]->type; - t_type_info_slice = record->fields[10]->type; - t_type_info_vector = record->fields[11]->type; - t_type_info_tuple = record->fields[12]->type; - t_type_info_struct = record->fields[13]->type; - t_type_info_union = record->fields[14]->type; - t_type_info_raw_union = record->fields[15]->type; - t_type_info_enum = record->fields[16]->type; + t_type_info_any = record->fields[ 4]->type; + t_type_info_string = record->fields[ 5]->type; + t_type_info_boolean = record->fields[ 6]->type; + t_type_info_pointer = record->fields[ 7]->type; + t_type_info_maybe = record->fields[ 8]->type; + t_type_info_procedure = record->fields[ 9]->type; + t_type_info_array = record->fields[10]->type; + t_type_info_slice = record->fields[11]->type; + t_type_info_vector = record->fields[12]->type; + t_type_info_tuple = record->fields[13]->type; + t_type_info_struct = record->fields[14]->type; + t_type_info_union = record->fields[15]->type; + t_type_info_raw_union = record->fields[16]->type; + t_type_info_enum = record->fields[17]->type; } if (t_allocator == NULL) { diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index c0c2e3a18..44fe990f0 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -555,6 +555,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke struct_type->Record.fields = reordered_fields; } + + type_set_offsets(c->sizes, c->allocator, struct_type); } void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker *cycle_checker) { @@ -1232,13 +1234,27 @@ b32 check_binary_op(Checker *c, Operand *o, Token op) { // TODO(bill): Handle errors correctly Type *type = base_type(base_vector_type(o->type)); switch (op.kind) { - case Token_Add: case Token_Sub: + case Token_SubEq: + if (!is_type_numeric(type) && !is_type_pointer(type)) { + error(op, "Operator `%.*s` is only allowed with numeric or pointer expressions", LIT(op.string)); + return false; + } + if (is_type_pointer(type)) { + o->type = t_int; + } + if (base_type(type) == t_rawptr) { + gbString str = type_to_string(type); + defer (gb_string_free(str)); + error(ast_node_token(o->expr), "Invalid pointer type for pointer arithmetic: `%s`", str); + return false; + } + break; + + case Token_Add: case Token_Mul: case Token_Quo: - case Token_AddEq: - case Token_SubEq: case Token_MulEq: case Token_QuoEq: if (!is_type_numeric(type)) { @@ -1732,6 +1748,44 @@ String check_down_cast_name(Type *dst_, Type *src_) { return result; } +Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) { + GB_ASSERT(node->kind == AstNode_BinaryExpr); + ast_node(be, BinaryExpr, node); + GB_ASSERT(is_type_pointer(ptr->type)); + GB_ASSERT(is_type_integer(offset->type)); + GB_ASSERT(op == Token_Add || op == Token_Sub); + + Operand operand = {}; + operand.mode = Addressing_Value; + operand.type = ptr->type; + operand.expr = node; + + if (base_type(ptr->type) == t_rawptr) { + gbString str = type_to_string(ptr->type); + defer (gb_string_free(str)); + error(ast_node_token(node), "Invalid pointer type for pointer arithmetic: `%s`", str); + operand.mode = Addressing_Invalid; + return operand; + } + + + if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) { + i64 elem_size = type_size_of(c->sizes, c->allocator, ptr->type); + i64 ptr_val = ptr->value.value_pointer; + i64 offset_val = exact_value_to_integer(offset->value).value_integer; + i64 new_ptr_val = ptr_val; + if (op == Token_Add) { + new_ptr_val += elem_size*offset_val; + } else { + new_ptr_val -= elem_size*offset_val; + } + operand.mode = Addressing_Constant; + operand.value = make_exact_value_pointer(new_ptr_val); + } + + return operand; +} + void check_binary_expr(Checker *c, Operand *x, AstNode *node) { PROF_PROC(); @@ -1904,14 +1958,35 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { Token op = be->op; - if (token_is_shift(op)) { check_shift(c, x, y, node); return; } + if (op.kind == Token_Add || op.kind == Token_Sub) { + if (is_type_pointer(x->type) && is_type_integer(y->type)) { + *x = check_ptr_addition(c, op.kind, x, y, node); + return; + } else if (is_type_integer(x->type) && is_type_pointer(y->type)) { + if (op.kind == Token_Sub) { + gbString lhs = expr_to_string(x->expr); + gbString rhs = expr_to_string(y->expr); + defer (gb_string_free(lhs)); + defer (gb_string_free(rhs)); + error(ast_node_token(node), "Invalid pointer arithmetic, did you mean `%s %.*s %s`?", rhs, LIT(op.string), lhs); + x->mode = Addressing_Invalid; + return; + } + *x = check_ptr_addition(c, op.kind, y, x, node); + return; + } + } + + convert_to_typed(c, x, y->type); - if (x->mode == Addressing_Invalid) return; + if (x->mode == Addressing_Invalid) { + return; + } convert_to_typed(c, y, x->type); if (y->mode == Addressing_Invalid) { x->mode = Addressing_Invalid; @@ -1952,12 +2027,14 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { b32 fail = false; switch (y->value.kind) { case ExactValue_Integer: - if (y->value.value_integer == 0) + if (y->value.value_integer == 0) { fail = true; + } break; case ExactValue_Float: - if (y->value.value_float == 0.0) + if (y->value.value_float == 0.0) { fail = true; + } break; } @@ -1975,6 +2052,14 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { ExactValue b = y->value; Type *type = base_type(x->type); + if (is_type_pointer(type)) { + GB_ASSERT(op.kind == Token_Sub); + i64 bytes = a.value_pointer - b.value_pointer; + i64 diff = bytes/type_size_of(c->sizes, c->allocator, type); + x->value = make_exact_value_pointer(diff); + return; + } + if (type->kind != Type_Basic) { gbString xt = type_to_string(x->type); defer (gb_string_free(xt)); @@ -2788,6 +2873,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->mode = Addressing_Value; } break; +#if 0 case BuiltinProc_ptr_offset: { // ptr_offset :: proc(ptr: ^T, offset: int) -> ^T // ^T cannot be rawptr @@ -2890,6 +2976,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->mode = Addressing_Value; } } break; +#endif case BuiltinProc_slice_ptr: { // slice_ptr :: proc(a: ^T, len: int[, cap: int]) -> []T diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index e4927345e..0b703edac 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -1007,14 +1007,16 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Operand operand = {Addressing_Invalid}; AstNode binary_expr = {AstNode_BinaryExpr}; ast_node(be, BinaryExpr, &binary_expr); - be->op = op; + be->op = op; + be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add)); // NOTE(bill): Only use the first one will be used be->left = as->lhs[0]; be->right = as->rhs[0]; check_binary_expr(c, &operand, &binary_expr); - if (operand.mode == Addressing_Invalid) + if (operand.mode == Addressing_Invalid) { return; + } // NOTE(bill): Only use the first one will be used check_assignment_variable(c, &operand, as->lhs[0]); } break; diff --git a/src/checker/type.cpp b/src/checker/type.cpp index bf8a0bd6b..e7122c072 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -367,6 +367,7 @@ gb_global Type *t_type_info_member_ptr = NULL; gb_global Type *t_type_info_named = NULL; gb_global Type *t_type_info_integer = NULL; gb_global Type *t_type_info_float = NULL; +gb_global Type *t_type_info_any = NULL; gb_global Type *t_type_info_string = NULL; gb_global Type *t_type_info_boolean = NULL; gb_global Type *t_type_info_pointer = NULL; @@ -380,7 +381,6 @@ gb_global Type *t_type_info_struct = NULL; gb_global Type *t_type_info_union = NULL; gb_global Type *t_type_info_raw_union = NULL; gb_global Type *t_type_info_enum = NULL; -gb_global Type *t_type_info_any = NULL; gb_global Type *t_allocator = NULL; gb_global Type *t_allocator_ptr = NULL; @@ -990,8 +990,11 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t); i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i64 index); i64 align_formula(i64 size, i64 align) { - i64 result = size + align-1; - return result - result%align; + if (align > 0) { + i64 result = size + align-1; + return result - result%align; + } + return size; } i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { @@ -1025,16 +1028,7 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: - if (!t->Record.struct_is_packed) { - i64 max = 1; - for (isize i = 0; i < t->Record.field_count; i++) { - i64 align = type_align_of(s, allocator, t->Record.fields[i]->type); - if (max < align) { - max = align; - } - } - return max; - } else if (t->Record.field_count > 0) { + if (t->Record.field_count > 0) { return type_align_of(s, allocator, t->Record.fields[0]->type); } break; @@ -1141,17 +1135,19 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { i64 total_size_in_bits = bit_size * count; i64 total_size = (total_size_in_bits+7)/8; return total_size; - - // i64 alignment = align_formula(size, align); - // return alignment*(count-1) + size; } break; case Type_Slice: // ptr + len + cap return 3 * s.word_size; - case Type_Maybe: // value + bool - return type_size_of(s, allocator, t->Maybe.elem) + type_size_of(s, allocator, t_bool); + case Type_Maybe: { // value + bool + Type *elem = t->Maybe.elem; + i64 align = type_align_of(s, allocator, elem); + i64 size = align_formula(type_size_of(s, allocator, elem), align); + size += type_size_of(s, allocator, t_bool); + return align_formula(size, align); + } case Type_Record: { switch (t->Record.kind) { @@ -1161,7 +1157,10 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { return 0; } type_set_offsets(s, allocator, t); - return t->Record.struct_offsets[count-1] + type_size_of(s, allocator, t->Record.fields[count-1]->type); + // TODO(bill): Is this how it should work? + i64 size = t->Record.struct_offsets[count-1] + type_size_of(s, allocator, t->Record.fields[count-1]->type); + i64 align = type_align_of(s, allocator, t); + return align_formula(size, align); } break; case TypeRecord_Union: { @@ -1174,7 +1173,10 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { max = size; } // NOTE(bill): Align to int - return align_formula(max, s.word_size) + type_size_of(s, allocator, t_int); + i64 align = type_align_of(s, allocator, t); + isize size = align_formula(max, s.word_size); + size += type_size_of(s, allocator, t_int); + return align_formula(size, align); } break; case TypeRecord_RawUnion: { @@ -1185,7 +1187,9 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { if (max < size) max = size; } - return max; + // TODO(bill): Is this how it should work? + i64 align = type_align_of(s, allocator, t); + return align_formula(max, align); } break; case TypeRecord_Enum: { diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 6ca29902a..7d84a6c7b 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -377,6 +377,10 @@ void ssa_gen_tree(ssaGen *s) { case Basic_string: tag = ssa_add_local_generated(proc, t_type_info_string); break; + + case Basic_any: + tag = ssa_add_local_generated(proc, t_type_info_any); + break; } break; @@ -445,13 +449,12 @@ void ssa_gen_tree(ssaGen *s) { ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index); type_set_offsets(m->sizes, a, t); // NOTE(bill): Just incase the offsets have not been set yet - for (isize i = 0; i < t->Record.field_count; i++) { + for (isize source_index = 0; source_index < t->Record.field_count; source_index++) { // TODO(bill): Order fields in source order not layout order - Entity *f = t->Record.fields_in_src_order[i]; + Entity *f = t->Record.fields_in_src_order[source_index]; ssaValue *tip = get_type_info_ptr(proc, type_info_data, f->type); i64 foffset = t->Record.struct_offsets[f->Variable.field_index]; GB_ASSERT(f->kind == Entity_Variable && f->Variable.field); - isize source_index = f->Variable.field_index; ssaValue *field = ssa_emit_ptr_offset(proc, memory, ssa_make_const_int(a, source_index)); ssaValue *name = ssa_emit_struct_gep(proc, field, v_zero32, t_string_ptr); diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index 427407570..1c2e0929d 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -268,6 +268,16 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Type *type); void ssa_print_compound_element(ssaFileBuffer *f, ssaModule *m, ExactValue v, Type *elem_type) { + ssa_print_type(f, m, elem_type); + ssa_fprintf(f, " "); + + if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) { + Type *t = base_type(elem_type)->Maybe.elem; + ssa_fprintf(f, "{"); + ssa_print_type(f, m, t); + ssa_fprintf(f, " "); + } + if (v.kind == ExactValue_Invalid) { ssa_fprintf(f, "zeroinitializer"); } else if (v.kind == ExactValue_String) { @@ -290,6 +300,13 @@ void ssa_print_compound_element(ssaFileBuffer *f, ssaModule *m, ExactValue v, Ty } else { ssa_print_exact_value(f, m, v, elem_type); } + + if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) { + ssa_fprintf(f, ", "); + ssa_print_type(f, m, t_bool); + ssa_fprintf(f, " "); + ssa_fprintf(f, "true}"); + } } void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Type *type) { @@ -367,9 +384,6 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ if (i > 0) { ssa_fprintf(f, ", "); } - ssa_print_type(f, m, elem_type); - ssa_fprintf(f, " "); - TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems[i]); GB_ASSERT(tav != NULL); ssa_print_compound_element(f, m, tav->value, elem_type); @@ -402,8 +416,6 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ if (i > 0) { ssa_fprintf(f, ", "); } - ssa_print_type(f, m, elem_type); - ssa_fprintf(f, " "); ssa_print_compound_element(f, m, tav->value, elem_type); } } else { @@ -411,9 +423,6 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ if (i > 0) { ssa_fprintf(f, ", "); } - ssa_print_type(f, m, elem_type); - ssa_fprintf(f, " "); - TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems[i]); GB_ASSERT(tav != NULL); ssa_print_compound_element(f, m, tav->value, elem_type); @@ -476,8 +485,6 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ } Type *elem_type = type->Record.fields[i]->type; - ssa_print_type(f, m, elem_type); - ssa_fprintf(f, " "); ssa_print_compound_element(f, m, values[i], elem_type); } diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 3b6f7d8b7..9a4508aa2 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -1462,8 +1462,47 @@ void ssa_pop_target_list(ssaProcedure *proc) { } +ssaValue *ssa_emit_ptr_offset(ssaProcedure *proc, ssaValue *ptr, ssaValue *offset) { + ssaValue *gep = NULL; + offset = ssa_emit_conv(proc, offset, t_int); + gep = ssa_make_instr_get_element_ptr(proc, ptr, offset, NULL, 1, false); + gep->Instr.GetElementPtr.result_type = ssa_type(ptr); + return ssa_emit(proc, gep); +} ssaValue *ssa_emit_arith(ssaProcedure *proc, TokenKind op, ssaValue *left, ssaValue *right, Type *type) { + Type *t_left = ssa_type(left); + Type *t_right = ssa_type(right); + + if (op == Token_Add) { + if (is_type_pointer(t_left)) { + ssaValue *ptr = ssa_emit_conv(proc, left, type); + ssaValue *offset = right; + return ssa_emit_ptr_offset(proc, ptr, offset); + } else if (is_type_pointer(ssa_type(right))) { + ssaValue *ptr = ssa_emit_conv(proc, right, type); + ssaValue *offset = left; + return ssa_emit_ptr_offset(proc, ptr, offset); + } + } else if (op == Token_Sub) { + if (is_type_pointer(t_left) && is_type_integer(t_right)) { + // ptr - int + ssaValue *ptr = ssa_emit_conv(proc, left, type); + ssaValue *offset = right; + return ssa_emit_ptr_offset(proc, ptr, offset); + } else if (is_type_pointer(t_left) && is_type_pointer(t_right)) { + GB_ASSERT(is_type_integer(type)); + Type *ptr_type = t_left; + ssaModule *m = proc->module; + ssaValue *x = ssa_emit_conv(proc, left, type); + ssaValue *y = ssa_emit_conv(proc, right, type); + ssaValue *diff = ssa_emit_arith(proc, op, x, y, type); + ssaValue *elem_size = ssa_make_const_int(m->allocator, type_size_of(m->sizes, m->allocator, ptr_type)); + return ssa_emit_arith(proc, Token_Quo, diff, elem_size, type); + } + } + + switch (op) { case Token_AndNot: { // NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1) @@ -1510,13 +1549,7 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, TokenKind op_kind, ssaValue *left, s return ssa_emit(proc, ssa_make_instr_binary_op(proc, op_kind, left, right, result)); } -ssaValue *ssa_emit_ptr_offset(ssaProcedure *proc, ssaValue *ptr, ssaValue *offset) { - ssaValue *gep = NULL; - offset = ssa_emit_conv(proc, offset, t_int); - gep = ssa_make_instr_get_element_ptr(proc, ptr, offset, NULL, 1, false); - gep->Instr.GetElementPtr.result_type = ssa_type(ptr); - return ssa_emit(proc, gep); -} + ssaValue *ssa_emit_zero_gep(ssaProcedure *proc, ssaValue *s) { ssaValue *gep = NULL; @@ -2824,6 +2857,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } break; +#if 0 case BuiltinProc_ptr_offset: { ssa_emit_comment(proc, make_string("ptr_offset")); ssaValue *ptr = ssa_build_expr(proc, ce->args[0]); @@ -2847,6 +2881,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue return v; } break; +#endif case BuiltinProc_slice_ptr: { ssa_emit_comment(proc, make_string("slice_ptr")); @@ -3440,7 +3475,13 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { void ssa_build_assign_op(ssaProcedure *proc, ssaAddr lhs, ssaValue *value, TokenKind op) { ssaValue *old_value = ssa_lvalue_load(proc, lhs); Type *type = ssa_type(old_value); - ssaValue *change = ssa_emit_conv(proc, value, type); + + ssaValue *change = value; + if (is_type_pointer(type) && is_type_integer(ssa_type(value))) { + change = ssa_emit_conv(proc, value, default_type(ssa_type(value))); + } else { + change = ssa_emit_conv(proc, value, type); + } ssaValue *new_value = ssa_emit_arith(proc, op, old_value, change, type); ssa_lvalue_store(proc, lhs, new_value); } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index c8c47ea60..c83dc2d75 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -91,9 +91,9 @@ ExactValue make_exact_value_float(f64 f) { return result; } -ExactValue make_exact_value_pointer(void *ptr) { +ExactValue make_exact_value_pointer(i64 ptr) { ExactValue result = {ExactValue_Pointer}; - result.value_pointer = cast(i64)cast(intptr)ptr; + result.value_pointer = ptr; return result; }