Union tag stored as an integer

This commit is contained in:
Ginger Bill
2017-10-08 15:16:13 +01:00
parent 4e42d7df43
commit 6424966b7a
7 changed files with 151 additions and 124 deletions
+1
View File
@@ -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
View File
@@ -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);
}
-6
View File
@@ -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 ");
+62
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);