From ba5050ac7c2eb116b8989b7d387e67eb79eec62a Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 10 Jul 2017 22:59:23 +0100 Subject: [PATCH] Compiler Internal Changes: TypeRecord_Union -> Type_Union --- src/check_decl.cpp | 5 - src/check_expr.cpp | 38 +++---- src/check_stmt.cpp | 4 +- src/checker.cpp | 25 ++--- src/ir.cpp | 118 ++++++++------------ src/ir_print.cpp | 43 ++++---- src/ssa.cpp | 7 +- src/types.cpp | 262 +++++++++++++++++++-------------------------- 8 files changed, 209 insertions(+), 293 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index ea457fcf3..1ce518318 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -53,11 +53,6 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex if (is_type_bit_field_value(t)) { t = default_bit_field_value_type(t); } - if (is_type_variant(t)) { - Type *st = base_type(t); - GB_ASSERT(st->Record.variant_parent != nullptr); - t = st->Record.variant_parent; - } GB_ASSERT(is_type_typed(t)); e->type = t; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2bfd25260..d135cf3dd 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -499,8 +499,8 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { #endif if (is_type_union(dst)) { - for (isize i = 0; i < dst->Record.variant_count; i++) { - Type *vt = dst->Record.variants[i]; + for (isize i = 0; i < dst->Union.variant_count; i++) { + Type *vt = dst->Union.variants[i]; if (are_types_identical(vt, s)) { return 1; } @@ -990,12 +990,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n array_init(&variants, c->allocator, variant_count); array_add(&variants, t_invalid); - union_type->Record.scope = c->context.scope; - union_type->Record.are_offsets_set = false; - union_type->Record.is_ordered = true; + union_type->Union.scope = c->context.scope; { Entity *__tag = make_entity_field(c->allocator, nullptr, make_token_ident(str_lit("__tag")), t_int, false, -1); - union_type->Record.union__tag = __tag; + union_type->Union.union__tag = __tag; } for_array(i, ut->variants) { @@ -1016,11 +1014,8 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n } } - type_set_offsets(c->allocator, union_type); - - - union_type->Record.variants = variants.data; - union_type->Record.variant_count = variants.count; + union_type->Union.variants = variants.data; + union_type->Union.variant_count = variants.count; } void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { @@ -2549,7 +2544,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) check_open_scope(c, e); check_union_type(c, named_type, *type, e); check_close_scope(c); - (*type)->Record.node = e; + (*type)->Union.node = e; return true; case_end; @@ -6436,7 +6431,13 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t Type *t = base_type(type); switch (t->kind) { case Type_Record: { - if (!is_type_struct(t) && !is_type_union(t)) { + if (is_type_union(t)) { + is_constant = false; + } + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + if (!is_type_struct(t)) { if (cl->elems.count != 0) { gbString type_str = type_to_string(type); error(node, "Illegal compound literal type `%s`", type_str); @@ -6444,12 +6445,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } break; } - if (is_type_union(t)) { - is_constant = false; - } - if (cl->elems.count == 0) { - break; // NOTE(bill): No need to init - } + { // Checker values isize field_count = t->Record.field_count; if (cl->elems[0]->kind == AstNode_FieldValue) { @@ -6817,8 +6813,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t if (is_type_union(src)) { bool ok = false; - for (isize i = 1; i < bsrc->Record.variant_count; i++) { - Type *vt = bsrc->Record.variants[i]; + for (isize i = 1; i < bsrc->Union.variant_count; i++) { + Type *vt = bsrc->Union.variants[i]; if (are_types_identical(vt, dst)) { ok = true; break; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 2abc6c756..4d07ce1cf 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1473,8 +1473,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { if (match_type_kind == MatchType_Union) { GB_ASSERT(is_type_union(bt)); bool tag_type_found = false; - for (isize i = 0; i < bt->Record.variant_count; i++) { - Type *vt = bt->Record.variants[i]; + for (isize i = 0; i < bt->Union.variant_count; i++) { + Type *vt = bt->Union.variants[i]; if (are_types_identical(vt, y.type)) { tag_type_found = true; break; diff --git a/src/checker.cpp b/src/checker.cpp index cbb6afe0d..e47ad9aa2 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1152,20 +1152,17 @@ void add_type_info_type(Checker *c, Type *t) { add_type_info_type(c, bt->Enum.base_type); break; + case Type_Union: + add_type_info_type(c, t_int); + for (isize i = 0; i < bt->Union.variant_count; i++) { + add_type_info_type(c, bt->Union.variants[i]); + } + break; + case Type_Record: { - switch (bt->Record.kind) { - case TypeRecord_Union: - add_type_info_type(c, t_int); - for (isize i = 0; i < bt->Record.variant_count; i++) { - add_type_info_type(c, bt->Record.variants[i]); - } - /* fallthrough */ - default: - for (isize i = 0; i < bt->Record.field_count; i++) { - Entity *f = bt->Record.fields[i]; - add_type_info_type(c, f->type); - } - break; + for (isize i = 0; i < bt->Record.field_count; i++) { + Entity *f = bt->Record.fields[i]; + add_type_info_type(c, f->type); } } break; @@ -1343,7 +1340,7 @@ void init_preload(Checker *c) { Entity *type_info_variant = record->fields_in_src_order[2]; Type *tiv_type = type_info_variant->type; GB_ASSERT(is_type_union(tiv_type)); - TypeRecord *tiv = &tiv_type->Record; + TypeUnion *tiv = &tiv_type->Union; if (tiv->variant_count != 23) { compiler_error("Invalid `TypeInfo` layout"); diff --git a/src/ir.cpp b/src/ir.cpp index bdb9c7c1c..4ff15ca32 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2949,8 +2949,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { } if (is_type_union(dst)) { - for (isize i = 1; i < dst->Record.variant_count; i++) { - Type *vt = dst->Record.variants[i]; + for (isize i = 1; i < dst->Union.variant_count; i++) { + Type *vt = dst->Union.variants[i]; if (are_types_identical(vt, src_type)) { ir_emit_comment(proc, str_lit("union - child to parent")); gbAllocator a = proc->module->allocator; @@ -3290,8 +3290,8 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_)); irValue *dst_tag = nullptr; - for (isize i = 1; i < src->Record.variant_count; i++) { - Type *vt = src->Record.variants[i]; + for (isize i = 1; i < src->Union.variant_count; i++) { + Type *vt = src->Union.variants[i]; if (are_types_identical(vt, dst)) { dst_tag = ir_const_int(a, i); break; @@ -6825,9 +6825,9 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { Type *bt = type_deref(case_type); irValue *index = nullptr; Type *ut = base_type(type_deref(parent_type)); - GB_ASSERT(ut->Record.kind == TypeRecord_Union); - for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) { - Type *vt = ut->Record.variants[variant_index]; + GB_ASSERT(ut->kind == Type_Union); + for (isize variant_index = 1; variant_index < ut->Union.variant_count; variant_index++) { + Type *vt = ut->Union.variants[variant_index]; if (are_types_identical(vt, bt)) { index = ir_const_int(allocator, variant_index); break; @@ -7232,16 +7232,15 @@ void ir_init_module(irModule *m, Checker *c) { Type *t = cast(Type *)entry->key.ptr; switch (t->kind) { + case Type_Union: + count += t->Union.variant_count; + break; case Type_Record: switch (t->Record.kind) { case TypeRecord_Struct: case TypeRecord_RawUnion: count += t->Record.field_count; break; - case TypeRecord_Union: - count += t->Record.field_count; - count += t->Record.variant_count; - break; } break; case Type_Tuple: @@ -8044,6 +8043,36 @@ void ir_gen_tree(irGen *s) { } } break; + + case Type_Union: { + ir_emit_comment(proc, str_lit("TypeInfoUnion")); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_union_ptr); + + { + irValue *variant_names = ir_emit_struct_ep(proc, tag, 1); + irValue *variant_types = ir_emit_struct_ep(proc, tag, 2); + + isize variant_count = gb_max(0, t->Union.variant_count-1); + irValue *memory_names = ir_type_info_member_names_offset(proc, variant_count); + irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count); + + // NOTE(bill): Zeroth is nil so ignore it + for (isize variant_index = 0; variant_index < variant_count; variant_index++) { + Type *vt = t->Union.variants[variant_index+1]; // Skip zeroth + irValue *tip = ir_get_type_info_ptr(proc, vt); + + irValue *index = ir_const_int(a, variant_index); + irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); + ir_emit_store(proc, type_info, ir_type_info(proc, vt)); + } + + irValue *count = ir_const_int(a, variant_count); + ir_fill_slice(proc, variant_names, memory_names, count, count); + ir_fill_slice(proc, variant_types, memory_types, count, count); + } + + } break; + case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: { @@ -8092,69 +8121,6 @@ void ir_gen_tree(irGen *s) { ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count); ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, count, count); } break; - case TypeRecord_Union: { - ir_emit_comment(proc, str_lit("TypeInfoUnion")); - tag = ir_emit_conv(proc, variant_ptr, t_type_info_union_ptr); - - { - irValue *common_fields = ir_emit_struct_ep(proc, tag, 0); - - isize field_count = t->Record.field_count; - irValue *memory_types = ir_type_info_member_types_offset(proc, field_count); - irValue *memory_names = ir_type_info_member_names_offset(proc, field_count); - irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, field_count); - - type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet - for (isize field_index = 0; field_index < field_count; field_index++) { - // TODO(bill): Order fields in source order not layout order - Entity *f = t->Record.fields[field_index]; - irValue *tip = ir_get_type_info_ptr(proc, f->type); - i64 foffset = t->Record.offsets[f->Variable.field_index]; - GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); - - irValue *index = ir_const_int(a, field_index); - irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); - irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, 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_const_string(a, f->token.string)); - } - ir_emit_store(proc, offset, ir_const_int(a, foffset)); - } - - - irValue *count = ir_const_int(a, field_count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 0), memory_types, count, count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 1), memory_names, count, count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 2), memory_offsets, count, count); - } - - { - irValue *variant_names = ir_emit_struct_ep(proc, tag, 1); - irValue *variant_types = ir_emit_struct_ep(proc, tag, 2); - - isize variant_count = gb_max(0, t->Record.variant_count-1); - irValue *memory_names = ir_type_info_member_names_offset(proc, variant_count); - irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count); - - // NOTE(bill): Zeroth is nil so ignore it - for (isize variant_index = 0; variant_index < variant_count; variant_index++) { - Type *vt = t->Record.variants[variant_index+1]; // Skip zeroth - irValue *tip = ir_get_type_info_ptr(proc, vt); - - irValue *index = ir_const_int(a, variant_index); - irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); - ir_emit_store(proc, type_info, ir_type_info(proc, vt)); - } - - irValue *count = ir_const_int(a, variant_count); - ir_fill_slice(proc, variant_names, memory_names, count, count); - ir_fill_slice(proc, variant_types, memory_types, count, count); - } - - } break; case TypeRecord_RawUnion: { ir_emit_comment(proc, str_lit("TypeInfoRawUnion")); tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr); @@ -8250,8 +8216,8 @@ void ir_gen_tree(irGen *s) { Type *tiv = base_type(ti->Record.fields_in_src_order[2]->type); GB_ASSERT(is_type_union(tiv)); bool found = false; - for (isize i = 1; i < tiv->Record.variant_count; i++) { - Type *vt = tiv->Record.variants[i]; + for (isize i = 1; i < tiv->Union.variant_count; i++) { + Type *vt = tiv->Union.variants[i]; if (are_types_identical(vt, tag_type)) { found = true; irValue *tag_val = ir_const_int(a, i); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 2ffd23818..bad0e6eca 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -285,6 +285,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { ir_print_type(f, m, base_enum_type(t)); return; + case Type_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 align = type_align_of(heap_allocator(), t); + i64 total_size = type_size_of(heap_allocator(), t); + #if 1 + i64 block_size = t->Union.variant_block_size; + + ir_fprintf(f, "{[0 x <%lld x i8>], ", align); + ir_fprintf(f, "[%lld x i8], ", block_size); + ir_fprintf(f, "i%lld}", word_bits); + #else + i64 block_size = total_size - build_context.word_size; + ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align, block_size, word_bits); + #endif + } return; + case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: @@ -309,26 +326,6 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { ir_fprintf(f, ">"); } return; - 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 align = type_align_of(heap_allocator(), t); - i64 total_size = type_size_of(heap_allocator(), t); - #if 1 - i64 block_size = t->Record.variant_block_size; - - ir_fprintf(f, "{[0 x <%lld x i8>], ", align); - for (isize i = 0; i < t->Record.field_count; i++) { - ir_print_type(f, m, t->Record.fields[i]->type); - ir_fprintf(f, ", "); - } - ir_fprintf(f, "[%lld x i8], ", block_size); - ir_fprintf(f, "i%lld}", word_bits); - #else - i64 block_size = total_size - build_context.word_size; - ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align, block_size, word_bits); - #endif - } return; case TypeRecord_RawUnion: { // 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) @@ -974,7 +971,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_fprintf(f, " 0, "); ir_print_type(f, m, t_i32); #if 1 - ir_fprintf(f, " %d", 2 + t->Record.field_count); + ir_fprintf(f, " %d", 2); #else ir_fprintf(f, " %d", 2); #endif @@ -993,11 +990,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_print_value(f, m, instr->UnionTagValue.address, et); ir_fprintf(f, ","); #if 1 - ir_fprintf(f, " %d", 2 + t->Record.field_count); + ir_fprintf(f, " %d", 2); #else ir_fprintf(f, " %d", 2); #endif - ir_fprintf(f, ", %d", 2 + t->Record.field_count); + ir_fprintf(f, ", %d", 2); ir_fprintf(f, " ; UnionTagValue"); ir_fprintf(f, "\n"); } break; diff --git a/src/ssa.cpp b/src/ssa.cpp index 2f9588917..248999e39 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -648,10 +648,11 @@ bool can_ssa_type(Type *t) { } } return true; + case Type_Union: + return false; + case Type_Record: - if (t->Record.kind == TypeRecord_Union) { - return false; - } else if (t->Record.kind == TypeRecord_Struct) { + if (t->Record.kind == TypeRecord_Struct) { if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) { return false; } diff --git a/src/types.cpp b/src/types.cpp index 5613d556f..52a14e352 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -73,7 +73,7 @@ enum TypeRecordKind { TypeRecord_Struct, TypeRecord_RawUnion, - TypeRecord_Union, // Tagged + // TypeRecord_Union, // Tagged // TypeRecord_Enum, TypeRecord_Count, @@ -93,13 +93,13 @@ struct TypeRecord { Scope * scope; // Entity_TypeName - union - Type ** variants; - i32 variant_count; - Entity * union__tag; - i64 variant_block_size; // NOTE(bill): Internal use only + // Type ** variants; + // i32 variant_count; + // Entity * union__tag; + // i64 variant_block_size; // NOTE(bill): Internal use only - Type * variant_parent; - i32 variant_index; + // Type * variant_parent; + // i32 variant_index; i64 * offsets; bool are_offsets_set; @@ -137,6 +137,17 @@ struct TypeRecord { Entity * min_value; \ Entity * max_value; \ }) \ + TYPE_KIND(Union, struct { \ + Type ** variants; \ + i32 variant_count; \ + AstNode *node; \ + Scope * scope; \ + Entity * union__tag; \ + i64 variant_block_size; \ + Type * variant_parent; \ + i32 variant_index; \ + i64 custom_align; \ + }) \ TYPE_KIND(Named, struct { \ String name; \ Type * base; \ @@ -539,8 +550,7 @@ Type *make_type_struct(gbAllocator a) { } Type *make_type_union(gbAllocator a) { - Type *t = alloc_type(a, Type_Record); - t->Record.kind = TypeRecord_Union; + Type *t = alloc_type(a, Type_Union); return t; } @@ -867,14 +877,7 @@ bool is_type_struct(Type *t) { } bool is_type_union(Type *t) { t = base_type(t); - return (t->kind == Type_Record && t->Record.kind == TypeRecord_Union); -} -bool is_type_variant(Type *t) { - t = base_type(t); - if (t->kind == Type_Record) { - return t->Record.kind == TypeRecord_Struct && t->Record.variant_parent != nullptr; - } - return false; + return t->kind == Type_Union; } bool is_type_raw_union(Type *t) { @@ -1002,14 +1005,17 @@ bool is_type_polymorphic(Type *t) { } return false; } - case Type_Record: - for (isize i = 0; i < t->Record.field_count; i++) { - if (is_type_polymorphic(t->Record.fields[i]->type)) { + break; + case Type_Union: + for (isize i = 1; i < t->Union.variant_count; i++) { + if (is_type_polymorphic(t->Union.variants[i])) { return true; } } - for (isize i = 1; i < t->Record.variant_count; i++) { - if (is_type_polymorphic(t->Record.variants[i])) { + break; + case Type_Record: + for (isize i = 0; i < t->Record.field_count; i++) { + if (is_type_polymorphic(t->Record.fields[i]->type)) { return true; } } @@ -1052,11 +1058,9 @@ bool type_has_nil(Type *t) { case Type_DynamicArray: case Type_Map: return true; + case Type_Union: + return true; case Type_Record: - switch (t->Record.kind) { - case TypeRecord_Union: - return true; - } return false; } return false; @@ -1140,15 +1144,28 @@ bool are_types_identical(Type *x, Type *y) { case Type_Enum: return x == y; // NOTE(bill): All enums are unique + case Type_Union: + if (y->kind == Type_Union) { + if (x->Union.variant_count == y->Union.variant_count && + x->Union.custom_align == y->Union.custom_align) { + // NOTE(bill): zeroth variant is nullptr + for (isize i = 1; i < x->Union.variant_count; i++) { + if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) { + return false; + } + } + return true; + } + } + break; + case Type_Record: if (y->kind == Type_Record) { if (x->Record.kind == y->Record.kind) { switch (x->Record.kind) { case TypeRecord_Struct: case TypeRecord_RawUnion: - case TypeRecord_Union: if (x->Record.field_count == y->Record.field_count && - x->Record.variant_count == y->Record.variant_count && x->Record.is_packed == y->Record.is_packed && x->Record.is_ordered == y->Record.is_ordered && x->Record.custom_align == y->Record.custom_align) { @@ -1168,12 +1185,6 @@ bool are_types_identical(Type *x, Type *y) { return false; } } - // NOTE(bill): zeroth variant is nullptr - for (isize i = 1; i < x->Record.variant_count; i++) { - if (!are_types_identical(x->Record.variants[i], y->Record.variants[i])) { - return false; - } - } return true; } break; @@ -1597,6 +1608,14 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } } + } else if (type->Record.kind == Type_Union) { + if (field_name == "__tag") { + Entity *e = type->Union.union__tag; + GB_ASSERT(e != nullptr); + selection_add_index(&sel, -1); // HACK(bill): Leaky memory + sel.entity = e; + return sel; + } } else if (type->kind == Type_Record) { for (isize i = 0; i < type->Record.field_count; i++) { Entity *f = type->Record.fields[i]; @@ -1625,15 +1644,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.index.count = prev_count; } } - if (type->Record.kind == TypeRecord_Union) { - if (field_name == "__tag") { - Entity *e = type->Record.union__tag; - GB_ASSERT(e != nullptr); - selection_add_index(&sel, -1); // HACK(bill): Leaky memory - sel.entity = e; - return sel; - } - } } else if (type->kind == Type_BitField) { for (isize i = 0; i < type->BitField.field_count; i++) { Entity *f = type->BitField.fields[i]; @@ -1828,6 +1838,24 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { case Type_Enum: return type_align_of_internal(allocator, t->Enum.base_type, path); + case Type_Union: { + i64 max = build_context.word_size; + // NOTE(bill): field zero is null + for (isize i = 1; i < t->Union.variant_count; i++) { + Type *variant = t->Union.variants[i]; + type_path_push(path, variant); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 align = type_align_of_internal(allocator, variant, path); + type_path_pop(path); + if (max < align) { + max = align; + } + } + return max; + } break; + case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: @@ -1854,35 +1882,6 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { return max; } 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); - i64 align = type_align_of_internal(allocator, field_type, path); - if (path->failure) { - return FAILURE_ALIGNMENT; - } - 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_path_push(path, variant); - if (path->failure) { - return FAILURE_ALIGNMENT; - } - i64 align = type_align_of_internal(allocator, variant, path); - type_path_pop(path); - if (max < align) { - max = align; - } - } - return max; - } break; case TypeRecord_RawUnion: { i64 max = 1; for (isize i = 0; i < t->Record.field_count; i++) { @@ -1947,14 +1946,7 @@ bool type_set_offsets(gbAllocator allocator, Type *t) { t->Record.are_offsets_set = true; return true; } - } else if (is_type_union(t)) { - if (!t->Record.are_offsets_set) { - t->Record.are_offsets_being_processed = true; - t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, false); - t->Record.are_offsets_set = true; - return true; - } - } else if (is_type_tuple(t)) { + } else if (is_type_tuple(t)) { if (!t->Tuple.are_offsets_set) { t->Record.are_offsets_being_processed = true; t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false); @@ -2080,6 +2072,36 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { case Type_Enum: return type_size_of_internal(allocator, t->Enum.base_type, path); + case Type_Union: { + i64 align = type_align_of_internal(allocator, t, path); + if (path->failure) { + return FAILURE_SIZE; + } + + i64 max = 0; + isize variant_count = t->Union.variant_count; + + i64 field_size = max; + + for (isize i = 1; i < variant_count; i++) { + Type *variant_type = t->Union.variants[i]; + i64 size = type_size_of_internal(allocator, variant_type, path); + if (max < size) { + max = size; + } + } + + // NOTE(bill): Align to int + i64 size = align_formula(max, build_context.word_size); + // NOTE(bill): Calculate the padding between the common fields and the tag + t->Union.variant_block_size = size - field_size; + + size += type_size_of(allocator, t_int); + size = align_formula(size, align); + return size; + } break; + + case Type_Record: { switch (t->Record.kind) { @@ -2101,52 +2123,6 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { return align_formula(size, align); } break; - case TypeRecord_Union: { - i64 align = type_align_of_internal(allocator, t, path); - if (path->failure) { - return FAILURE_SIZE; - } - - i64 max = 0; - isize field_count = t->Record.field_count; - isize variant_count = t->Record.variant_count; - - // Check for recursive types - for (isize i = 0; i < field_count; i++) { - i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path); - if (path->failure) { - return FAILURE_SIZE; - } - } - // NOTE(bill): Zeroth field is invalid - type_set_offsets(allocator, t); - - 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 ; - } - i64 field_size = max; - - for (isize i = 1; i < variant_count; i++) { - Type *variant_type = t->Record.variants[i]; - i64 size = type_size_of_internal(allocator, variant_type, path); - if (max < size) { - max = size; - } - } - - // NOTE(bill): Align to int - i64 size = align_formula(max, build_context.word_size); - // NOTE(bill): Calculate the padding between the common fields and the tag - t->Record.variant_block_size = size - field_size; - - size += type_size_of(allocator, t_int); - size = align_formula(size, align); - return size; - } break; - case TypeRecord_RawUnion: { i64 count = t->Record.field_count; i64 align = type_align_of_internal(allocator, t, path); @@ -2185,7 +2161,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) { t = base_type(t); - if (t->kind == Type_Record && (t->Record.kind == TypeRecord_Struct || t->Record.kind == TypeRecord_Union)) { + if (t->kind == Type_Record && (t->Record.kind == TypeRecord_Struct)) { type_set_offsets(allocator, t); if (gb_is_between(index, 0, t->Record.field_count-1)) { return t->Record.offsets[index]; @@ -2342,6 +2318,16 @@ gbString write_type_to_string(gbString str, Type *type) { str = gb_string_appendc(str, "}"); break; + case Type_Union: + str = gb_string_appendc(str, "union{"); + for (isize i = 1; i < type->Union.variant_count; i++) { + Type *t = type->Union.variants[i]; + if (i > 1) str = gb_string_appendc(str, ", "); + str = write_type_to_string(str, t); + } + str = gb_string_appendc(str, "}"); + break; + case Type_Record: { switch (type->Record.kind) { case TypeRecord_Struct: @@ -2366,28 +2352,6 @@ gbString write_type_to_string(gbString str, Type *type) { str = gb_string_appendc(str, "}"); break; - case TypeRecord_Union: - str = gb_string_appendc(str, "union{"); - for (isize i = 0; i < type->Record.field_count; i++) { - Entity *f = type->Record.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) { - str = gb_string_appendc(str, ", "); - } - 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, f->type); - } - for (isize i = 1; i < type->Record.variant_count; i++) { - Type *t = type->Record.variants[i]; - if (i > 1 || type->Record.field_count > 1) { - str = gb_string_appendc(str, ", "); - } - str = write_type_to_string(str, t); - } - str = gb_string_appendc(str, "}"); - break; - case TypeRecord_RawUnion: str = gb_string_appendc(str, "raw_union{"); for (isize i = 0; i < type->Record.field_count; i++) {