From 23a0a6de4b78bc5447d70cebfd792319ea2b7059 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Fri, 14 Apr 2017 21:47:59 +0100 Subject: [PATCH] Add parse_int; Fix union bugs with size, alignment, and recursive definition checking --- core/strconv.odin | 46 ++++++++++++++++++++++++++++++++++++ src/check_expr.c | 4 ++++ src/ir.c | 55 +++++++++++++++++++++++-------------------- src/ir_print.c | 2 +- src/parser.c | 4 ++++ src/types.c | 59 +++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 135 insertions(+), 35 deletions(-) diff --git a/core/strconv.odin b/core/strconv.odin index e083bfd82..983c19403 100644 --- a/core/strconv.odin +++ b/core/strconv.odin @@ -18,6 +18,52 @@ parse_bool :: proc(s: string) -> (result: bool, ok: bool) { return false, false; } +_digit_value :: proc(r: rune) -> (int) { + ri := cast(int)r; + v: int = 16; + match { + case '0' <= r && r <= '9': + v = ri - '0'; + case 'a' <= r && r <= 'z': + v = ri - 'a' + 10; + case 'A' <= r && r <= 'Z': + v = ri - 'A' + 10; + } + return v; +} + +parse_i64 :: proc(s: string, base: int) -> i64 { + result: i64; + for r in s { + v := _digit_value(r); + if v >= base { + break; + } + result *= cast(i64)base; + result += cast(i64)v; + } + return result; +} +parse_u64 :: proc(s: string, base: int) -> u64 { + result: u64; + for r in s { + v := _digit_value(r); + if v >= base { + break; + } + result *= cast(u64)base; + result += cast(u64)v; + } + return result; +} +parse_int :: proc(s: string, base: int) -> int { + return cast(int)parse_i64(s, base); +} +parse_uint :: proc(s: string, base: int) -> uint { + return cast(uint)parse_u64(s, base); +} + + append_bool :: proc(buf: []byte, b: bool) -> string { s := b ? "true" : "false"; append(buf, ..cast([]byte)s); diff --git a/src/check_expr.c b/src/check_expr.c index 24ac6dfc1..5d711afdf 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -601,6 +601,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { union_type->Record.fields = fields; union_type->Record.field_count = field_count; + union_type->Record.are_offsets_set = false; + for_array(i, ut->variants) { AstNode *variant = ut->variants.e[i]; @@ -668,6 +670,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { add_entity_use(c, f->name, e); } + type_set_offsets(c->allocator, union_type); + gb_temp_arena_memory_end(tmp); union_type->Record.variants = variants; diff --git a/src/ir.c b/src/ir.c index c0f36b92c..e76503af2 100644 --- a/src/ir.c +++ b/src/ir.c @@ -886,7 +886,7 @@ irValue *ir_instr_union_tag_value(irProcedure *p, irValue *address) { irValue *v = ir_alloc_instr(p, irInstr_UnionTagValue); irInstr *i = &v->Instr; i->UnionTagValue.address = address; - i->UnionTagValue.type = t_int_ptr; + i->UnionTagValue.type = t_int; return v; } @@ -1986,6 +1986,27 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type)); } +irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) { + Type *t = ir_type(u); + GB_ASSERT_MSG(is_type_pointer(t) && + is_type_union(type_deref(t)), "%s", type_to_string(t)); + irValue *tag_ptr = ir_emit(proc, ir_instr_union_tag_ptr(proc, u)); + Type *tpt = ir_type(tag_ptr); + GB_ASSERT(is_type_pointer(tpt)); + tpt = base_type(type_deref(tpt)); + GB_ASSERT(tpt == t_int); + return tag_ptr; +} + +irValue *ir_emit_union_tag_value(irProcedure *proc, irValue *u) { + Type *t = ir_type(u); + GB_ASSERT(is_type_union(t)); + GB_ASSERT(are_types_identical(t, ir_type(u))); + return ir_emit(proc, ir_instr_union_tag_value(proc, u)); +} + +irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right); + irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue *x) { Type *t = ir_type(x); if (is_type_any(t)) { @@ -2034,6 +2055,9 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue } else if (op_kind == Token_NotEq) { return ir_emit_arith(proc, Token_And, a, b, t_bool); } + } else if (is_type_union(t)) { + irValue *tag = ir_emit_union_tag_value(proc, x); + return ir_emit_comp(proc, op_kind, tag, v_zero); } return NULL; } @@ -2108,25 +2132,6 @@ irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index) { return ir_emit_array_ep(proc, s, ir_const_i32(proc->module->allocator, index)); } -irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) { - Type *t = ir_type(u); - GB_ASSERT_MSG(is_type_pointer(t) && - is_type_union(type_deref(t)), "%s", type_to_string(t)); - irValue *tag_ptr = ir_emit(proc, ir_instr_union_tag_ptr(proc, u)); - Type *tpt = ir_type(tag_ptr); - GB_ASSERT(is_type_pointer(tpt)); - tpt = base_type(type_deref(tpt)); - GB_ASSERT(tpt == t_int); - return tag_ptr; -} - -irValue *ir_emit_union_tag_value(irProcedure *proc, irValue *u) { - Type *t = ir_type(u); - GB_ASSERT(is_type_union(t)); - GB_ASSERT(are_types_identical(t, ir_type(u))); - return ir_emit(proc, ir_instr_union_tag_value(proc, u)); -} - irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { @@ -2697,14 +2702,14 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { Entity *f = dst->Record.variants[i]; if (are_types_identical(f->type, src_type)) { ir_emit_comment(proc, str_lit("union - child to parent")); - gbAllocator allocator = proc->module->allocator; + gbAllocator a = proc->module->allocator; irValue *parent = ir_add_local_generated(proc, t); - irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent); - ir_emit_store(proc, tag_ptr, ir_const_int(allocator, i)); - - irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(allocator, src_type)); + irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(a, src_type)); ir_emit_store(proc, underlying, value); + irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent); + ir_emit_store(proc, tag_ptr, ir_const_int(a, i)); + return ir_emit_load(proc, parent); } } diff --git a/src/ir_print.c b/src/ir_print.c index 6bb20aaaf..2e3922b1c 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -231,7 +231,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { case TypeRecord_Union: { // NOTE(bill): The zero size array is used to fix the alignment used in a structure as // LLVM takes the first element's alignment as the entire alignment (like C) - i64 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size; + i64 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size; i64 align_of_union = type_align_of(heap_allocator(), t); ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits); } return; diff --git a/src/parser.c b/src/parser.c index e9c1a9a44..c3005ddb7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1197,7 +1197,11 @@ Token expect_token(AstFile *f, TokenKind kind) { syntax_error(f->curr_token, "Expected `%.*s`, got `%.*s`", LIT(token_strings[kind]), LIT(token_strings[prev.kind])); + if (prev.kind == Token_EOF) { + gb_exit(1); + } } + next_token(f); return prev; } diff --git a/src/types.c b/src/types.c index a12432747..02c01d4c9 100644 --- a/src/types.c +++ b/src/types.c @@ -402,6 +402,7 @@ void set_base_type(Type *t, Type *base) { Type *alloc_type(gbAllocator a, TypeKind kind) { Type *t = gb_alloc_item(a, Type); + gb_zero_item(t); t->kind = kind; return t; } @@ -837,6 +838,12 @@ bool type_has_nil(Type *t) { case Type_DynamicArray: case Type_Map: return true; + case Type_Record: + switch (t->Record.kind) { + case TypeRecord_Union: + return true; + } + return false; } return false; } @@ -1138,7 +1145,6 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { Entity *ey = py.params->Tuple.variables[0]; bool ok = are_types_identical(ex->type, ey->type); if (ok) { - gb_printf_err("Here\n"); } } @@ -1520,7 +1526,7 @@ void type_path_free(TypePath *tp) { TypePath *type_path_push(TypePath *tp, Type *t) { GB_ASSERT(tp != NULL); - for_array(i, tp->path) { + for (isize i = 0; i < tp->path.count; i++) { if (tp->path.e[i] == t) { // TODO(bill): GB_ASSERT(is_type_named(t)); @@ -1601,6 +1607,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { if (t->failure) { return FAILURE_ALIGNMENT; } + t = base_type(t); switch (t->kind) { @@ -1705,6 +1712,18 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { break; case TypeRecord_Union: { i64 max = 1; + if (t->Record.field_count > 0) { + Type *field_type = t->Record.fields[0]->type; + type_path_push(path, field_type); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 align = type_align_of_internal(allocator, field_type, path); + type_path_pop(path); + if (max < align) { + max = align; + } + } // NOTE(bill): field zero is null for (isize i = 1; i < t->Record.variant_count; i++) { Type *variant = t->Record.variants[i]->type; @@ -1795,8 +1814,18 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { if (t->failure) { return FAILURE_SIZE; } - t = base_type(t); + switch (t->kind) { + case Type_Named: { + type_path_push(path, t); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 size = type_size_of_internal(allocator, t->Named.base, path); + type_path_pop(path); + return size; + } break; + case Type_Basic: { GB_ASSERT(is_type_typed(t)); BasicKind kind = t->Basic.kind; @@ -1907,15 +1936,26 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { } break; case TypeRecord_Union: { - i64 count = t->Record.variant_count; i64 align = type_align_of_internal(allocator, t, path); if (path->failure) { return FAILURE_SIZE; } - i64 max = 0; // NOTE(bill): Zeroth field is invalid - for (isize i = 1; i < count; i++) { - i64 size = type_size_of_internal(allocator, t->Record.variants[i]->type, path); + type_set_offsets(allocator, t); + + i64 max = 0; + isize field_count = t->Record.field_count; + isize variant_count = t->Record.variant_count; + if (field_count > 0) { + Type *end_type = t->Record.fields[field_count-1]->type; + i64 end_offset = t->Record.offsets[field_count-1]; + i64 end_size = type_size_of_internal(allocator, end_type, path); + max = end_offset + end_size ; + } + + for (isize i = 1; i < variant_count; i++) { + Type *variant_type = t->Record.variants[i]->type; + i64 size = type_size_of_internal(allocator, variant_type, path); if (max < size) { max = size; } @@ -1923,7 +1963,8 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { // NOTE(bill): Align to int i64 size = align_formula(max, build_context.word_size); size += type_size_of_internal(allocator, t_int, path); - return align_formula(size, align); + size = align_formula(size, align); + return size; } break; case TypeRecord_RawUnion: { @@ -2111,7 +2152,7 @@ gbString write_type_to_string(gbString str, Type *type) { } str = gb_string_append_length(str, f->token.string.text, f->token.string.len); str = gb_string_appendc(str, ": "); - str = write_type_to_string(str, base_type(f->type)); + str = write_type_to_string(str, f->type); } for (isize i = 1; i < type->Record.variant_count; i++) { Entity *f = type->Record.variants[i];