mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-22 13:44:59 -07:00
Union tag stored as an integer
This commit is contained in:
@@ -86,6 +86,7 @@ Type_Info_Struct :: struct #ordered {
|
||||
Type_Info_Union :: struct #ordered {
|
||||
variants: []^Type_Info,
|
||||
tag_offset: int,
|
||||
tag_type: ^Type_Info,
|
||||
};
|
||||
Type_Info_Enum :: struct #ordered {
|
||||
base: ^Type_Info,
|
||||
|
||||
+20
-5
@@ -920,11 +920,28 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
|
||||
case Type_Info_Union:
|
||||
data := cast(^u8)v.data;
|
||||
tipp := cast(^^Type_Info)(data + info.tag_offset);
|
||||
if data == nil || tipp == nil {
|
||||
tag_ptr := rawptr(data + info.tag_offset);
|
||||
tag_any := any{tag_ptr, info.tag_type};
|
||||
|
||||
tag: i64 = -1;
|
||||
switch i in tag_any {
|
||||
case u8: tag = i64(i);
|
||||
case i8: tag = i64(i);
|
||||
case u16: tag = i64(i);
|
||||
case i16: tag = i64(i);
|
||||
case u32: tag = i64(i);
|
||||
case i32: tag = i64(i);
|
||||
case u64: tag = i64(i);
|
||||
case i64: tag = i64(i);
|
||||
case u128: tag = i64(i);
|
||||
case i128: tag = i64(i);
|
||||
case: panic("Invalid union tag type");
|
||||
}
|
||||
|
||||
if data == nil || tag < 0 {
|
||||
write_string(fi.buf, "(union)");
|
||||
} else {
|
||||
ti := tipp^;
|
||||
ti := info.variants[tag-1];
|
||||
fmt_arg(fi, any{data, ti}, verb);
|
||||
}
|
||||
|
||||
@@ -1007,10 +1024,8 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
||||
case u64: fmt_int(fi, u128(a), false, 64, verb);
|
||||
case u128: fmt_int(fi, u128(a), false, 128, verb);
|
||||
|
||||
|
||||
case string: fmt_string(fi, a, verb);
|
||||
|
||||
|
||||
case: fmt_value(fi, arg, verb);
|
||||
}
|
||||
|
||||
|
||||
@@ -6472,12 +6472,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
str = gb_string_append_rune(str, '}');
|
||||
case_end;
|
||||
|
||||
// case_ast_node(st, RawUnionType, node);
|
||||
// str = gb_string_appendc(str, "raw_union ");
|
||||
// str = gb_string_append_rune(str, '{');
|
||||
// str = write_struct_fields_to_string(str, st->fields);
|
||||
// str = gb_string_append_rune(str, '}');
|
||||
// case_end;
|
||||
|
||||
case_ast_node(st, UnionType, node);
|
||||
str = gb_string_appendc(str, "union ");
|
||||
|
||||
@@ -304,6 +304,68 @@ i64 next_pow2(i64 n) {
|
||||
return n;
|
||||
}
|
||||
|
||||
i32 bit_set_count(u32 x) {
|
||||
x -= ((x >> 1) & 0x55555555);
|
||||
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
|
||||
x = (((x >> 4) + x) & 0x0f0f0f0f);
|
||||
x += (x >> 8);
|
||||
x += (x >> 16);
|
||||
|
||||
return cast(i32)(x & 0x0000003f);
|
||||
}
|
||||
|
||||
i64 bit_set_count(u64 x) {
|
||||
u32 a = *(cast(u32 *)&x);
|
||||
u32 b = *(cast(u32 *)&x + 1);
|
||||
return bit_set_count(a) + bit_set_count(b);
|
||||
}
|
||||
|
||||
u32 floor_log2(u32 x) {
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return cast(u32)(bit_set_count(x) - 1);
|
||||
}
|
||||
|
||||
u64 floor_log2(u64 x) {
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
x |= x >> 32;
|
||||
return cast(u64)(bit_set_count(x) - 1);
|
||||
}
|
||||
|
||||
|
||||
u32 ceil_log2(u32 x) {
|
||||
i32 y = cast(i32)(x & (x-1));
|
||||
y |= -y;
|
||||
y >>= 32-1;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return cast(u32)(bit_set_count(x) - 1 - y);
|
||||
}
|
||||
|
||||
u64 ceil_log2(u64 x) {
|
||||
i64 y = cast(i64)(x & (x-1));
|
||||
y |= -y;
|
||||
y >>= 64-1;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
x |= x >> 32;
|
||||
return cast(u64)(bit_set_count(x) - 1 - y);
|
||||
}
|
||||
|
||||
|
||||
i32 prev_pow2(i32 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
|
||||
+27
-97
@@ -966,7 +966,9 @@ irValue *ir_instr_union_tag_ptr(irProcedure *p, irValue *address) {
|
||||
irValue *v = ir_alloc_instr(p, irInstr_UnionTagPtr);
|
||||
irInstr *i = &v->Instr;
|
||||
i->UnionTagPtr.address = address;
|
||||
i->UnionTagPtr.type = make_type_pointer(p->module->allocator, t_type_info_ptr);
|
||||
// i->UnionTagPtr.type = make_type_pointer(p->module->allocator, t_type_info_ptr);
|
||||
Type *u = type_deref(ir_type(address));
|
||||
i->UnionTagPtr.type = make_type_pointer(p->module->allocator, union_tag_type(u));
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -974,7 +976,10 @@ irValue *ir_instr_union_tag_value(irProcedure *p, irValue *address) {
|
||||
irValue *v = ir_alloc_instr(p, irInstr_UnionTagValue);
|
||||
irInstr *i = &v->Instr;
|
||||
i->UnionTagValue.address = address;
|
||||
i->UnionTagValue.type = t_type_info_ptr;
|
||||
// i->UnionTagValue.type = t_type_info_ptr;
|
||||
// i->UnionTagValue.type = t_int;
|
||||
Type *u = type_deref(ir_type(address));
|
||||
i->UnionTagPtr.type = union_tag_type(u);
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -2236,10 +2241,6 @@ irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) {
|
||||
GB_ASSERT_MSG(is_type_pointer(t) &&
|
||||
is_type_union(type_deref(t)), "%s", type_to_string(t));
|
||||
irValue *tag_ptr = ir_emit(proc, ir_instr_union_tag_ptr(proc, u));
|
||||
Type *tpt = ir_type(tag_ptr);
|
||||
GB_ASSERT(is_type_pointer(tpt));
|
||||
tpt = base_type(type_deref(tpt));
|
||||
GB_ASSERT(tpt == t_type_info_ptr);
|
||||
return tag_ptr;
|
||||
}
|
||||
|
||||
@@ -2784,6 +2785,10 @@ irValue *ir_find_or_add_entity_string(irModule *m, String str) {
|
||||
}
|
||||
|
||||
|
||||
irValue *ir_const_union_tag(gbAllocator a, Type *u, Type *v) {
|
||||
return ir_value_constant(a, union_tag_type(u), exact_value_i64(union_variant_index(u, v)));
|
||||
}
|
||||
|
||||
|
||||
String ir_lookup_subtype_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) {
|
||||
Type *prev_src = src;
|
||||
@@ -3011,7 +3016,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
||||
ir_emit_store(proc, underlying, value);
|
||||
|
||||
irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
|
||||
ir_emit_store(proc, tag_ptr, ir_type_info(proc, vt));
|
||||
ir_emit_store(proc, tag_ptr, ir_const_union_tag(a, t, src_type));
|
||||
|
||||
return ir_emit_load(proc, parent);
|
||||
}
|
||||
@@ -3233,6 +3238,7 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) {
|
||||
gbAllocator a = proc->module->allocator;
|
||||
|
||||
@@ -3248,77 +3254,6 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
|
||||
|
||||
irValue *v = ir_add_local_generated(proc, tuple);
|
||||
|
||||
#if 0
|
||||
if (is_ptr) {
|
||||
Type *src = base_type(type_deref(src_type));
|
||||
Type *src_ptr = src_type;
|
||||
GB_ASSERT(is_type_union(src));
|
||||
Type *dst_ptr = tuple->Tuple.variables[0]->type;
|
||||
Type *dst = type_deref(dst_ptr);
|
||||
|
||||
irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value));
|
||||
irValue *dst_tag = nullptr;
|
||||
for (isize i = 1; i < src->Struct.variant_count; i++) {
|
||||
Type *vt = src->Struct.variants[i];
|
||||
if (are_types_identical(vt, dst)) {
|
||||
dst_tag = ir_const_int(a, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
GB_ASSERT(dst_tag != nullptr);
|
||||
|
||||
irBlock *ok_block = ir_new_block(proc, nullptr, "union_cast.ok");
|
||||
irBlock *end_block = ir_new_block(proc, nullptr, "union_cast.end");
|
||||
irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag);
|
||||
ir_emit_if(proc, cond, ok_block, end_block);
|
||||
ir_start_block(proc, ok_block);
|
||||
|
||||
irValue *gep0 = ir_emit_struct_ep(proc, v, 0);
|
||||
irValue *gep1 = ir_emit_struct_ep(proc, v, 1);
|
||||
|
||||
irValue *data = ir_emit_conv(proc, value, dst_ptr);
|
||||
ir_emit_store(proc, gep0, data);
|
||||
ir_emit_store(proc, gep1, v_true);
|
||||
|
||||
ir_emit_jump(proc, end_block);
|
||||
ir_start_block(proc, end_block);
|
||||
|
||||
} else {
|
||||
Type *src = base_type(src_type);
|
||||
GB_ASSERT(is_type_union(src));
|
||||
Type *dst = tuple->Tuple.variables[0]->type;
|
||||
Type *dst_ptr = make_type_pointer(a, dst);
|
||||
|
||||
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 = nullptr;
|
||||
for (isize i = 1; i < src->Struct.variant_count; i++) {
|
||||
Type *vt = src->Struct.variants[i];
|
||||
if (are_types_identical(vt, dst)) {
|
||||
dst_tag = ir_const_int(a, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
GB_ASSERT(dst_tag != nullptr);
|
||||
|
||||
irBlock *ok_block = ir_new_block(proc, nullptr, "union_cast.ok");
|
||||
irBlock *end_block = ir_new_block(proc, nullptr, "union_cast.end");
|
||||
irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag);
|
||||
ir_emit_if(proc, cond, ok_block, end_block);
|
||||
ir_start_block(proc, ok_block);
|
||||
|
||||
irValue *gep0 = ir_emit_struct_ep(proc, v, 0);
|
||||
irValue *gep1 = ir_emit_struct_ep(proc, v, 1);
|
||||
|
||||
irValue *data = ir_emit_load(proc, ir_emit_conv(proc, value_, ir_type(gep0)));
|
||||
ir_emit_store(proc, gep0, data);
|
||||
ir_emit_store(proc, gep1, v_true);
|
||||
|
||||
ir_emit_jump(proc, end_block);
|
||||
ir_start_block(proc, end_block);
|
||||
}
|
||||
#else
|
||||
if (is_ptr) {
|
||||
value = ir_emit_load(proc, value);
|
||||
}
|
||||
@@ -3326,10 +3261,11 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
|
||||
GB_ASSERT(is_type_union(src));
|
||||
Type *dst = tuple->Tuple.variables[0]->type;
|
||||
|
||||
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 = ir_type_info(proc, dst);
|
||||
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 = ir_const_union_tag(a, src, dst);
|
||||
|
||||
|
||||
irBlock *ok_block = ir_new_block(proc, nullptr, "union_cast.ok");
|
||||
irBlock *end_block = ir_new_block(proc, nullptr, "union_cast.end");
|
||||
@@ -3346,7 +3282,7 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
|
||||
|
||||
ir_emit_jump(proc, end_block);
|
||||
ir_start_block(proc, end_block);
|
||||
#endif
|
||||
|
||||
if (!is_tuple) {
|
||||
// NOTE(bill): Panic on invalid conversion
|
||||
Type *dst_type = tuple->Tuple.variables[0]->type;
|
||||
@@ -7073,18 +7009,8 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
case_type = type_of_expr(proc->module->info, cc->list[type_index]);
|
||||
irValue *cond = nullptr;
|
||||
if (match_type_kind == MatchType_Union) {
|
||||
Type *bt = type_deref(case_type);
|
||||
irValue *variant_tag = nullptr;
|
||||
Type *ut = base_type(type_deref(parent_type));
|
||||
GB_ASSERT(ut->kind == Type_Union);
|
||||
for_array(variant_index, ut->Union.variants) {
|
||||
Type *vt = ut->Union.variants[variant_index];
|
||||
if (are_types_identical(vt, bt)) {
|
||||
variant_tag = ir_type_info(proc, vt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
GB_ASSERT(variant_tag != nullptr);
|
||||
irValue *variant_tag = ir_const_union_tag(proc->module->allocator, ut, case_type);
|
||||
cond = ir_emit_comp(proc, Token_CmpEq, tag_index, variant_tag);
|
||||
} else if (match_type_kind == MatchType_Any) {
|
||||
irValue *any_ti = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 1));
|
||||
@@ -8414,6 +8340,7 @@ void ir_gen_tree(irGen *s) {
|
||||
{
|
||||
irValue *variant_types = ir_emit_struct_ep(proc, tag, 0);
|
||||
irValue *tag_offset_ptr = ir_emit_struct_ep(proc, tag, 1);
|
||||
irValue *tag_type_ptr = ir_emit_struct_ep(proc, tag, 2);
|
||||
|
||||
isize variant_count = gb_max(0, t->Union.variants.count);
|
||||
irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count);
|
||||
@@ -8431,8 +8358,10 @@ void ir_gen_tree(irGen *s) {
|
||||
irValue *count = ir_const_int(a, variant_count);
|
||||
ir_fill_slice(proc, variant_types, memory_types, count, count);
|
||||
|
||||
i64 tag_offset = align_formula(t->Union.variant_block_size, build_context.word_size);
|
||||
i64 tag_size = union_tag_size(t);
|
||||
i64 tag_offset = align_formula(t->Union.variant_block_size, tag_size);
|
||||
ir_emit_store(proc, tag_offset_ptr, ir_const_int(a, tag_offset));
|
||||
ir_emit_store(proc, tag_type_ptr, ir_type_info(proc, union_tag_type(t)));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -8556,11 +8485,12 @@ void ir_gen_tree(irGen *s) {
|
||||
if (tag != nullptr) {
|
||||
Type *tag_type = type_deref(ir_type(tag));
|
||||
GB_ASSERT(is_type_named(tag_type));
|
||||
irValue *ti = ir_type_info(proc, tag_type);
|
||||
Type *variant_type = type_deref(ir_type(variant_ptr));
|
||||
irValue *tag = ir_const_union_tag(a, variant_type, tag_type);
|
||||
irValue *ptr = ir_emit_union_tag_ptr(proc, variant_ptr);
|
||||
ir_emit_store(proc, ptr, ti);
|
||||
ir_emit_store(proc, ptr, tag);
|
||||
} else {
|
||||
GB_PANIC("Unhandled TypeInfo type: %s", type_to_string(t));
|
||||
GB_PANIC("Unhandled Type_Info variant: %s", type_to_string(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -305,7 +305,8 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
|
||||
ir_fprintf(f, "[%lld x i8], ", block_size);
|
||||
ir_print_type(f, m, t_type_info_ptr);
|
||||
// ir_print_type(f, m, t_type_info_ptr);
|
||||
ir_print_type(f, m, union_tag_type(t));
|
||||
ir_write_byte(f, '}');
|
||||
}
|
||||
} return;
|
||||
|
||||
+39
-15
@@ -118,7 +118,6 @@ struct TypeStruct {
|
||||
Array<Type *> variants; \
|
||||
AstNode *node; \
|
||||
Scope * scope; \
|
||||
Entity * union__type_info; \
|
||||
i64 variant_block_size; \
|
||||
i64 custom_align; \
|
||||
}) \
|
||||
@@ -1335,6 +1334,42 @@ bool is_type_cte_safe(Type *type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i64 union_variant_index(Type *u, Type *v) {
|
||||
u = base_type(u);
|
||||
GB_ASSERT(u->kind == Type_Union);
|
||||
|
||||
for_array(i, u->Union.variants) {
|
||||
Type *vt = u->Union.variants[i];
|
||||
if (are_types_identical(v, vt)) {
|
||||
return cast(i64)(i+1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
i64 union_tag_size(Type *u) {
|
||||
u = base_type(u);
|
||||
GB_ASSERT(u->kind == Type_Union);
|
||||
u64 cl2 = ceil_log2(cast(u64)u->Union.variants.count);
|
||||
i64 s = (next_pow2(cast(i64)cl2) + 7)/8;
|
||||
return gb_clamp(s, 1, build_context.word_size);
|
||||
}
|
||||
|
||||
Type *union_tag_type(Type *u) {
|
||||
i64 s = union_tag_size(u);
|
||||
switch (s) {
|
||||
case 1: return t_u8;
|
||||
case 2: return t_u16;
|
||||
case 4: return t_u32;
|
||||
case 8: return t_u64;
|
||||
case 16: return t_u128;
|
||||
}
|
||||
GB_PANIC("Invalid union_tag_size");
|
||||
return t_int;
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum ProcTypeOverloadKind {
|
||||
ProcOverload_Identical, // The types are identical
|
||||
|
||||
@@ -1614,20 +1649,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
|
||||
} else if (type->kind == Type_Union) {
|
||||
if (field_name == "__type_info") {
|
||||
Entity *e = type->Union.union__type_info;
|
||||
if (e == nullptr) {
|
||||
Entity *__type_info = make_entity_field(a, nullptr, make_token_ident(str_lit("__type_info")), t_type_info_ptr, false, -1);
|
||||
type->Union.union__type_info = __type_info;
|
||||
e = __type_info;
|
||||
}
|
||||
|
||||
GB_ASSERT(e != nullptr);
|
||||
selection_add_index(&sel, -1); // HACK(bill): Leaky memory
|
||||
sel.entity = e;
|
||||
|
||||
return sel;
|
||||
}
|
||||
} else if (type->kind == Type_Struct) {
|
||||
for_array(i, type->Struct.fields) {
|
||||
Entity *f = type->Struct.fields[i];
|
||||
@@ -1854,7 +1876,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
if (t->Union.custom_align > 0) {
|
||||
return gb_clamp(t->Union.custom_align, 1, build_context.max_align);
|
||||
}
|
||||
i64 max = build_context.word_size;
|
||||
|
||||
|
||||
i64 max = union_tag_size(t);
|
||||
for_array(i, t->Union.variants) {
|
||||
Type *variant = t->Union.variants[i];
|
||||
type_path_push(path, variant);
|
||||
|
||||
Reference in New Issue
Block a user