Compiler Internal Changes: TypeRecord_Union -> Type_Union

This commit is contained in:
Ginger Bill
2017-07-10 22:59:23 +01:00
parent d936ca1ea0
commit ba5050ac7c
8 changed files with 209 additions and 293 deletions
-5
View File
@@ -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;
}
+17 -21
View File
@@ -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;
+2 -2
View File
@@ -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;
+11 -14
View File
@@ -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");
+42 -76
View File
@@ -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);
+20 -23
View File
@@ -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;
+4 -3
View File
@@ -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;
}
+113 -149
View File
@@ -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++) {