This commit is contained in:
Zac Pierson
2017-02-22 10:57:30 -06:00
10 changed files with 678 additions and 389 deletions
+95 -5
View File
@@ -7,12 +7,102 @@
#import "os.odin"; #import "os.odin";
// #import "halloc.odin"; // #import "halloc.odin";
Token_Kind :: enum {
}
Token_Pos :: struct {
file: string,
line: int,
column: int,
}
Token :: struct {
kind: Token_Kind,
name: string,
using pos: Token_Pos,
}
Exact_Value :: union {
Boolean {b: bool},
String {s: string},
Integer {i: i64},
Float {f: f64},
Pointer {p: i64},
Compound{c: rawptr},
}
Overload_Kind :: enum {
UNKNOWN,
NO,
YES,
}
Scope :: struct {
parent: ^Scope,
prev, next: ^Scope,
first_child, last_child: ^Scope,
elements: map[string]^Entity,
implicit: map[^Entity]bool,
shared: [dynamic]^Scope,
imported: [dynamic]^Scope,
is_proc: bool,
is_global: bool,
is_file: bool,
is_init: bool,
has_been_imported: bool, // This is only applicable to file scopes
file: rawptr,
}
Type :: struct {
}
Entity :: union {
// Common Fields
flags: u32,
using token: Token,
scope: ^Scope, // Parent's scope
type: ^Type,
// identifier: ^ast.Node,
using_parent: ^Entity,
// using_expr: ^ast.Node,
// Variants
Constant{value: Exact_Value},
Variable{
field_index, field_src_index: int,
is_immutable, is_thread_local: bool,
},
Type_Name{},
Procedure{
is_foreign: bool,
foreign_name: string,
foreign_library: ^Entity,
link_name: string,
tags: u64,
overload_kind: Overload_Kind,
},
Builtin{id: int},
Import_Name{
import_path: string,
import_name: string,
import_scope: ^Scope,
used: bool,
},
Library_Name{
library_path: string,
library_name: string,
used: bool,
},
Nil{},
}
main :: proc() { main :: proc() {
m: map[int]int; e: Entity;
m[123] = 312; u := union_cast(^Type_Info.Union)type_info_base(type_info_of_val(e));
fmt.println(m[123]);
delete(m, 123);
fmt.println(m[123]); fmt.println(type_info_base(type_info(Entity)));
// e.flags = 123;
/* /*
+24 -75
View File
@@ -14,6 +14,18 @@
// IMPORTANT NOTE(bill): Do not change the order of any of this data // IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order // The compiler relies upon this _exact_ order
Type_Info_Enum_Value :: raw_union {
f: f64,
i: i64,
}
// NOTE(bill): This must match the compiler's
Calling_Convention :: enum {
ODIN = 0,
C = 1,
STD = 2,
FAST = 3,
}
Type_Info_Record :: struct #ordered { Type_Info_Record :: struct #ordered {
types: []^Type_Info, types: []^Type_Info,
names: []string, names: []string,
@@ -24,80 +36,7 @@ Type_Info_Record :: struct #ordered {
ordered: bool, ordered: bool,
custom_align: bool, custom_align: bool,
} }
Type_Info_Enum_Value :: raw_union {
f: f64,
i: i64,
}
// NOTE(bill): This much the same as the compiler's
Calling_Convention :: enum {
ODIN = 0,
C = 1,
STD = 2,
FAST = 3,
}
/*
Type_Info :: union {
Named: struct #ordered {
name: string,
base: ^Type_Info, // This will _not_ be a Type_Info.Named
},
Integer: struct #ordered {
size: int, // in bytes
signed: bool,
},
Float: struct #ordered {
size: int, // in bytes
},
String: struct #ordered {},
Boolean: struct #ordered {},
Any: struct #ordered {},
Pointer: struct #ordered {
elem: ^Type_Info, // nil -> rawptr
},
Procedure: struct #ordered {
params: ^Type_Info, // Type_Info.Tuple
results: ^Type_Info, // Type_Info.Tuple
variadic: bool,
convention: Calling_Convention,
},
Array: struct #ordered {
elem: ^Type_Info,
elem_size: int,
count: int,
},
Dynamic_Array: struct #ordered {
elem: ^Type_Info,
elem_size: int,
},
Slice: struct #ordered {
elem: ^Type_Info,
elem_size: int,
},
Vector: struct #ordered {
elem: ^Type_Info,
elem_size: int,
count: int,
align: int,
},
Tuple: Type_Info_Record, // Only really used for procedures
Struct: Type_Info_Record,
Union: Type_Info_Record,
Raw_Union: Type_Info_Record,
Enum: struct #ordered {
base: ^Type_Info,
names: []string,
values: []Type_Info_Enum_Value,
},
Map: struct #ordered {
key: ^Type_Info,
value: ^Type_Info,
generated_struct: ^Type_Info,
count: int, // == 0 if dynamic
},
}
*/
Type_Info :: union { Type_Info :: union {
Named{name: string, base: ^Type_Info}, Named{name: string, base: ^Type_Info},
Integer{size: int, signed: bool}, Integer{size: int, signed: bool},
@@ -124,8 +63,18 @@ Type_Info :: union {
Vector {elem: ^Type_Info, elem_size, count, align: int}, Vector {elem: ^Type_Info, elem_size, count, align: int},
Tuple {using record: Type_Info_Record}, // Only really used for procedures Tuple {using record: Type_Info_Record}, // Only really used for procedures
Struct {using record: Type_Info_Record}, Struct {using record: Type_Info_Record},
Union {using record: Type_Info_Record},
Raw_Union {using record: Type_Info_Record}, Raw_Union {using record: Type_Info_Record},
Union{
common_fields: struct {
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
},
variant_names: []string,
variant_types: []^Type_Info,
size: int,
align: int,
},
Enum{ Enum{
base: ^Type_Info, base: ^Type_Info,
names: []string, names: []string,
@@ -142,7 +91,7 @@ Type_Info :: union {
// // NOTE(bill): only the ones that are needed (not all types) // // NOTE(bill): only the ones that are needed (not all types)
// // This will be set by the compiler // // This will be set by the compiler
// immutable __type_infos: []Type_Info; __type_infos: []Type_Info;
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil { if info == nil {
+46 -4
View File
@@ -215,11 +215,36 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
case Union: case Union:
buffer_write_string(buf, "union {"); buffer_write_string(buf, "union {");
for name, i in info.names { cf := info.common_fields;
total_count := 0;
for name, i in cf.names {
if i > 0 {
buffer_write_string(buf, ", ");
}
buffer_write_string(buf, name); buffer_write_string(buf, name);
buffer_write_string(buf, ": "); buffer_write_string(buf, ": ");
buffer_write_type(buf, info.types[i]); buffer_write_type(buf, cf.types[i]);
buffer_write_byte(buf, ','); total_count += 1;
}
for name, i in info.variant_names {
if i > 0 || total_count > 0 {
buffer_write_string(buf, ", ");
}
buffer_write_string(buf, name);
buffer_write_byte(buf, '{');
defer buffer_write_byte(buf, '}');
variant_type := type_info_base(info.variant_types[i]);
variant := union_cast(^Struct)variant_type;
for j in cf.names.count..<variant.names.count {
if j > 0 {
buffer_write_byte(buf, ',');
}
buffer_write_string(buf, variant.names[j]);
buffer_write_string(buf, ": ");
buffer_write_type(buf, variant.types[j]);
}
} }
buffer_write_string(buf, "}"); buffer_write_string(buf, "}");
@@ -687,6 +712,9 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
break; break;
} }
} }
} else if e.values.count == 0 {
buffer_write_string(fi.buf, "");
ok = true;
} else { } else {
for it, idx in e.values { for it, idx in e.values {
if it.f == f { if it.f == f {
@@ -864,7 +892,21 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
} }
case Union: case Union:
buffer_write_string(fi.buf, "(union)"); buffer_write_byte(fi.buf, '{');
defer buffer_write_byte(fi.buf, '}');
cf := info.common_fields;
for _, i in cf.names {
if i > 0 {
buffer_write_string(fi.buf, ", ");
}
buffer_write_string(fi.buf, cf.names[i]);
buffer_write_string(fi.buf, " = ");
data := cast(^byte)v.data + cf.offsets[i];
fmt_value(fi, any{cf.types[i], cast(rawptr)data}, 'v');
}
case Raw_Union: case Raw_Union:
buffer_write_string(fi.buf, "(raw_union)"); buffer_write_string(fi.buf, "(raw_union)");
+156 -148
View File
@@ -189,8 +189,8 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
#endif #endif
if (is_type_union(dst)) { if (is_type_union(dst)) {
for (isize i = 0; i < dst->Record.field_count; i++) { for (isize i = 0; i < dst->Record.variant_count; i++) {
Entity *f = dst->Record.fields[i]; Entity *f = dst->Record.variants[i];
if (are_types_identical(f->type, s)) { if (are_types_identical(f->type, s)) {
return 1; return 1;
} }
@@ -297,7 +297,10 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *entity_map) { void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *entity_map) {
t = base_type(type_deref(t)); t = base_type(type_deref(t));
gbString str = expr_to_string(node); gbString str = NULL;
if (node != NULL) {
expr_to_string(node);
}
if (t->kind == Type_Record) { if (t->kind == Type_Record) {
for (isize i = 0; i < t->Record.field_count; i++) { for (isize i = 0; i < t->Record.field_count; i++) {
@@ -309,7 +312,11 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *en
if (found != NULL) { if (found != NULL) {
Entity *e = *found; Entity *e = *found;
// TODO(bill): Better type error // TODO(bill): Better type error
error(e->token, "`%.*s` is already declared in `%s`", LIT(name), str); if (str != NULL) {
error(e->token, "`%.*s` is already declared in `%s`", LIT(name), str);
} else {
error(e->token, "`%.*s` is already declared`", LIT(name));
}
} else { } else {
map_entity_set(entity_map, key, f); map_entity_set(entity_map, key, f);
add_entity(c, c->context.scope, NULL, f); add_entity(c, c->context.scope, NULL, f);
@@ -324,145 +331,106 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *en
} }
void check_fields(Checker *c, AstNode *node, AstNodeArray decls, // Returns filled field_count
Entity **fields, isize field_count, isize check_fields(Checker *c, AstNode *node, AstNodeArray decls,
String context) { Entity **fields, isize field_count,
String context) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
MapEntity entity_map = {0}; MapEntity entity_map = {0};
map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count); map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count);
isize other_field_index = 0;
Entity *using_index_expr = NULL; Entity *using_index_expr = NULL;
if (node->kind == AstNode_UnionType) { if (node != NULL) {
isize field_index = 0; GB_ASSERT(node->kind != AstNode_UnionType);
fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL); }
for_array(decl_index, decls) {
AstNode *decl = decls.e[decl_index]; isize field_index = 0;
if (decl->kind != AstNode_Field) { for_array(decl_index, decls) {
AstNode *decl = decls.e[decl_index];
if (decl->kind != AstNode_Field) {
continue;
}
ast_node(f, Field, decl);
Type *type = check_type(c, f->type);
if (f->flags&FieldFlag_using) {
if (f->names.count > 1) {
error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type");
}
}
for_array(name_index, f->names) {
AstNode *name = f->names.e[name_index];
if (!ast_node_expect(name, AstNode_Ident)) {
continue; continue;
} }
ast_node(f, Field, decl); Token name_token = name->Ident;
Type *base_type = check_type_extra(c, f->type, NULL);
for_array(name_index, f->names) {
AstNode *name = f->names.e[name_index];
if (!ast_node_expect(name, AstNode_Ident)) {
continue;
}
Token name_token = name->Ident;
if (str_eq(name_token.string, str_lit("names"))) {
error(name_token, "`names` is a reserved identifier for unions");
continue;
}
Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL);
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type);
type->Named.type_name = e;
add_entity(c, c->context.scope, name, e);
if (str_eq(name_token.string, str_lit("_"))) {
error(name_token, "`_` cannot be used a union subtype");
continue;
}
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->flags&FieldFlag_using, cast(i32)field_index);
e->identifier = name;
if (str_eq(name_token.string, str_lit("_"))) {
fields[field_index++] = e;
} else {
HashKey key = hash_string(name_token.string); HashKey key = hash_string(name_token.string);
if (map_entity_get(&entity_map, key) != NULL) { Entity **found = map_entity_get(&entity_map, key);
if (found != NULL) {
Entity *e = *found;
// TODO(bill): Scope checking already checks the declaration // TODO(bill): Scope checking already checks the declaration
error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string)); error(name_token, "`%.*s` is already declared in this type", LIT(name_token.string));
error(e->token, "\tpreviously declared");
} else { } else {
map_entity_set(&entity_map, key, e); map_entity_set(&entity_map, key, e);
fields[field_index++] = e; fields[field_index++] = e;
add_entity(c, c->context.scope, name, e);
} }
add_entity_use(c, name, e); add_entity_use(c, name, e);
} }
} }
} else {
isize field_index = 0;
for_array(decl_index, decls) {
AstNode *decl = decls.e[decl_index];
if (decl->kind != AstNode_Field) {
continue;
}
ast_node(f, Field, decl);
Type *type = check_type_extra(c, f->type, NULL);
if (f->flags&FieldFlag_using) {
if (f->names.count > 1) {
error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type");
}
}
for_array(name_index, f->names) {
AstNode *name = f->names.e[name_index];
if (!ast_node_expect(name, AstNode_Ident)) {
continue;
}
Token name_token = name->Ident;
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->flags&FieldFlag_using, cast(i32)field_index);
e->identifier = name;
if (str_eq(name_token.string, str_lit("_"))) {
fields[field_index++] = e;
} else {
HashKey key = hash_string(name_token.string);
if (map_entity_get(&entity_map, key) != NULL) {
// TODO(bill): Scope checking already checks the declaration
error(name_token, "`%.*s` is already declared in this type", LIT(name_token.string));
} else {
map_entity_set(&entity_map, key, e);
fields[field_index++] = e;
add_entity(c, c->context.scope, name, e);
}
add_entity_use(c, name, e);
}
}
if (f->flags&FieldFlag_using) { if (f->flags&FieldFlag_using) {
Type *t = base_type(type_deref(type)); Type *t = base_type(type_deref(type));
if (!is_type_struct(t) && !is_type_raw_union(t) && if (!is_type_struct(t) && !is_type_raw_union(t) &&
f->names.count >= 1 && f->names.count >= 1 &&
f->names.e[0]->kind == AstNode_Ident) { f->names.e[0]->kind == AstNode_Ident) {
Token name_token = f->names.e[0]->Ident; Token name_token = f->names.e[0]->Ident;
if (is_type_indexable(t)) { if (is_type_indexable(t)) {
bool ok = true; bool ok = true;
for_array(emi, entity_map.entries) { for_array(emi, entity_map.entries) {
Entity *e = entity_map.entries.e[emi].value; Entity *e = entity_map.entries.e[emi].value;
if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) { if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
if (is_type_indexable(e->type)) { if (is_type_indexable(e->type)) {
if (e->identifier != f->names.e[0]) { if (e->identifier != f->names.e[0]) {
ok = false; ok = false;
using_index_expr = e; using_index_expr = e;
break; break;
}
} }
} }
} }
if (ok) {
using_index_expr = fields[field_index-1];
} else {
fields[field_index-1]->flags &= ~EntityFlag_Anonymous;
error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string));
}
} else {
error(name_token, "`using` on a field `%.*s` must be a `struct` or `raw_union`", LIT(name_token.string));
continue;
} }
if (ok) {
using_index_expr = fields[field_index-1];
} else {
fields[field_index-1]->flags &= ~EntityFlag_Anonymous;
error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string));
}
} else {
error(name_token, "`using` on a field `%.*s` must be a `struct` or `raw_union`", LIT(name_token.string));
continue;
} }
populate_using_entity_map(c, node, type, &entity_map);
} }
populate_using_entity_map(c, node, type, &entity_map);
} }
} }
gb_temp_arena_memory_end(tmp); gb_temp_arena_memory_end(tmp);
return field_index;
} }
@@ -520,7 +488,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count); Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
check_fields(c, node, st->fields, fields, field_count, str_lit("struct")); field_count = check_fields(c, node, st->fields, fields, field_count, str_lit("struct"));
struct_type->Record.struct_is_packed = st->is_packed; struct_type->Record.struct_is_packed = st->is_packed;
struct_type->Record.struct_is_ordered = st->is_ordered; struct_type->Record.struct_is_ordered = st->is_ordered;
@@ -590,55 +558,88 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
return; return;
} }
}
}
void check_union_type(Checker *c, Type *union_type, AstNode *node) { void check_union_type(Checker *c, Type *union_type, AstNode *node) {
GB_ASSERT(is_type_union(union_type)); GB_ASSERT(is_type_union(union_type));
ast_node(ut, UnionType, node); ast_node(ut, UnionType, node);
isize field_count = ut->fields.count+1; isize variant_count = ut->variants.count+1;
isize field_count = 0;
for_array(i, ut->fields) {
AstNode *field = ut->fields.e[i];
if (field->kind == AstNode_Field) {
ast_node(f, Field, field);
field_count += f->names.count;
}
}
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
MapEntity entity_map = {0}; MapEntity entity_map = {0};
map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count); map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*variant_count);
Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count); Entity *using_index_expr = NULL;
isize field_index = 0; Entity **variants = gb_alloc_array(c->allocator, Entity *, variant_count);
fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL); Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
for_array(i, ut->fields) { isize variant_index = 0;
AstNode *field = ut->fields.e[i]; variants[variant_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL);
if (field->kind != AstNode_UnionField) {
field_count = check_fields(c, NULL, ut->fields, fields, field_count, str_lit("union"));
union_type->Record.fields = fields;
union_type->Record.field_count = field_count;
for_array(i, ut->variants) {
AstNode *variant = ut->variants.e[i];
if (variant->kind != AstNode_UnionField) {
continue; continue;
} }
ast_node(f, UnionField, ut->fields.e[i]); ast_node(f, UnionField, variant);
Token name_token = f->name->Ident; Token name_token = f->name->Ident;
if (str_eq(name_token.string, str_lit("names"))) {
error(name_token, "`names` is a reserved identifier for unions");
continue;
}
Type *base_type = make_type_struct(c->allocator); Type *base_type = make_type_struct(c->allocator);
{ {
ast_node(fl, FieldList, f->list); ast_node(fl, FieldList, f->list);
isize field_count = 0;
for_array(j, fl->list) { // TODO(bill): Just do a gb_memcopy here
ast_node(f, Field, fl->list.e[j]); // NOTE(bill): Copy the contents for the common fields for now
field_count += f->names.count; AstNodeArray list = {0};
array_init_count(&list, c->allocator, ut->fields.count+fl->list.count);
for (isize j = 0; j < ut->fields.count; j++) {
list.e[j] = ut->fields.e[j];
} }
for (isize j = 0; j < fl->list.count; j++) {
list.e[j+ut->fields.count] = fl->list.e[j];
}
isize list_count = 0;
for_array(j, list) {
ast_node(f, Field, list.e[j]);
list_count += f->names.count;
}
Token token = name_token; Token token = name_token;
token.kind = Token_struct; token.kind = Token_struct;
AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, fl->list, field_count, AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, list, list_count, false, true, NULL);
false, true, NULL);
check_open_scope(c, dummy_struct); check_open_scope(c, dummy_struct);
check_struct_type(c, base_type, dummy_struct); Entity **fields = gb_alloc_array(c->allocator, Entity *, list_count);
check_close_scope(c); isize field_count = check_fields(c, dummy_struct, list, fields, list_count, str_lit("variant"));
base_type->Record.struct_is_packed = false;
base_type->Record.struct_is_ordered = true;
base_type->Record.fields = fields;
base_type->Record.fields_in_src_order = fields;
base_type->Record.field_count = field_count;
base_type->Record.names = make_names_field_for_record(c, c->context.scope);
base_type->Record.node = dummy_struct; base_type->Record.node = dummy_struct;
type_set_offsets(c->allocator, base_type);
check_close_scope(c);
} }
Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL); Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL);
@@ -657,16 +658,15 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string)); error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string));
} else { } else {
map_entity_set(&entity_map, key, e); map_entity_set(&entity_map, key, e);
fields[field_index++] = e; variants[variant_index++] = e;
} }
add_entity_use(c, f->name, e); add_entity_use(c, f->name, e);
} }
gb_temp_arena_memory_end(tmp); gb_temp_arena_memory_end(tmp);
union_type->Record.fields = fields; union_type->Record.variants = variants;
union_type->Record.field_count = field_index; union_type->Record.variant_count = variant_index;
union_type->Record.names = make_names_field_for_record(c, c->context.scope);
} }
void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
@@ -686,7 +686,7 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count); Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
check_fields(c, node, ut->fields, fields, field_count, str_lit("raw_union")); field_count = check_fields(c, node, ut->fields, fields, field_count, str_lit("raw_union"));
union_type->Record.fields = fields; union_type->Record.fields = fields;
union_type->Record.field_count = field_count; union_type->Record.field_count = field_count;
@@ -865,7 +865,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
AstNode *field = params.e[i]; AstNode *field = params.e[i];
if (ast_node_expect(field, AstNode_Field)) { if (ast_node_expect(field, AstNode_Field)) {
ast_node(f, Field, field); ast_node(f, Field, field);
variable_count += max(f->names.count, 1); variable_count += gb_max(f->names.count, 1);
} }
} }
@@ -951,7 +951,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
AstNode *field = results.e[i]; AstNode *field = results.e[i];
if (ast_node_expect(field, AstNode_Field)) { if (ast_node_expect(field, AstNode_Field)) {
ast_node(f, Field, field); ast_node(f, Field, field);
variable_count += max(f->names.count, 1); variable_count += gb_max(f->names.count, 1);
} }
} }
@@ -4516,12 +4516,15 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
Type *t = base_type(type); Type *t = base_type(type);
switch (t->kind) { switch (t->kind) {
case Type_Record: { case Type_Record: {
if (!is_type_struct(t)) { if (!is_type_struct(t) && !is_type_union(t)) {
if (cl->elems.count != 0) { if (cl->elems.count != 0) {
error_node(node, "Illegal compound literal"); error_node(node, "Illegal compound literal");
} }
break; break;
} }
if (is_type_union(t)) {
is_constant = false;
}
if (cl->elems.count == 0) { if (cl->elems.count == 0) {
break; // NOTE(bill): No need to init break; // NOTE(bill): No need to init
} }
@@ -4917,8 +4920,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
} }
bool ok = false; bool ok = false;
for (isize i = 1; i < bsrc->Record.field_count; i++) { for (isize i = 1; i < bsrc->Record.variant_count; i++) {
Entity *f = bsrc->Record.fields[i]; Entity *f = bsrc->Record.variants[i];
if (are_types_identical(f->type, dst)) { if (are_types_identical(f->type, dst)) {
ok = true; ok = true;
break; break;
@@ -5308,11 +5311,9 @@ gbString write_expr_to_string(gbString str, AstNode *node);
gbString write_record_fields_to_string(gbString str, AstNodeArray params) { gbString write_record_fields_to_string(gbString str, AstNodeArray params) {
for_array(i, params) { for_array(i, params) {
if (i > 0) { if (i > 0) {
str = gb_string_appendc(str, " "); str = gb_string_appendc(str, ", ");
} }
str = write_expr_to_string(str, params.e[i]); str = write_expr_to_string(str, params.e[i]);
str = gb_string_appendc(str, ";");
} }
return str; return str;
} }
@@ -5502,6 +5503,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
} }
case_end; case_end;
case_ast_node(f, UnionField, node);
str = write_expr_to_string(str, f->name);
str = gb_string_appendc(str, "{");
str = write_expr_to_string(str, f->list);
str = gb_string_appendc(str, "}");
case_end;
case_ast_node(ce, CallExpr, node); case_ast_node(ce, CallExpr, node);
str = write_expr_to_string(str, ce->proc); str = write_expr_to_string(str, ce->proc);
str = gb_string_appendc(str, "("); str = gb_string_appendc(str, "(");
+5 -6
View File
@@ -1029,8 +1029,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (is_union_ptr) { if (is_union_ptr) {
GB_ASSERT(is_type_union(bt)); GB_ASSERT(is_type_union(bt));
bool tag_type_found = false; bool tag_type_found = false;
for (isize i = 0; i < bt->Record.field_count; i++) { for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.fields[i]; Entity *f = bt->Record.variants[i];
if (are_types_identical(f->type, y.type)) { if (are_types_identical(f->type, y.type)) {
tag_type_found = true; tag_type_found = true;
break; break;
@@ -1038,8 +1038,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
if (!tag_type_found) { if (!tag_type_found) {
gbString type_str = type_to_string(y.type); gbString type_str = type_to_string(y.type);
error_node(y.expr, error_node(y.expr, "Unknown tag type, got `%s`", type_str);
"Unknown tag type, got `%s`", type_str);
gb_string_free(type_str); gb_string_free(type_str);
continue; continue;
} }
@@ -1163,8 +1162,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case Entity_TypeName: { case Entity_TypeName: {
Type *t = base_type(e->type); Type *t = base_type(e->type);
if (is_type_union(t)) { if (is_type_union(t)) {
for (isize i = 0; i < t->Record.field_count; i++) { for (isize i = 0; i < t->Record.variant_count; i++) {
Entity *f = t->Record.fields[i]; Entity *f = t->Record.variants[i];
Entity *found = scope_insert_entity(c->context.scope, f); Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) { if (found != NULL) {
gbString expr_str = expr_to_string(expr); gbString expr_str = expr_to_string(expr);
+24 -20
View File
@@ -954,6 +954,10 @@ void add_type_info_type(Checker *c, Type *t) {
break; break;
case TypeRecord_Union: case TypeRecord_Union:
add_type_info_type(c, t_int); add_type_info_type(c, t_int);
for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.variants[i];
add_type_info_type(c, f->type);
}
/* fallthrough */ /* fallthrough */
default: default:
for (isize i = 0; i < bt->Record.field_count; i++) { for (isize i = 0; i < bt->Record.field_count; i++) {
@@ -1103,27 +1107,27 @@ void init_preload(Checker *c) {
if (record->field_count != 19) { if (record->variant_count != 19) {
compiler_error("Invalid `Type_Info` layout"); compiler_error("Invalid `Type_Info` layout");
} }
t_type_info_named = record->fields[ 1]->type; t_type_info_named = record->variants[ 1]->type;
t_type_info_integer = record->fields[ 2]->type; t_type_info_integer = record->variants[ 2]->type;
t_type_info_float = record->fields[ 3]->type; t_type_info_float = record->variants[ 3]->type;
t_type_info_string = record->fields[ 4]->type; t_type_info_string = record->variants[ 4]->type;
t_type_info_boolean = record->fields[ 5]->type; t_type_info_boolean = record->variants[ 5]->type;
t_type_info_any = record->fields[ 6]->type; t_type_info_any = record->variants[ 6]->type;
t_type_info_pointer = record->fields[ 7]->type; t_type_info_pointer = record->variants[ 7]->type;
t_type_info_procedure = record->fields[ 8]->type; t_type_info_procedure = record->variants[ 8]->type;
t_type_info_array = record->fields[ 9]->type; t_type_info_array = record->variants[ 9]->type;
t_type_info_dynamic_array = record->fields[10]->type; t_type_info_dynamic_array = record->variants[10]->type;
t_type_info_slice = record->fields[11]->type; t_type_info_slice = record->variants[11]->type;
t_type_info_vector = record->fields[12]->type; t_type_info_vector = record->variants[12]->type;
t_type_info_tuple = record->fields[13]->type; t_type_info_tuple = record->variants[13]->type;
t_type_info_struct = record->fields[14]->type; t_type_info_struct = record->variants[14]->type;
t_type_info_union = record->fields[15]->type; t_type_info_raw_union = record->variants[15]->type;
t_type_info_raw_union = record->fields[16]->type; t_type_info_union = record->variants[16]->type;
t_type_info_enum = record->fields[17]->type; t_type_info_enum = record->variants[17]->type;
t_type_info_map = record->fields[18]->type; t_type_info_map = record->variants[18]->type;
t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named); t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named);
t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer); t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer);
@@ -1139,8 +1143,8 @@ void init_preload(Checker *c) {
t_type_info_vector_ptr = make_type_pointer(c->allocator, t_type_info_vector); t_type_info_vector_ptr = make_type_pointer(c->allocator, t_type_info_vector);
t_type_info_tuple_ptr = make_type_pointer(c->allocator, t_type_info_tuple); t_type_info_tuple_ptr = make_type_pointer(c->allocator, t_type_info_tuple);
t_type_info_struct_ptr = make_type_pointer(c->allocator, t_type_info_struct); t_type_info_struct_ptr = make_type_pointer(c->allocator, t_type_info_struct);
t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union);
t_type_info_raw_union_ptr = make_type_pointer(c->allocator, t_type_info_raw_union); t_type_info_raw_union_ptr = make_type_pointer(c->allocator, t_type_info_raw_union);
t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union);
t_type_info_enum_ptr = make_type_pointer(c->allocator, t_type_info_enum); t_type_info_enum_ptr = make_type_pointer(c->allocator, t_type_info_enum);
t_type_info_map_ptr = make_type_pointer(c->allocator, t_type_info_map); t_type_info_map_ptr = make_type_pointer(c->allocator, t_type_info_map);
} }
+205 -93
View File
@@ -1827,6 +1827,15 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
GB_ASSERT(t->Record.field_count > 0); GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = make_type_pointer(a, t->Record.fields[index]->type); result_type = make_type_pointer(a, t->Record.fields[index]->type);
} else if (is_type_union(t)) {
type_set_offsets(a, t);
GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = make_type_pointer(a, t->Record.fields[index]->type);
i64 offset = t->Record.struct_offsets[index];
irValue *ptr = ir_emit_conv(proc, s, t_u8_ptr);
ptr = ir_emit_ptr_offset(proc, ptr, ir_make_const_int(a, offset));
return ir_emit_conv(proc, ptr, result_type);
} else if (is_type_tuple(t)) { } else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0); GB_ASSERT(t->Tuple.variable_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
@@ -1881,6 +1890,17 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
GB_ASSERT(t->Record.field_count > 0); GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = t->Record.fields[index]->type; result_type = t->Record.fields[index]->type;
} else if (is_type_union(t)) {
type_set_offsets(a, t);
GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
Type *ptr_type = make_type_pointer(a, t->Record.fields[index]->type);
i64 offset = t->Record.struct_offsets[index];
irValue *ptr = ir_address_from_load_or_generate_local(proc, s);
ptr = ir_emit_conv(proc, s, t_u8_ptr);
ptr = ir_emit_ptr_offset(proc, ptr, ir_make_const_int(a, offset));
ptr = ir_emit_conv(proc, ptr, ptr_type);
return ir_emit_load(proc, ptr);
} else if (is_type_tuple(t)) { } else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0); GB_ASSERT(t->Tuple.variable_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
@@ -2278,20 +2298,16 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
} }
if (is_type_union(dst)) { if (is_type_union(dst)) {
for (isize i = 0; i < dst->Record.field_count; i++) { for (isize i = 1; i < dst->Record.variant_count; i++) {
Entity *f = dst->Record.fields[i]; Entity *f = dst->Record.variants[i];
if (are_types_identical(f->type, src_type)) { if (are_types_identical(f->type, src_type)) {
ir_emit_comment(proc, str_lit("union - child to parent")); ir_emit_comment(proc, str_lit("union - child to parent"));
gbAllocator allocator = proc->module->allocator; gbAllocator allocator = proc->module->allocator;
irValue *parent = ir_add_local_generated(proc, t); irValue *parent = ir_add_local_generated(proc, t);
irValue *tag = ir_make_const_int(allocator, i); irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
ir_emit_store(proc, ir_emit_union_tag_ptr(proc, parent), tag); ir_emit_store(proc, tag_ptr, ir_make_const_int(allocator, i));
irValue *data = ir_emit_conv(proc, parent, t_rawptr); irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(allocator, src_type));
Type *tag_type = src_type;
Type *tag_type_ptr = make_type_pointer(allocator, tag_type);
irValue *underlying = ir_emit_bitcast(proc, data, tag_type_ptr);
ir_emit_store(proc, underlying, value); ir_emit_store(proc, underlying, value);
return ir_emit_load(proc, parent); return ir_emit_load(proc, parent);
@@ -2515,8 +2531,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 *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value));
irValue *dst_tag = NULL; irValue *dst_tag = NULL;
for (isize i = 1; i < src->Record.field_count; i++) { for (isize i = 1; i < src->Record.variant_count; i++) {
Entity *f = src->Record.fields[i]; Entity *f = src->Record.variants[i];
if (are_types_identical(f->type, dst)) { if (are_types_identical(f->type, dst)) {
dst_tag = ir_make_const_int(a, i); dst_tag = ir_make_const_int(a, i);
break; break;
@@ -2546,10 +2562,12 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
Type *dst = tuple->Tuple.variables[0]->type; Type *dst = tuple->Tuple.variables[0]->type;
Type *dst_ptr = make_type_pointer(a, dst); Type *dst_ptr = make_type_pointer(a, dst);
irValue *tag = ir_emit_union_tag_value(proc, value); irValue *value_ = ir_address_from_load_or_generate_local(proc, value);
irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_));
irValue *dst_tag = NULL; irValue *dst_tag = NULL;
for (isize i = 1; i < src->Record.field_count; i++) { for (isize i = 1; i < src->Record.variant_count; i++) {
Entity *f = src->Record.fields[i]; Entity *f = src->Record.variants[i];
if (are_types_identical(f->type, dst)) { if (are_types_identical(f->type, dst)) {
dst_tag = ir_make_const_int(a, i); dst_tag = ir_make_const_int(a, i);
break; break;
@@ -2557,8 +2575,6 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
} }
GB_ASSERT(dst_tag != NULL); GB_ASSERT(dst_tag != NULL);
irValue *union_ptr = ir_address_from_load_or_generate_local(proc, value);
irBlock *ok_block = ir_new_block(proc, NULL, "union_cast.ok"); irBlock *ok_block = ir_new_block(proc, NULL, "union_cast.ok");
irBlock *end_block = ir_new_block(proc, NULL, "union_cast.end"); irBlock *end_block = ir_new_block(proc, NULL, "union_cast.end");
irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag); irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag);
@@ -2568,13 +2584,12 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
irValue *gep0 = ir_emit_struct_ep(proc, v, 0); irValue *gep0 = ir_emit_struct_ep(proc, v, 0);
irValue *gep1 = ir_emit_struct_ep(proc, v, 1); irValue *gep1 = ir_emit_struct_ep(proc, v, 1);
irValue *data = ir_emit_load(proc, ir_emit_conv(proc, union_ptr, dst_ptr)); irValue *data = ir_emit_load(proc, ir_emit_conv(proc, value_, ir_type(gep0)));
ir_emit_store(proc, gep0, data); ir_emit_store(proc, gep0, data);
ir_emit_store(proc, gep1, v_true); ir_emit_store(proc, gep1, v_true);
ir_emit_jump(proc, end_block); ir_emit_jump(proc, end_block);
ir_start_block(proc, end_block); ir_start_block(proc, end_block);
} }
if (!is_tuple) { if (!is_tuple) {
@@ -2629,10 +2644,20 @@ isize ir_type_info_index(CheckerInfo *info, Type *type) {
return entry_index; return entry_index;
} }
// TODO(bill): Try and make a lot of this constant aggregate literals in LLVM IR
gb_global irValue *ir_global_type_info_data = NULL;
gb_global irValue *ir_global_type_info_member_types = NULL;
gb_global irValue *ir_global_type_info_member_names = NULL;
gb_global irValue *ir_global_type_info_member_offsets = NULL;
gb_global i32 ir_global_type_info_data_index = 0;
gb_global i32 ir_global_type_info_member_types_index = 0;
gb_global i32 ir_global_type_info_member_names_index = 0;
gb_global i32 ir_global_type_info_member_offsets_index = 0;
irValue *ir_type_info(irProcedure *proc, Type *type) { irValue *ir_type_info(irProcedure *proc, Type *type) {
irValue **found = map_ir_value_get(&proc->module->members, hash_string(str_lit(IR_TYPE_INFO_DATA_NAME)));
GB_ASSERT(found != NULL);
irValue *type_info_data = *found;
CheckerInfo *info = proc->module->info; CheckerInfo *info = proc->module->info;
type = default_type(type); type = default_type(type);
@@ -2641,7 +2666,7 @@ irValue *ir_type_info(irProcedure *proc, Type *type) {
// gb_printf_err("%d %s\n", entry_index, type_to_string(type)); // gb_printf_err("%d %s\n", entry_index, type_to_string(type));
return ir_emit_array_ep(proc, type_info_data, ir_make_const_i32(proc->module->allocator, entry_index)); return ir_emit_array_ep(proc, ir_global_type_info_data, ir_make_const_i32(proc->module->allocator, entry_index));
} }
@@ -2780,10 +2805,9 @@ void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
if (is_type_union(e->type)) { if (is_type_union(e->type)) {
Type *bt = base_type(e->type); Type *bt = base_type(e->type);
TypeRecord *s = &bt->Record;
// NOTE(bill): Zeroth entry is null (for `match type` stmts) // NOTE(bill): Zeroth entry is null (for `match type` stmts)
for (isize j = 1; j < s->field_count; j++) { for (isize j = 1; j < bt->Record.variant_count; j++) {
ir_mangle_sub_type_name(m, s->fields[j], name); ir_mangle_sub_type_name(m, bt->Record.variants[j], name);
} }
} }
} }
@@ -4191,7 +4215,10 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
} break; } break;
case Type_Record: { case Type_Record: {
GB_ASSERT(is_type_struct(bt)); // TODO(bill): "constant" unions are not initialized constantly at the moment.
// NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR
bool is_union = is_type_union(bt);
GB_ASSERT(is_type_struct(bt) || is_type_union(bt));
TypeRecord *st = &bt->Record; TypeRecord *st = &bt->Record;
if (cl->elems.count > 0) { if (cl->elems.count > 0) {
ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr))); ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
@@ -4214,7 +4241,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
} }
field = st->fields[index]; field = st->fields[index];
if (ir_is_elem_const(proc->module, elem, field->type)) { if (!is_union && ir_is_elem_const(proc->module, elem, field->type)) {
continue; continue;
} }
@@ -5420,10 +5447,10 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
irValue *index = NULL; irValue *index = NULL;
Type *ut = base_type(type_deref(ir_type(parent))); Type *ut = base_type(type_deref(ir_type(parent)));
GB_ASSERT(ut->Record.kind == TypeRecord_Union); GB_ASSERT(ut->Record.kind == TypeRecord_Union);
for (isize field_index = 1; field_index < ut->Record.field_count; field_index++) { for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) {
Entity *f = ut->Record.fields[field_index]; Entity *f = ut->Record.variants[variant_index];
if (are_types_identical(f->type, bt)) { if (are_types_identical(f->type, bt)) {
index = ir_make_const_int(allocator, field_index); index = ir_make_const_int(allocator, variant_index);
break; break;
} }
} }
@@ -5751,13 +5778,25 @@ void ir_init_module(irModule *m, Checker *c) {
{ {
// Add type info data // Add type info data
{ {
isize max_index = -1;
for_array(type_info_map_index, m->info->type_info_map.entries) {
MapIsizeEntry *entry = &m->info->type_info_map.entries.e[type_info_map_index];
Type *t = cast(Type *)cast(uintptr)entry->key.key;
t = default_type(t);
isize entry_index = ir_type_info_index(m->info, t);
if (max_index < entry_index) {
max_index = entry_index;
}
}
isize max_type_info_count = max_index+1;
String name = str_lit(IR_TYPE_INFO_DATA_NAME); String name = str_lit(IR_TYPE_INFO_DATA_NAME);
isize count = c->info.type_info_map.entries.count; Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), make_type_array(m->allocator, t_type_info, max_type_info_count), false);
Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), make_type_array(m->allocator, t_type_info, count), false);
irValue *g = ir_make_value_global(m->allocator, e, NULL); irValue *g = ir_make_value_global(m->allocator, e, NULL);
g->Global.is_private = true; g->Global.is_private = true;
ir_module_add_value(m, e, g); ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g); map_ir_value_set(&m->members, hash_string(name), g);
ir_global_type_info_data = g;
} }
// Type info member buffer // Type info member buffer
@@ -5775,6 +5814,11 @@ void ir_init_module(irModule *m, Checker *c) {
case TypeRecord_Struct: case TypeRecord_Struct:
case TypeRecord_RawUnion: case TypeRecord_RawUnion:
count += t->Record.field_count; count += t->Record.field_count;
break;
case TypeRecord_Union:
count += t->Record.field_count;
count += t->Record.variant_count;
break;
} }
break; break;
case Type_Tuple: case Type_Tuple:
@@ -5790,6 +5834,7 @@ void ir_init_module(irModule *m, Checker *c) {
irValue *g = ir_make_value_global(m->allocator, e, NULL); irValue *g = ir_make_value_global(m->allocator, e, NULL);
ir_module_add_value(m, e, g); ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g); map_ir_value_set(&m->members, hash_string(name), g);
ir_global_type_info_member_types = g;
} }
{ {
String name = str_lit(IR_TYPE_INFO_NAMES_NAME); String name = str_lit(IR_TYPE_INFO_NAMES_NAME);
@@ -5798,6 +5843,7 @@ void ir_init_module(irModule *m, Checker *c) {
irValue *g = ir_make_value_global(m->allocator, e, NULL); irValue *g = ir_make_value_global(m->allocator, e, NULL);
ir_module_add_value(m, e, g); ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g); map_ir_value_set(&m->members, hash_string(name), g);
ir_global_type_info_member_names = g;
} }
{ {
String name = str_lit(IR_TYPE_INFO_OFFSETS_NAME); String name = str_lit(IR_TYPE_INFO_OFFSETS_NAME);
@@ -5806,6 +5852,7 @@ void ir_init_module(irModule *m, Checker *c) {
irValue *g = ir_make_value_global(m->allocator, e, NULL); irValue *g = ir_make_value_global(m->allocator, e, NULL);
ir_module_add_value(m, e, g); ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g); map_ir_value_set(&m->members, hash_string(name), g);
ir_global_type_info_member_offsets = g;
} }
} }
} }
@@ -5912,18 +5959,36 @@ String ir_mangle_name(irGen *s, String path, Entity *e) {
return make_string(new_name, new_name_len-1); return make_string(new_name, new_name_len-1);
} }
irValue *ir_get_type_info_ptr(irProcedure *proc, irValue *type_info_data, Type *type) {
//
// Type Info stuff
//
irValue *ir_get_type_info_ptr(irProcedure *proc, Type *type) {
i32 index = cast(i32)ir_type_info_index(proc->module->info, type); i32 index = cast(i32)ir_type_info_index(proc->module->info, type);
// gb_printf_err("%d %s\n", index, type_to_string(type)); // gb_printf_err("%d %s\n", index, type_to_string(type));
irValue *ptr = ir_emit_array_epi(proc, type_info_data, index); irValue *ptr = ir_emit_array_epi(proc, ir_global_type_info_data, index);
return ir_emit_bitcast(proc, ptr, t_type_info_ptr); return ir_emit_bitcast(proc, ptr, t_type_info_ptr);
} }
irValue *ir_type_info_member_offset(irProcedure *proc, irValue *data, isize count, i32 *index) { irValue *ir_type_info_member_types_offset(irProcedure *proc, isize count) {
irValue *offset = ir_emit_array_epi(proc, data, *index); irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_types, ir_global_type_info_member_types_index);
*index += count; ir_global_type_info_member_types_index += count;
return offset; return offset;
} }
irValue *ir_type_info_member_names_offset(irProcedure *proc, isize count) {
irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_names, ir_global_type_info_member_names_index);
ir_global_type_info_member_names_index += count;
return offset;
}
irValue *ir_type_info_member_offsets_offset(irProcedure *proc, isize count) {
irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_offsets, ir_global_type_info_member_offsets_index);
ir_global_type_info_member_offsets_index += count;
return offset;
}
void ir_add_foreign_library_path(irModule *m, Entity *e) { void ir_add_foreign_library_path(irModule *m, Entity *e) {
GB_ASSERT(e != NULL); GB_ASSERT(e != NULL);
@@ -6285,25 +6350,13 @@ void ir_gen_tree(irGen *s) {
} }
{ // NOTE(bill): Setup type_info data { // NOTE(bill): Setup type_info data
// TODO(bill): Try and make a lot of this constant aggregate literals in LLVM IR
irValue *type_info_data = NULL;
irValue *type_info_member_types = NULL;
irValue *type_info_member_names = NULL;
irValue *type_info_member_offsets = NULL;
irValue **found = NULL;
type_info_data = *map_ir_value_get(&proc->module->members, hash_string(str_lit(IR_TYPE_INFO_DATA_NAME)));
type_info_member_types = *map_ir_value_get(&proc->module->members, hash_string(str_lit(IR_TYPE_INFO_TYPES_NAME)));
type_info_member_names = *map_ir_value_get(&proc->module->members, hash_string(str_lit(IR_TYPE_INFO_NAMES_NAME)));
type_info_member_offsets = *map_ir_value_get(&proc->module->members, hash_string(str_lit(IR_TYPE_INFO_OFFSETS_NAME)));
CheckerInfo *info = proc->module->info; CheckerInfo *info = proc->module->info;
if (false) { if (true) {
irValue *global_type_infos = ir_find_global_variable(proc, str_lit("__type_infos")); irValue *global_type_infos = ir_find_global_variable(proc, str_lit("__type_infos"));
Type *type = base_type(type_deref(ir_type(type_info_data))); Type *type = base_type(type_deref(ir_type(ir_global_type_info_data)));
GB_ASSERT(is_type_array(type)); GB_ASSERT(is_type_array(type));
irValue *array_data = ir_emit_array_epi(proc, type_info_data, 0); irValue *array_data = ir_emit_array_epi(proc, ir_global_type_info_data, 0);
irValue *array_count = ir_make_const_int(proc->module->allocator, type->Array.count); irValue *array_count = ir_make_const_int(proc->module->allocator, type->Array.count);
ir_emit_store(proc, ir_emit_struct_ep(proc, global_type_infos, 0), array_data); ir_emit_store(proc, ir_emit_struct_ep(proc, global_type_infos, 0), array_data);
@@ -6323,10 +6376,10 @@ void ir_gen_tree(irGen *s) {
MapIsizeEntry *entry = &info->type_info_map.entries.e[type_info_map_index]; MapIsizeEntry *entry = &info->type_info_map.entries.e[type_info_map_index];
Type *t = cast(Type *)cast(uintptr)entry->key.key; Type *t = cast(Type *)cast(uintptr)entry->key.key;
t = default_type(t); t = default_type(t);
isize entry_index = entry->value; isize entry_index = ir_type_info_index(info, t);
irValue *tag = NULL; irValue *tag = NULL;
irValue *ti_ptr = ir_emit_array_epi(proc, type_info_data, entry_index); irValue *ti_ptr = ir_emit_array_epi(proc, ir_global_type_info_data, entry_index);
switch (t->kind) { switch (t->kind) {
@@ -6336,7 +6389,7 @@ void ir_gen_tree(irGen *s) {
// TODO(bill): Which is better? The mangled name or actual name? // TODO(bill): Which is better? The mangled name or actual name?
irValue *name = ir_make_const_string(a, t->Named.type_name->token.string); irValue *name = ir_make_const_string(a, t->Named.type_name->token.string);
irValue *gtip = ir_get_type_info_ptr(proc, type_info_data, t->Named.base); irValue *gtip = ir_get_type_info_ptr(proc, t->Named.base);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), name); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), name);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), gtip); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), gtip);
@@ -6395,13 +6448,13 @@ void ir_gen_tree(irGen *s) {
case Type_Pointer: { case Type_Pointer: {
ir_emit_comment(proc, str_lit("Type_Info_Pointer")); ir_emit_comment(proc, str_lit("Type_Info_Pointer"));
tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr); tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr);
irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Pointer.elem); irValue *gep = ir_get_type_info_ptr(proc, t->Pointer.elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep);
} break; } break;
case Type_Array: { case Type_Array: {
ir_emit_comment(proc, str_lit("Type_Info_Array")); ir_emit_comment(proc, str_lit("Type_Info_Array"));
tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr); tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr);
irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Array.elem); irValue *gep = ir_get_type_info_ptr(proc, t->Array.elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep);
isize ez = type_size_of(a, t->Array.elem); isize ez = type_size_of(a, t->Array.elem);
@@ -6415,7 +6468,7 @@ void ir_gen_tree(irGen *s) {
case Type_DynamicArray: { case Type_DynamicArray: {
ir_emit_comment(proc, str_lit("Type_Info_DynamicArray")); ir_emit_comment(proc, str_lit("Type_Info_DynamicArray"));
tag = ir_emit_conv(proc, ti_ptr, t_type_info_dynamic_array_ptr); tag = ir_emit_conv(proc, ti_ptr, t_type_info_dynamic_array_ptr);
irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->DynamicArray.elem); irValue *gep = ir_get_type_info_ptr(proc, t->DynamicArray.elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep);
isize ez = type_size_of(a, t->DynamicArray.elem); isize ez = type_size_of(a, t->DynamicArray.elem);
@@ -6425,7 +6478,7 @@ void ir_gen_tree(irGen *s) {
case Type_Slice: { case Type_Slice: {
ir_emit_comment(proc, str_lit("Type_Info_Slice")); ir_emit_comment(proc, str_lit("Type_Info_Slice"));
tag = ir_emit_conv(proc, ti_ptr, t_type_info_slice_ptr); tag = ir_emit_conv(proc, ti_ptr, t_type_info_slice_ptr);
irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Slice.elem); irValue *gep = ir_get_type_info_ptr(proc, t->Slice.elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep);
isize ez = type_size_of(a, t->Slice.elem); isize ez = type_size_of(a, t->Slice.elem);
@@ -6435,7 +6488,7 @@ void ir_gen_tree(irGen *s) {
case Type_Vector: { case Type_Vector: {
ir_emit_comment(proc, str_lit("Type_Info_Vector")); ir_emit_comment(proc, str_lit("Type_Info_Vector"));
tag = ir_emit_conv(proc, ti_ptr, t_type_info_vector_ptr); tag = ir_emit_conv(proc, ti_ptr, t_type_info_vector_ptr);
irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Vector.elem); irValue *gep = ir_get_type_info_ptr(proc, t->Vector.elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep);
isize ez = type_size_of(a, t->Vector.elem); isize ez = type_size_of(a, t->Vector.elem);
@@ -6454,10 +6507,10 @@ void ir_gen_tree(irGen *s) {
irValue *convention = ir_emit_struct_ep(proc, tag, 3); irValue *convention = ir_emit_struct_ep(proc, tag, 3);
if (t->Proc.params) { if (t->Proc.params) {
ir_emit_store(proc, params, ir_get_type_info_ptr(proc, type_info_data, t->Proc.params)); ir_emit_store(proc, params, ir_get_type_info_ptr(proc, t->Proc.params));
} }
if (t->Proc.results) { if (t->Proc.results) {
ir_emit_store(proc, results, ir_get_type_info_ptr(proc, type_info_data, t->Proc.results)); ir_emit_store(proc, results, ir_get_type_info_ptr(proc, t->Proc.results));
} }
ir_emit_store(proc, variadic, ir_make_const_bool(a, t->Proc.variadic)); ir_emit_store(proc, variadic, ir_make_const_bool(a, t->Proc.variadic));
ir_emit_store(proc, convention, ir_make_const_int(a, t->Proc.calling_convention)); ir_emit_store(proc, convention, ir_make_const_int(a, t->Proc.calling_convention));
@@ -6474,8 +6527,8 @@ void ir_gen_tree(irGen *s) {
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align); ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
} }
irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index); irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count);
irValue *memory_names = ir_type_info_member_offset(proc, type_info_member_names, t->Record.field_count, &type_info_member_names_index); irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count);
for (isize i = 0; i < t->Tuple.variable_count; i++) { for (isize i = 0; i < t->Tuple.variable_count; i++) {
// NOTE(bill): offset is not used for tuples // NOTE(bill): offset is not used for tuples
@@ -6514,15 +6567,15 @@ void ir_gen_tree(irGen *s) {
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 7), custom_align); ir_emit_store(proc, ir_emit_struct_ep(proc, record, 7), custom_align);
} }
irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index); irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count);
irValue *memory_names = ir_type_info_member_offset(proc, type_info_member_names, t->Record.field_count, &type_info_member_names_index); irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count);
irValue *memory_offsets = ir_type_info_member_offset(proc, type_info_member_offsets, t->Record.field_count, &type_info_member_offsets_index); irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet
for (isize source_index = 0; source_index < t->Record.field_count; source_index++) { for (isize source_index = 0; source_index < t->Record.field_count; source_index++) {
// TODO(bill): Order fields in source order not layout order // TODO(bill): Order fields in source order not layout order
Entity *f = t->Record.fields_in_src_order[source_index]; Entity *f = t->Record.fields_in_src_order[source_index];
irValue *tip = ir_get_type_info_ptr(proc, type_info_data, f->type); irValue *tip = ir_get_type_info_ptr(proc, f->type);
i64 foffset = t->Record.struct_offsets[f->Variable.field_index]; i64 foffset = t->Record.struct_offsets[f->Variable.field_index];
GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
@@ -6545,33 +6598,75 @@ void ir_gen_tree(irGen *s) {
case TypeRecord_Union: { case TypeRecord_Union: {
ir_emit_comment(proc, str_lit("Type_Info_Union")); ir_emit_comment(proc, str_lit("Type_Info_Union"));
tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr); tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr);
irValue *record = ir_emit_struct_ep(proc, tag, 0);
{ {
irValue *size = ir_make_const_int(a, type_size_of(a, t)); irValue *size = ir_make_const_int(a, type_size_of(a, t));
irValue *align = ir_make_const_int(a, type_align_of(a, t)); irValue *align = ir_make_const_int(a, type_align_of(a, t));
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size);
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
} }
irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index); {
irValue *memory_names = ir_type_info_member_offset(proc, type_info_member_names, t->Record.field_count, &type_info_member_names_index); irValue *common_fields = ir_emit_struct_ep(proc, tag, 0);
for (isize source_index = 1; source_index < t->Record.field_count; source_index++) { isize field_count = t->Record.field_count;
// TODO(bill): Order fields in source order not layout order irValue *memory_types = ir_type_info_member_types_offset(proc, field_count);
Entity *f = t->Record.fields[source_index]; irValue *memory_names = ir_type_info_member_names_offset(proc, field_count);
irValue *tip = ir_get_type_info_ptr(proc, type_info_data, f->type); irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, field_count);
irValue *index = ir_make_const_int(a, source_index);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet
if (f->token.string.len > 0) { for (isize field_index = 0; field_index < field_count; field_index++) {
irValue *name = ir_emit_ptr_offset(proc, memory_names, index); // TODO(bill): Order fields in source order not layout order
ir_emit_store(proc, name, ir_make_const_string(a, f->token.string)); Entity *f = t->Record.fields[field_index];
irValue *tip = ir_get_type_info_ptr(proc, f->type);
i64 foffset = t->Record.struct_offsets[f->Variable.field_index];
GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
irValue *index = ir_make_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_make_const_string(a, f->token.string));
}
ir_emit_store(proc, offset, ir_make_const_int(a, foffset));
} }
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 0), memory_types, ir_make_const_int(a, field_count));
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 1), memory_names, ir_make_const_int(a, field_count));
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 2), memory_offsets, ir_make_const_int(a, field_count));
} }
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count)); {
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_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++) {
Entity *f = t->Record.variants[variant_index+1]; // Skip zeroth
irValue *tip = ir_get_type_info_ptr(proc, f->type);
irValue *index = ir_make_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, f->type));
if (f->token.string.len > 0) {
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
}
}
irValue *count = ir_make_const_int(a, variant_count);
ir_fill_slice(proc, variant_names, memory_names, count);
ir_fill_slice(proc, variant_types, memory_types, count);
}
} break; } break;
case TypeRecord_RawUnion: { case TypeRecord_RawUnion: {
@@ -6586,9 +6681,9 @@ void ir_gen_tree(irGen *s) {
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align); ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
} }
irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index); irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count);
irValue *memory_names = ir_type_info_member_offset(proc, type_info_member_names, t->Record.field_count, &type_info_member_names_index); irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count);
irValue *memory_offsets = ir_type_info_member_offset(proc, type_info_member_offsets, t->Record.field_count, &type_info_member_offsets_index); irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
for (isize i = 0; i < t->Record.field_count; i++) { for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i]; Entity *f = t->Record.fields[i];
@@ -6672,9 +6767,9 @@ void ir_gen_tree(irGen *s) {
irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2); irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2);
irValue *count = ir_emit_struct_ep(proc, tag, 3); irValue *count = ir_emit_struct_ep(proc, tag, 3);
ir_emit_store(proc, key, ir_get_type_info_ptr(proc, type_info_data, t->Map.key)); ir_emit_store(proc, key, ir_get_type_info_ptr(proc, t->Map.key));
ir_emit_store(proc, value, ir_get_type_info_ptr(proc, type_info_data, t->Map.value)); ir_emit_store(proc, value, ir_get_type_info_ptr(proc, t->Map.value));
ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, type_info_data, t->Map.generated_struct_type)); ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, t->Map.generated_struct_type));
ir_emit_store(proc, count, ir_make_const_int(a, t->Map.count)); ir_emit_store(proc, count, ir_make_const_int(a, t->Map.count));
} break; } break;
} }
@@ -6682,10 +6777,11 @@ void ir_gen_tree(irGen *s) {
if (tag != NULL) { if (tag != NULL) {
Type *tag_type = type_deref(ir_type(tag)); Type *tag_type = type_deref(ir_type(tag));
GB_ASSERT(is_type_named(tag_type));
Type *ti = base_type(t_type_info); Type *ti = base_type(t_type_info);
bool found = false; bool found = false;
for (isize i = 1; i < ti->Record.field_count; i++) { for (isize i = 1; i < ti->Record.variant_count; i++) {
Entity *f = ti->Record.fields[i]; Entity *f = ti->Record.variants[i];
if (are_types_identical(f->type, tag_type)) { if (are_types_identical(f->type, tag_type)) {
found = true; found = true;
irValue *tag = ir_make_const_int(a, i); irValue *tag = ir_make_const_int(a, i);
@@ -6695,6 +6791,8 @@ void ir_gen_tree(irGen *s) {
} }
} }
GB_ASSERT_MSG(found, "%s", type_to_string(tag_type)); GB_ASSERT_MSG(found, "%s", type_to_string(tag_type));
} else {
GB_PANIC("Unhandled Type_Info type: %s", type_to_string(t));
} }
} }
} }
@@ -6702,6 +6800,20 @@ void ir_gen_tree(irGen *s) {
ir_end_procedure_body(proc); ir_end_procedure_body(proc);
} }
for_array(type_info_map_index, info->type_info_map.entries) {
MapIsizeEntry *entry = &info->type_info_map.entries.e[type_info_map_index];
Type *t = cast(Type *)cast(uintptr)entry->key.key;
t = default_type(t);
isize entry_index = entry->value;
gbString s = type_to_string(t);
GB_ASSERT(s[0] != 0);
// gb_printf_err("%s\n", s);
}
for_array(i, m->procs_to_generate) { for_array(i, m->procs_to_generate) {
ir_build_proc(m->procs_to_generate.e[i], m->procs_to_generate.e[i]->Proc.parent); ir_build_proc(m->procs_to_generate.e[i], m->procs_to_generate.e[i]->Proc.parent);
} }
+1 -1
View File
@@ -191,7 +191,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
case Type_Slice: case Type_Slice:
ir_fprintf(f, "{"); ir_fprintf(f, "{");
ir_print_type(f, m, t->Slice.elem); ir_print_type(f, m, t->Slice.elem);
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits); ir_fprintf(f, "*, i%lld}", word_bits);
return; return;
case Type_DynamicArray: case Type_DynamicArray:
ir_fprintf(f, "{"); ir_fprintf(f, "{");
+39 -12
View File
@@ -349,9 +349,10 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
AstNode *align; \ AstNode *align; \
}) \ }) \
AST_NODE_KIND(UnionType, "union type", struct { \ AST_NODE_KIND(UnionType, "union type", struct { \
Token token; \ Token token; \
AstNodeArray fields; \ AstNodeArray fields; \
isize field_count; \ isize field_count; \
AstNodeArray variants; \
}) \ }) \
AST_NODE_KIND(RawUnionType, "raw union type", struct { \ AST_NODE_KIND(RawUnionType, "raw union type", struct { \
Token token; \ Token token; \
@@ -1040,11 +1041,12 @@ AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize fie
} }
AstNode *ast_union_type(AstFile *f, Token token, AstNodeArray fields, isize field_count) { AstNode *ast_union_type(AstFile *f, Token token, AstNodeArray fields, isize field_count, AstNodeArray variants) {
AstNode *result = make_ast_node(f, AstNode_UnionType); AstNode *result = make_ast_node(f, AstNode_UnionType);
result->UnionType.token = token; result->UnionType.token = token;
result->UnionType.fields = fields; result->UnionType.fields = fields;
result->UnionType.field_count = field_count; result->UnionType.field_count = field_count;
result->UnionType.variants = variants;
return result; return result;
} }
@@ -2682,29 +2684,54 @@ AstNode *parse_type_or_ident(AstFile *f) {
case Token_union: { case Token_union: {
Token token = expect_token(f, Token_union); Token token = expect_token(f, Token_union);
Token open = expect_token_after(f, Token_OpenBrace, "union"); Token open = expect_token_after(f, Token_OpenBrace, "union");
AstNodeArray decls = make_ast_node_array(f);
AstNodeArray variants = make_ast_node_array(f); AstNodeArray variants = make_ast_node_array(f);
isize total_decl_name_count = 0;
while (f->curr_token.kind != Token_CloseBrace && while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) { f->curr_token.kind != Token_EOF) {
AstNode *name = parse_ident(f); u32 decl_flags = parse_field_prefixes(f);
Token open = expect_token(f, Token_OpenBrace); if (decl_flags != 0) {
isize decl_count = 0; AstNodeArray names = parse_ident_list(f);
AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union")); if (names.count == 0) {
Token close = expect_token(f, Token_CloseBrace); syntax_error(f->curr_token, "Empty field declaration");
}
array_add(&variants, ast_union_field(f, name, list)); u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
total_decl_name_count += names.count;
expect_token_after(f, Token_Colon, "field list");
AstNode *type = parse_var_type(f, false);
array_add(&decls, ast_field(f, names, type, set_flags));
} else {
AstNodeArray names = parse_ident_list(f);
if (names.count == 0) {
break;
}
if (names.count > 1 || f->curr_token.kind == Token_Colon) {
u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
total_decl_name_count += names.count;
expect_token_after(f, Token_Colon, "field list");
AstNode *type = parse_var_type(f, false);
array_add(&decls, ast_field(f, names, type, set_flags));
} else {
AstNode *name = names.e[0];
Token open = expect_token(f, Token_OpenBrace);
isize decl_count = 0;
AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
Token close = expect_token(f, Token_CloseBrace);
array_add(&variants, ast_union_field(f, name, list));
}
}
if (f->curr_token.kind != Token_Comma) { if (f->curr_token.kind != Token_Comma) {
break; break;
} }
next_token(f); next_token(f);
} }
// AstNode *fields = parse_record_fields(f, &decl_count, 0, str_lit("union"));
Token close = expect_token(f, Token_CloseBrace); Token close = expect_token(f, Token_CloseBrace);
return ast_union_type(f, token, variants, variants.count); return ast_union_type(f, token, decls, total_decl_name_count, variants);
} }
case Token_raw_union: { case Token_raw_union: {
+83 -25
View File
@@ -89,12 +89,15 @@ typedef struct TypeRecord {
// All record types // All record types
// Theses are arrays // Theses are arrays
// Entity_Variable - struct/raw_union // Entity_Variable - struct/raw_union
// Entity_TypeName - union
// Entity_Constant - enum // Entity_Constant - enum
Entity **fields; Entity **fields;
i32 field_count; // == struct_offsets count i32 field_count; // == struct_offsets count
AstNode *node; AstNode *node;
// Entity_TypeName - union
Entity **variants;
i32 variant_count;
i64 * struct_offsets; i64 * struct_offsets;
bool struct_are_offsets_set; bool struct_are_offsets_set;
bool struct_is_packed; bool struct_is_packed;
@@ -301,8 +304,8 @@ gb_global Type *t_type_info_slice = NULL;
gb_global Type *t_type_info_vector = NULL; gb_global Type *t_type_info_vector = NULL;
gb_global Type *t_type_info_tuple = NULL; gb_global Type *t_type_info_tuple = NULL;
gb_global Type *t_type_info_struct = NULL; gb_global Type *t_type_info_struct = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_raw_union = NULL; gb_global Type *t_type_info_raw_union = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_enum = NULL; gb_global Type *t_type_info_enum = NULL;
gb_global Type *t_type_info_map = NULL; gb_global Type *t_type_info_map = NULL;
@@ -320,8 +323,8 @@ gb_global Type *t_type_info_slice_ptr = NULL;
gb_global Type *t_type_info_vector_ptr = NULL; gb_global Type *t_type_info_vector_ptr = NULL;
gb_global Type *t_type_info_tuple_ptr = NULL; gb_global Type *t_type_info_tuple_ptr = NULL;
gb_global Type *t_type_info_struct_ptr = NULL; gb_global Type *t_type_info_struct_ptr = NULL;
gb_global Type *t_type_info_union_ptr = NULL;
gb_global Type *t_type_info_raw_union_ptr = NULL; gb_global Type *t_type_info_raw_union_ptr = NULL;
gb_global Type *t_type_info_union_ptr = NULL;
gb_global Type *t_type_info_enum_ptr = NULL; gb_global Type *t_type_info_enum_ptr = NULL;
gb_global Type *t_type_info_map_ptr = NULL; gb_global Type *t_type_info_map_ptr = NULL;
@@ -858,6 +861,7 @@ bool are_types_identical(Type *x, Type *y) {
case TypeRecord_RawUnion: case TypeRecord_RawUnion:
case TypeRecord_Union: case TypeRecord_Union:
if (x->Record.field_count == y->Record.field_count && if (x->Record.field_count == y->Record.field_count &&
x->Record.variant_count == y->Record.variant_count &&
x->Record.struct_is_packed == y->Record.struct_is_packed && x->Record.struct_is_packed == y->Record.struct_is_packed &&
x->Record.struct_is_ordered == y->Record.struct_is_ordered && x->Record.struct_is_ordered == y->Record.struct_is_ordered &&
x->Record.custom_align == y->Record.custom_align) { x->Record.custom_align == y->Record.custom_align) {
@@ -870,9 +874,18 @@ bool are_types_identical(Type *x, Type *y) {
return false; return false;
} }
} }
for (isize i = 1; i < x->Record.variant_count; i++) {
if (!are_types_identical(x->Record.variants[i]->type, y->Record.variants[i]->type)) {
return false;
}
if (str_ne(x->Record.variants[i]->token.string, y->Record.variants[i]->token.string)) {
return false;
}
}
return true; return true;
} }
break; break;
case TypeRecord_Enum: case TypeRecord_Enum:
return x == y; // NOTE(bill): All enums are unique return x == y; // NOTE(bill): All enums are unique
} }
@@ -1331,14 +1344,12 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
} }
if (is_type_union(type)) { if (is_type_union(type)) {
// NOTE(bill): The subtype for a union are stored in the fields for (isize i = 1; i < type->Record.variant_count; i++) {
// as they are "kind of" like variables but not Entity *f = type->Record.variants[i];
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_TypeName); GB_ASSERT(f->kind == Entity_TypeName);
String str = f->token.string; String str = f->token.string;
if (str_eq(field_name, str)) { if (str_eq(str, field_name)) {
sel.entity = f; sel.entity = f;
// selection_add_index(&sel, i); // selection_add_index(&sel, i);
return sel; return sel;
@@ -1373,7 +1384,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
} }
} }
} }
} else if (!is_type_union(type)) { } else {
for (isize i = 0; i < type->Record.field_count; i++) { for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i]; Entity *f = type->Record.fields[i];
if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
@@ -1605,13 +1616,13 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
case TypeRecord_Union: { case TypeRecord_Union: {
i64 max = 1; i64 max = 1;
// NOTE(bill): field zero is null // NOTE(bill): field zero is null
for (isize i = 1; i < t->Record.field_count; i++) { for (isize i = 1; i < t->Record.variant_count; i++) {
Type *field_type = t->Record.fields[i]->type; Type *variant = t->Record.variants[i]->type;
type_path_push(path, field_type); type_path_push(path, variant);
if (path->failure) { if (path->failure) {
return FAILURE_ALIGNMENT; return FAILURE_ALIGNMENT;
} }
i64 align = type_align_of_internal(allocator, field_type, path); i64 align = type_align_of_internal(allocator, variant, path);
type_path_pop(path); type_path_pop(path);
if (max < align) { if (max < align) {
max = align; max = align;
@@ -1620,7 +1631,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
return max; return max;
} break; } break;
case TypeRecord_RawUnion: { case TypeRecord_RawUnion: {
i64 max = 1; i64 max = build_context.word_size;
for (isize i = 0; i < t->Record.field_count; i++) { for (isize i = 0; i < t->Record.field_count; i++) {
Type *field_type = t->Record.fields[i]->type; Type *field_type = t->Record.fields[i]->type;
type_path_push(path, field_type); type_path_push(path, field_type);
@@ -1653,7 +1664,6 @@ i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_cou
offsets[i] = curr_offset; offsets[i] = curr_offset;
curr_offset += type_size_of(allocator, fields[i]->type); curr_offset += type_size_of(allocator, fields[i]->type);
} }
} else { } else {
for (isize i = 0; i < field_count; i++) { for (isize i = 0; i < field_count; i++) {
i64 align = type_align_of(allocator, fields[i]->type); i64 align = type_align_of(allocator, fields[i]->type);
@@ -1673,7 +1683,13 @@ bool type_set_offsets(gbAllocator allocator, Type *t) {
t->Record.struct_are_offsets_set = true; t->Record.struct_are_offsets_set = true;
return true; return true;
} }
} else if (is_type_tuple(t)) { } else if (is_type_union(t)) {
if (!t->Record.struct_are_offsets_set) {
t->Record.struct_offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, false);
t->Record.struct_are_offsets_set = true;
return true;
}
} else if (is_type_tuple(t)) {
if (!t->Tuple.are_offsets_set) { if (!t->Tuple.are_offsets_set) {
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);
t->Tuple.are_offsets_set = true; t->Tuple.are_offsets_set = true;
@@ -1801,7 +1817,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
} break; } break;
case TypeRecord_Union: { case TypeRecord_Union: {
i64 count = t->Record.field_count; i64 count = t->Record.variant_count;
i64 align = type_align_of_internal(allocator, t, path); i64 align = type_align_of_internal(allocator, t, path);
if (path->failure) { if (path->failure) {
return FAILURE_SIZE; return FAILURE_SIZE;
@@ -1809,13 +1825,13 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
i64 max = 0; i64 max = 0;
// NOTE(bill): Zeroth field is invalid // NOTE(bill): Zeroth field is invalid
for (isize i = 1; i < count; i++) { for (isize i = 1; i < count; i++) {
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path); i64 size = type_size_of_internal(allocator, t->Record.variants[i]->type, path);
if (max < size) { if (max < size) {
max = size; max = size;
} }
} }
// NOTE(bill): Align to int // NOTE(bill): Align to int
isize size = align_formula(max, build_context.word_size); i64 size = align_formula(max, build_context.word_size);
size += type_size_of_internal(allocator, t_int, path); size += type_size_of_internal(allocator, t_int, path);
return align_formula(size, align); return align_formula(size, align);
} break; } break;
@@ -1983,8 +1999,9 @@ gbString write_type_to_string(gbString str, Type *type) {
for (isize i = 0; i < type->Record.field_count; i++) { for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i]; Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_Variable); GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) if (i > 0) {
str = gb_string_appendc(str, "; "); str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len); str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": "); str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type); str = write_type_to_string(str, f->type);
@@ -1994,16 +2011,38 @@ gbString write_type_to_string(gbString str, Type *type) {
case TypeRecord_Union: case TypeRecord_Union:
str = gb_string_appendc(str, "union{"); str = gb_string_appendc(str, "union{");
for (isize i = 1; i < type->Record.field_count; i++) { for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i]; Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_TypeName); GB_ASSERT(f->kind == Entity_Variable);
if (i > 1) { if (i > 0) {
str = gb_string_appendc(str, "; "); str = gb_string_appendc(str, ", ");
} }
str = gb_string_append_length(str, f->token.string.text, f->token.string.len); str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": "); str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, base_type(f->type)); str = write_type_to_string(str, base_type(f->type));
} }
for (isize i = 1; i < type->Record.variant_count; i++) {
Entity *f = type->Record.variants[i];
GB_ASSERT(f->kind == Entity_TypeName);
if (i > 1 || type->Record.field_count > 1) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, "{");
Type *variant = base_type(f->type);
for (isize i = 0; i < variant->Record.field_count; i++) {
Entity *f = variant->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, "{");
}
str = gb_string_appendc(str, "}"); str = gb_string_appendc(str, "}");
break; break;
@@ -2021,6 +2060,25 @@ gbString write_type_to_string(gbString str, Type *type) {
} }
str = gb_string_appendc(str, "}"); str = gb_string_appendc(str, "}");
break; break;
case TypeRecord_Enum:
str = gb_string_appendc(str, "enum");
if (type->Record.enum_base_type != NULL) {
str = gb_string_appendc(str, " ");
str = write_type_to_string(str, type->Record.enum_base_type);
}
str = gb_string_appendc(str, " {");
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_Constant);
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 = gb_string_appendc(str, "}");
break;
} }
} break; } break;