Merge raw_union into struct as a memory layout tag #raw_union

This commit is contained in:
Ginger Bill
2017-07-18 19:24:45 +01:00
parent 65f079ebc4
commit 59fb7b020a
11 changed files with 242 additions and 294 deletions

View File

@@ -130,18 +130,16 @@ get_hash :: proc(s: string) -> u32 {
Vector :: struct(N: int, T: type) {
using _: raw_union {
using e: [N]T;
when 0 < N && N <= 4 {
using v: struct {
when N >= 1 do x: T;
when N >= 2 do y: T;
when N >= 3 do z: T;
when N >= 4 do w: T;
};
} };
Vector :: struct(N: int, T: type) #raw_union {
using e: [N]T;
when 0 < N && N <= 4 {
using v: struct {
when N >= 1 do x: T;
when N >= 2 do y: T;
when N >= 3 do z: T;
when N >= 4 do w: T;
};
}
}
Vector3 :: Vector(3, f32);
@@ -161,17 +159,17 @@ foo3 :: proc(a: type/Vector(3, $T)) { fmt.println("foo3", a{}); }
main :: proc() {
Foo :: struct {
a := 123;
b := true;
}
v1 := Foo{};
fmt.println(v1);
// Foo :: struct {
// a := 123;
// b := true;
// }
// v1 := Foo{};
// fmt.println(v1);
foo1(Vector(3, f32));
foo1(Vector3);
foo3(Vector(3, f32));
foo3(Vector3);
// foo1(Vector(3, f32));
// foo1(Vector3);
// foo3(Vector(3, f32));
// foo3(Vector3);
a, b: Vector3;
@@ -184,17 +182,18 @@ main :: proc() {
b.z = 5;
v := add(a, b);
fmt.println(v.v);
fmt.println(size_of(Vector3));
fmt.println(v.e, v.v);
table: Table(string, int);
// table: Table(string, int);
for i in 0..36 do put(&table, "Hellope", i);
for i in 0..42 do put(&table, "World!", i);
// for i in 0..36 do put(&table, "Hellope", i);
// for i in 0..42 do put(&table, "World!", i);
found, _ := find(&table, "Hellope");
fmt.printf("found is %v\n", found);
// found, _ := find(&table, "Hellope");
// fmt.printf("found is %v\n", found);
found, _ = find(&table, "World!");
fmt.printf("found is %v\n", found);
// found, _ = find(&table, "World!");
// fmt.printf("found is %v\n", found);
}

View File

@@ -38,7 +38,7 @@ CallingConvention :: enum {
// The compiler relies upon this _exact_ order
TypeInfo :: struct #ordered {
// Core Types
EnumValue :: raw_union {
EnumValue :: struct #raw_union {
f: f64;
i: i128;
}

View File

@@ -6,12 +6,12 @@ __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
when ODIN_ENDIAN == "bit" {
TWords :: raw_union {
TWords :: struct #raw_union {
all: u128;
using _: struct {lo, hi: u64;};
};
} else {
TWords :: raw_union {
TWords :: struct #raw_union {
all: u128;
using _: struct {hi, lo: u64;};
};
@@ -106,7 +106,7 @@ __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "
__f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
when true {
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
FP32 :: raw_union {u: u32, f: f32};
FP32 :: struct #raw_union {u: u32, f: f32};
magic, was_infnan: FP32;
magic.u = (254-15) << 23;
@@ -130,8 +130,8 @@ __f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee"
__f32_to_f16 :: proc(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
when false {
// Source: https://gist.github.com/rygorous/2156668
FP16 :: raw_union {u: u16, f: f16};
FP32 :: raw_union {u: u32, f: f32};
FP16 :: struct #raw_union {u: u16, f: f16};
FP32 :: struct #raw_union {u: u32, f: f32};
f32infty, f16infty, magic: FP32;
f32infty.u = 255<<23;

View File

@@ -1055,6 +1055,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
GB_ASSERT(is_type_struct(struct_type));
ast_node(st, StructType, node);
String context = str_lit("struct");
isize min_field_count = 0;
for_array(field_index, st->fields) {
AstNode *field = st->fields[field_index];
@@ -1066,6 +1068,11 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
}
struct_type->Record.names = make_names_field_for_record(c, c->context.scope);
if (st->is_raw_union) {
struct_type->Record.is_raw_union = true;
context = str_lit("struct #raw_union");
}
Type *polymorphic_params = nullptr;
bool is_polymorphic = false;
bool can_check_fields = true;
@@ -1218,7 +1225,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
Array<Entity *> fields = {};
if (!is_polymorphic) {
fields = check_fields(c, node, st->fields, min_field_count, str_lit("struct"));
fields = check_fields(c, node, st->fields, min_field_count, context);
}
struct_type->Record.scope = c->context.scope;
@@ -1232,35 +1239,36 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
struct_type->Record.is_poly_specialized = is_poly_specialized;
type_set_offsets(c->allocator, struct_type);
if (!struct_type->Record.is_raw_union) {
type_set_offsets(c->allocator, struct_type);
if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
struct_type->failure = false;
struct_type->Record.are_offsets_set = false;
struct_type->Record.offsets = nullptr;
// NOTE(bill): Reorder fields for reduced size/performance
if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
struct_type->failure = false;
struct_type->Record.are_offsets_set = false;
struct_type->Record.offsets = nullptr;
// NOTE(bill): Reorder fields for reduced size/performance
Entity **reordered_fields = gb_alloc_array(c->allocator, Entity *, fields.count);
for (isize i = 0; i < fields.count; i++) {
reordered_fields[i] = struct_type->Record.fields_in_src_order[i];
}
Entity **reordered_fields = gb_alloc_array(c->allocator, Entity *, fields.count);
for (isize i = 0; i < fields.count; i++) {
reordered_fields[i] = struct_type->Record.fields_in_src_order[i];
// NOTE(bill): Hacky thing
// TODO(bill): Probably make an inline sorting procedure rather than use global variables
__checker_allocator = c->allocator;
// NOTE(bill): compound literal order must match source not layout
gb_sort_array(reordered_fields, fields.count, cmp_reorder_struct_fields);
for (isize i = 0; i < fields.count; i++) {
reordered_fields[i]->Variable.field_index = i;
}
struct_type->Record.fields = reordered_fields;
}
// NOTE(bill): Hacky thing
// TODO(bill): Probably make an inline sorting procedure rather than use global variables
__checker_allocator = c->allocator;
// NOTE(bill): compound literal order must match source not layout
gb_sort_array(reordered_fields, fields.count, cmp_reorder_struct_fields);
for (isize i = 0; i < fields.count; i++) {
reordered_fields[i]->Variable.field_index = i;
}
struct_type->Record.fields = reordered_fields;
type_set_offsets(c->allocator, struct_type);
}
type_set_offsets(c->allocator, struct_type);
if (st->align != nullptr) {
if (st->is_packed) {
@@ -1353,29 +1361,29 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
union_type->Union.variant_count = variants.count;
}
void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
GB_ASSERT(node->kind == AstNode_RawUnionType);
GB_ASSERT(is_type_raw_union(union_type));
ast_node(ut, RawUnionType, node);
// void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
// GB_ASSERT(node->kind == AstNode_RawUnionType);
// GB_ASSERT(is_type_raw_union(union_type));
// ast_node(ut, RawUnionType, node);
isize min_field_count = 0;
for_array(i, ut->fields) {
AstNode *field = ut->fields[i];
switch (field->kind) {
case_ast_node(f, ValueDecl, field);
min_field_count += f->names.count;
case_end;
}
}
// isize min_field_count = 0;
// for_array(i, ut->fields) {
// AstNode *field = ut->fields[i];
// switch (field->kind) {
// case_ast_node(f, ValueDecl, field);
// min_field_count += f->names.count;
// case_end;
// }
// }
union_type->Record.names = make_names_field_for_record(c, c->context.scope);
// union_type->Record.names = make_names_field_for_record(c, c->context.scope);
auto fields = check_fields(c, node, ut->fields, min_field_count, str_lit("raw_union"));
// auto fields = check_fields(c, node, ut->fields, min_field_count, str_lit("raw_union"));
union_type->Record.scope = c->context.scope;
union_type->Record.fields = fields.data;
union_type->Record.field_count = fields.count;
}
// union_type->Record.scope = c->context.scope;
// union_type->Record.fields = fields.data;
// union_type->Record.field_count = fields.count;
// }
void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) {
@@ -3018,7 +3026,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
return true;
case_end;
case_ast_node(rut, RawUnionType, e);
/* case_ast_node(rut, RawUnionType, e);
*type = make_type_raw_union(c->allocator);
set_base_type(named_type, *type);
check_open_scope(c, e);
@@ -3027,7 +3035,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
(*type)->Record.node = e;
return true;
case_end;
*/
case_ast_node(et, EnumType, e);
*type = make_type_enum(c->allocator);
set_base_type(named_type, *type);
@@ -6482,7 +6490,7 @@ CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, As
Type *original_type = operand->type;
Type *struct_type = base_type(operand->type);
GB_ASSERT(is_type_struct(struct_type));
GB_ASSERT(struct_type->kind == Type_Record);
TypeRecord *st = &struct_type->Record;
GB_ASSERT(st->is_polymorphic);
@@ -7738,7 +7746,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
valid = false;
}
if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
if (!valid && t->kind == Type_Record) {
Entity *found = find_using_index_expr(t);
if (found != nullptr) {
valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count);
@@ -7937,7 +7945,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
case AstNode_VectorType:
case AstNode_StructType:
case AstNode_UnionType:
case AstNode_RawUnionType:
// case AstNode_RawUnionType:
case AstNode_EnumType:
case AstNode_MapType:
o->mode = Addressing_Type;
@@ -8351,19 +8359,20 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
case_ast_node(st, StructType, node);
str = gb_string_appendc(str, "struct ");
if (st->is_packed) str = gb_string_appendc(str, "#packed ");
if (st->is_ordered) str = gb_string_appendc(str, "#ordered ");
if (st->is_packed) str = gb_string_appendc(str, "#packed ");
if (st->is_ordered) str = gb_string_appendc(str, "#ordered ");
if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union ");
str = gb_string_appendc(str, "{");
str = write_record_fields_to_string(str, st->fields);
str = gb_string_appendc(str, "}");
case_end;
case_ast_node(st, RawUnionType, node);
str = gb_string_appendc(str, "raw_union ");
str = gb_string_appendc(str, "{");
str = write_record_fields_to_string(str, st->fields);
str = gb_string_appendc(str, "}");
case_end;
// case_ast_node(st, RawUnionType, node);
// str = gb_string_appendc(str, "raw_union ");
// str = gb_string_appendc(str, "{");
// str = write_record_fields_to_string(str, st->fields);
// str = gb_string_appendc(str, "}");
// case_end;
case_ast_node(st, UnionType, node);
str = gb_string_appendc(str, "union ");

View File

@@ -472,7 +472,6 @@ void check_open_scope(Checker *c, AstNode *node) {
case AstNode_StructType:
case AstNode_EnumType:
case AstNode_UnionType:
case AstNode_RawUnionType:
scope->is_record = true;
break;
}

View File

@@ -662,7 +662,7 @@ bool ir_type_has_default_values(Type *t) {
return ir_type_has_default_values(t->Array.elem);
case Type_Record:
if (t->Record.kind == TypeRecord_Struct) {
if (!t->Record.is_raw_union) {
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields_in_src_order[i];
if (f->kind != Entity_Variable) continue;
@@ -7355,12 +7355,7 @@ void ir_init_module(irModule *m, Checker *c) {
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;
}
count += t->Record.field_count;
break;
case Type_Tuple:
count += t->Tuple.variable_count;
@@ -8193,8 +8188,32 @@ void ir_gen_tree(irGen *s) {
} break;
case Type_Record: {
switch (t->Record.kind) {
case TypeRecord_Struct: {
if (t->Record.is_raw_union) {
ir_emit_comment(proc, str_lit("TypeInfoRawUnion"));
tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr);
irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count);
irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count);
irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
irValue *index = ir_const_int(a, i);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
// NOTE(bill): Offsets are always 0
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));
}
}
irValue *count = ir_const_int(a, t->Record.field_count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
} else {
ir_emit_comment(proc, str_lit("TypeInfoStruct"));
tag = ir_emit_conv(proc, variant_ptr, t_type_info_struct_ptr);
@@ -8239,33 +8258,6 @@ void ir_gen_tree(irGen *s) {
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count);
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_RawUnion: {
ir_emit_comment(proc, str_lit("TypeInfoRawUnion"));
tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr);
irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count);
irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count);
irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
irValue *index = ir_const_int(a, i);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
// NOTE(bill): Offsets are always 0
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));
}
}
irValue *count = ir_const_int(a, t->Record.field_count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
} break;
}
} break;
case Type_Map: {

View File

@@ -300,8 +300,14 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
} return;
case Type_Record: {
switch (t->Record.kind) {
case TypeRecord_Struct:
if (t->Record.is_raw_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);
i64 align_of_union = type_align_of(heap_allocator(), t);
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
return;
} else {
if (t->Record.is_packed) {
ir_fprintf(f, "<");
}
@@ -323,13 +329,6 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_fprintf(f, ">");
}
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)
i64 size_of_union = type_size_of(heap_allocator(), t);
i64 align_of_union = type_align_of(heap_allocator(), t);
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
} return;
}
} break;

View File

@@ -423,17 +423,13 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
AstNode * polymorphic_params; \
bool is_packed; \
bool is_ordered; \
bool is_raw_union; \
AstNode * align; \
}) \
AST_NODE_KIND(UnionType, "union type", struct { \
Token token; \
Array<AstNode *> variants; \
}) \
AST_NODE_KIND(RawUnionType, "raw union type", struct { \
Token token; \
Array<AstNode *> fields; \
isize field_count; \
}) \
AST_NODE_KIND(EnumType, "enum type", struct { \
Token token; \
AstNode * base_type; \
@@ -599,7 +595,6 @@ Token ast_node_token(AstNode *node) {
case AstNode_VectorType: return node->VectorType.token;
case AstNode_StructType: return node->StructType.token;
case AstNode_UnionType: return node->UnionType.token;
case AstNode_RawUnionType: return node->RawUnionType.token;
case AstNode_EnumType: return node->EnumType.token;
case AstNode_BitFieldType: return node->BitFieldType.token;
case AstNode_MapType: return node->MapType.token;
@@ -868,9 +863,6 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
case AstNode_UnionType:
n->UnionType.variants = clone_ast_node_array(a, n->UnionType.variants);
break;
case AstNode_RawUnionType:
n->RawUnionType.fields = clone_ast_node_array(a, n->RawUnionType.fields);
break;
case AstNode_EnumType:
n->EnumType.base_type = clone_ast_node(a, n->EnumType.base_type);
n->EnumType.fields = clone_ast_node_array(a, n->EnumType.fields);
@@ -1451,7 +1443,8 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
}
AstNode *ast_struct_type(AstFile *f, Token token, Array<AstNode *> fields, isize field_count,
AstNode *polymorphic_params, bool is_packed, bool is_ordered, AstNode *align) {
AstNode *polymorphic_params, bool is_packed, bool is_ordered, bool is_raw_union,
AstNode *align) {
AstNode *result = make_ast_node(f, AstNode_StructType);
result->StructType.token = token;
result->StructType.fields = fields;
@@ -1459,6 +1452,7 @@ AstNode *ast_struct_type(AstFile *f, Token token, Array<AstNode *> fields, isize
result->StructType.polymorphic_params = polymorphic_params;
result->StructType.is_packed = is_packed;
result->StructType.is_ordered = is_ordered;
result->StructType.is_raw_union = is_raw_union;
result->StructType.align = align;
return result;
}
@@ -1471,14 +1465,6 @@ AstNode *ast_union_type(AstFile *f, Token token, Array<AstNode *> variants) {
return result;
}
AstNode *ast_raw_union_type(AstFile *f, Token token, Array<AstNode *> fields, isize field_count) {
AstNode *result = make_ast_node(f, AstNode_RawUnionType);
result->RawUnionType.token = token;
result->RawUnionType.fields = fields;
result->RawUnionType.field_count = field_count;
return result;
}
AstNode *ast_enum_type(AstFile *f, Token token, AstNode *base_type, Array<AstNode *> fields) {
AstNode *result = make_ast_node(f, AstNode_EnumType);
@@ -1837,7 +1823,6 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
case AstNode_StructType:
case AstNode_UnionType:
case AstNode_RawUnionType:
case AstNode_EnumType:
case AstNode_BitFieldType:
return true;
@@ -2424,8 +2409,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
case Token_struct: {
Token token = expect_token(f, Token_struct);
AstNode *polymorphic_params = nullptr;
bool is_packed = false;
bool is_ordered = false;
bool is_packed = false;
bool is_ordered = false;
bool is_raw_union = false;
AstNode *align = nullptr;
if (allow_token(f, Token_OpenParen)) {
@@ -2458,6 +2444,11 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
}
align = parse_expr(f, true);
} else if (tag.string == "raw_union") {
if (is_raw_union) {
syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
}
is_raw_union = true;
} else {
syntax_error(tag, "Invalid struct tag `#%.*s`", LIT(tag.string));
}
@@ -2468,6 +2459,14 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
if (is_packed && is_ordered) {
syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering");
}
if (is_raw_union && is_packed) {
is_packed = false;
syntax_error(token, "`#raw_union` cannot also be `#packed`");
}
if (is_raw_union && is_ordered) {
is_ordered = false;
syntax_error(token, "`#raw_union` cannot also be `#ordered`");
}
Token open = expect_token_after(f, Token_OpenBrace, "struct");
@@ -2481,7 +2480,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
decls = fields->FieldList.list;
}
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_ordered, align);
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_ordered, is_raw_union, align);
} break;
case Token_union: {
@@ -2510,23 +2509,6 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return ast_union_type(f, token, variants);
} break;
case Token_raw_union: {
Token token = expect_token(f, Token_raw_union);
Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
isize decl_count = 0;
AstNode *fields = parse_record_field_list(f, &decl_count);
Token close = expect_token(f, Token_CloseBrace);
Array<AstNode *> decls = {};
if (fields != nullptr) {
GB_ASSERT(fields->kind == AstNode_FieldList);
decls = fields->FieldList.list;
}
return ast_raw_union_type(f, token, decls, decl_count);
} break;
case Token_enum: {
Token token = expect_token(f, Token_enum);
AstNode *base_type = nullptr;

View File

@@ -652,7 +652,7 @@ bool can_ssa_type(Type *t) {
return false;
case Type_Record:
if (t->Record.kind == TypeRecord_Struct) {
if (!t->Record.is_raw_union) {
if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) {
return false;
}

View File

@@ -107,7 +107,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
/* TOKEN_KIND(Token_raw_union, "raw_union"), */ \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_bit_field, "bit_field"), \
TOKEN_KIND(Token_vector, "vector"), \

View File

@@ -68,17 +68,7 @@ struct BasicType {
String name;
};
enum TypeRecordKind {
TypeRecord_Invalid,
TypeRecord_Struct,
TypeRecord_RawUnion,
TypeRecord_Count,
};
struct TypeRecord {
TypeRecordKind kind;
// All record types
// Theses are arrays
@@ -94,6 +84,7 @@ struct TypeRecord {
bool are_offsets_being_processed;
bool is_packed;
bool is_ordered;
bool is_raw_union;
bool is_polymorphic;
bool is_poly_specialized;
Type * polymorphic_params; // Type_Tuple
@@ -523,7 +514,6 @@ Type *make_type_slice(gbAllocator a, Type *elem) {
Type *make_type_struct(gbAllocator a) {
Type *t = alloc_type(a, Type_Record);
t->Record.kind = TypeRecord_Struct;
return t;
}
@@ -532,12 +522,6 @@ Type *make_type_union(gbAllocator a) {
return t;
}
Type *make_type_raw_union(gbAllocator a) {
Type *t = alloc_type(a, Type_Record);
t->Record.kind = TypeRecord_RawUnion;
return t;
}
Type *make_type_enum(gbAllocator a) {
Type *t = alloc_type(a, Type_Enum);
return t;
@@ -847,7 +831,7 @@ Type *base_complex_elem_type(Type *t) {
bool is_type_struct(Type *t) {
t = base_type(t);
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct);
return (t->kind == Type_Record && !t->Record.is_raw_union);
}
bool is_type_union(Type *t) {
t = base_type(t);
@@ -856,7 +840,7 @@ bool is_type_union(Type *t) {
bool is_type_raw_union(Type *t) {
t = base_type(t);
return (t->kind == Type_Record && t->Record.kind == TypeRecord_RawUnion);
return (t->kind == Type_Record && t->Record.is_raw_union);
}
bool is_type_enum(Type *t) {
t = base_type(t);
@@ -932,8 +916,7 @@ bool is_type_indexable(Type *t) {
bool is_type_polymorphic_struct(Type *t) {
t = base_type(t);
if (t->kind == Type_Record &&
t->Record.kind == TypeRecord_Struct) {
if (t->kind == Type_Record) {
return t->Record.is_polymorphic;
}
return false;
@@ -941,8 +924,7 @@ bool is_type_polymorphic_struct(Type *t) {
bool is_type_polymorphic_struct_specialized(Type *t) {
t = base_type(t);
if (t->kind == Type_Record &&
t->Record.kind == TypeRecord_Struct) {
if (t->kind == Type_Record) {
return t->Record.is_polymorphic && t->Record.is_poly_specialized;
}
return false;
@@ -1158,34 +1140,28 @@ bool are_types_identical(Type *x, Type *y) {
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:
if (x->Record.field_count == y->Record.field_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) {
// TODO(bill); Fix the custom alignment rule
for (isize i = 0; i < x->Record.field_count; i++) {
Entity *xf = x->Record.fields[i];
Entity *yf = y->Record.fields[i];
if (!are_types_identical(xf->type, yf->type)) {
return false;
}
if (xf->token.string != yf->token.string) {
return false;
}
bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
if (xf_is_using ^ yf_is_using) {
return false;
}
}
return true;
if (x->Record.is_raw_union == y->Record.is_raw_union &&
x->Record.field_count == y->Record.field_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) {
// TODO(bill); Fix the custom alignment rule
for (isize i = 0; i < x->Record.field_count; i++) {
Entity *xf = x->Record.fields[i];
Entity *yf = y->Record.fields[i];
if (!are_types_identical(xf->type, yf->type)) {
return false;
}
if (xf->token.string != yf->token.string) {
return false;
}
bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
if (xf_is_using ^ yf_is_using) {
return false;
}
break;
}
return true;
}
}
break;
@@ -1310,7 +1286,7 @@ bool is_type_cte_safe(Type *type) {
return false;
case Type_Record: {
if (type->Record.kind != TypeRecord_Struct) {
if (type->Record.is_raw_union) {
return false;
}
for (isize i = 0; i < type->Record.field_count; i++) {
@@ -1619,7 +1595,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
return lookup_field_with_selection(a, specialized, field_name, is_type, sel);
}
} else if (type->Record.kind == Type_Union) {
} else if (type->kind == Type_Union) {
if (field_name == "__tag") {
Entity *e = type->Union.union__tag;
GB_ASSERT(e != nullptr);
@@ -1868,8 +1844,22 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
} break;
case Type_Record: {
switch (t->Record.kind) {
case TypeRecord_Struct:
if (t->Record.is_raw_union) {
i64 max = 1;
for (isize i = 0; i < t->Record.field_count; i++) {
Type *field_type = t->Record.fields[i]->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;
}
}
return max;
} else {
if (t->Record.custom_align > 0) {
return gb_clamp(t->Record.custom_align, 1, build_context.max_align);
}
@@ -1892,23 +1882,6 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
}
return max;
}
break;
case TypeRecord_RawUnion: {
i64 max = 1;
for (isize i = 0; i < t->Record.field_count; i++) {
Type *field_type = t->Record.fields[i]->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;
}
}
return max;
} break;
}
} break;
@@ -1927,10 +1900,14 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
return gb_clamp(next_pow2(type_size_of_internal(allocator, t, path)), 1, build_context.word_size);
}
i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_count, bool is_packed) {
i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_count, bool is_packed, bool is_raw_union) {
i64 *offsets = gb_alloc_array(allocator, i64, field_count);
i64 curr_offset = 0;
if (is_packed) {
if (is_raw_union) {
for (isize i = 0; i < field_count; i++) {
offsets[i] = 0;
}
} else if (is_packed) {
for (isize i = 0; i < field_count; i++) {
i64 size = type_size_of(allocator, fields[i]->type);
offsets[i] = curr_offset;
@@ -1950,17 +1927,17 @@ i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_cou
bool type_set_offsets(gbAllocator allocator, Type *t) {
t = base_type(t);
if (is_type_struct(t)) {
if (t->kind == Type_Record) {
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, t->Record.is_packed);
t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, t->Record.is_packed, t->Record.is_raw_union);
t->Record.are_offsets_set = true;
return true;
}
} 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);
t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false, false);
t->Tuple.are_offsets_set = true;
return true;
}
@@ -2114,9 +2091,22 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
case Type_Record: {
switch (t->Record.kind) {
case TypeRecord_Struct: {
if (t->Record.is_raw_union) {
i64 count = t->Record.field_count;
i64 align = type_align_of_internal(allocator, t, path);
if (path->failure) {
return FAILURE_SIZE;
}
i64 max = 0;
for (isize i = 0; i < count; i++) {
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
if (max < size) {
max = size;
}
}
// TODO(bill): Is this how it should work?
return align_formula(max, align);
} else {
i64 count = t->Record.field_count;
if (count == 0) {
return 0;
@@ -2132,24 +2122,6 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
type_set_offsets(allocator, t);
i64 size = t->Record.offsets[count-1] + type_size_of_internal(allocator, t->Record.fields[count-1]->type, path);
return align_formula(size, align);
} break;
case TypeRecord_RawUnion: {
i64 count = t->Record.field_count;
i64 align = type_align_of_internal(allocator, t, path);
if (path->failure) {
return FAILURE_SIZE;
}
i64 max = 0;
for (isize i = 0; i < count; i++) {
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
if (max < size) {
max = size;
}
}
// TODO(bill): Is this how it should work?
return align_formula(max, align);
} break;
}
} break;
@@ -2172,7 +2144,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)) {
if (t->kind == Type_Record && !t->Record.is_raw_union) {
type_set_offsets(allocator, t);
if (gb_is_between(index, 0, t->Record.field_count-1)) {
return t->Record.offsets[index];
@@ -2221,7 +2193,7 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s
isize index = sel.index[i];
t = base_type(t);
offset += type_offset_of(allocator, t, index);
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
if (t->kind == Type_Record && !t->Record.is_raw_union) {
t = t->Record.fields[index]->type;
} else {
// NOTE(bill): No need to worry about custom types, just need the alignment
@@ -2339,8 +2311,20 @@ gbString write_type_to_string(gbString str, Type *type) {
break;
case Type_Record: {
switch (type->Record.kind) {
case TypeRecord_Struct:
if (type->Record.is_raw_union) {
str = gb_string_appendc(str, "raw_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);
}
str = gb_string_appendc(str, "}");
} else {
str = gb_string_appendc(str, "struct");
if (type->Record.is_packed) {
str = gb_string_appendc(str, " #packed");
@@ -2360,22 +2344,6 @@ gbString write_type_to_string(gbString str, Type *type) {
str = write_type_to_string(str, f->type);
}
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++) {
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);
}
str = gb_string_appendc(str, "}");
break;
}
} break;