Browse Source

Mock out map get/set functionality

gingerBill 2 years ago
parent
commit
0c1b39d881
8 changed files with 299 additions and 21 deletions
  1. 17 1
      src/tilde.cpp
  2. 8 1
      src/tilde.hpp
  3. 129 0
      src/tilde_builtin.cpp
  4. 11 2
      src/tilde_const.cpp
  5. 93 10
      src/tilde_expr.cpp
  6. 5 1
      src/tilde_proc.cpp
  7. 33 3
      src/tilde_stmt.cpp
  8. 3 3
      src/tilde_type_info.cpp

+ 17 - 1
src/tilde.cpp

@@ -189,6 +189,19 @@ gb_internal cgAddr cg_addr(cgValue const &value) {
 	return addr;
 }
 
+gb_internal cgAddr cg_addr_map(cgValue addr, cgValue map_key, Type *map_type, Type *map_result) {
+	GB_ASSERT(is_type_pointer(addr.type));
+	Type *mt = type_deref(addr.type);
+	GB_ASSERT(is_type_map(mt));
+
+	cgAddr v = {cgAddr_Map, addr};
+	v.map.key    = map_key;
+	v.map.type   = map_type;
+	v.map.result = map_result;
+	return v;
+}
+
+
 gb_internal void cg_set_debug_pos_from_node(cgProcedure *p, Ast *node) {
 	if (node) {
 		TokenPos pos = ast_token(node).pos;
@@ -435,6 +448,8 @@ gb_internal cgModule *cg_module_create(Checker *c) {
 	map_init(&m->hasher_procs);
 	map_init(&m->map_get_procs);
 	map_init(&m->map_set_procs);
+	map_init(&m->map_info_map);
+	map_init(&m->map_cell_info_map);
 
 	array_init(&m->single_threaded_procedure_queue, heap_allocator());
 
@@ -461,6 +476,8 @@ gb_internal void cg_module_destroy(cgModule *m) {
 	map_destroy(&m->hasher_procs);
 	map_destroy(&m->map_get_procs);
 	map_destroy(&m->map_set_procs);
+	map_destroy(&m->map_info_map);
+	map_destroy(&m->map_cell_info_map);
 
 	array_free(&m->single_threaded_procedure_queue);
 
@@ -784,7 +801,6 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) {
 	}
 
 
-
 	TB_DebugFormat debug_format = TB_DEBUGFMT_NONE;
 	if (build_context.ODIN_DEBUG) {
 		switch (build_context.metrics.os) {

+ 8 - 1
src/tilde.hpp

@@ -237,6 +237,9 @@ struct cgModule {
 	PtrMap<Type *, cgProcedure *> map_get_procs;
 	PtrMap<Type *, cgProcedure *> map_set_procs;
 
+	RecursiveMutex map_info_mutex;
+	PtrMap<Type *, TB_Symbol *> map_info_map;
+	PtrMap<Type *, TB_Symbol *> map_cell_info_map;
 
 	// NOTE(bill): no need to protect this with a mutex
 	PtrMap<uintptr, TB_FileID> file_id_map; // Key: AstFile.id (i32 cast to uintptr)
@@ -289,6 +292,7 @@ gb_internal cgValue cg_value(TB_Symbol *  s,    Type *type);
 gb_internal cgValue cg_value(TB_Node *    node, Type *type);
 
 gb_internal cgAddr cg_addr(cgValue const &value);
+gb_internal cgAddr cg_addr_map(cgValue addr, cgValue map_key, Type *map_type, Type *map_result);
 
 gb_internal u64 cg_typeid_as_u64(cgModule *m, Type *type);
 gb_internal cgValue cg_type_info(cgProcedure *p, Type *type);
@@ -370,4 +374,7 @@ gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type,
 
 gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value);
 gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &x);
-
+gb_internal cgValue cg_builtin_map_info(cgProcedure *p, Type *map_type);
+gb_internal cgValue cg_builtin_map_cell_info(cgProcedure *p, Type *type);
+gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos);
+gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, Ast *node);

+ 129 - 0
src/tilde_builtin.cpp

@@ -231,6 +231,76 @@ gb_internal cgValue cg_builtin_mem_copy_non_overlapping(cgProcedure *p, cgValue
 	return dst;
 }
 
+gb_internal TB_Symbol *cg_builtin_map_cell_info_symbol(cgModule *m, Type *type) {
+	MUTEX_GUARD(&m->map_info_mutex);
+	TB_Symbol **found = map_get(&m->map_cell_info_map, type);
+	if (found) {
+		return *found;
+	}
+	i64 size = 0, len = 0;
+	map_cell_size_and_len(type, &size, &len);
+
+	TB_Global *global = tb_global_create(m->mod, 0, "", cg_debug_type(m, t_map_cell_info), TB_LINKAGE_PRIVATE);
+	tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(t_map_cell_info), type_align_of(t_map_cell_info), 4);
+
+	i64 ptr_size = build_context.ptr_size;
+	void *size_of_type      = tb_global_add_region(m->mod, global, 0*ptr_size, ptr_size);
+	void *align_of_type     = tb_global_add_region(m->mod, global, 1*ptr_size, ptr_size);
+	void *size_of_cell      = tb_global_add_region(m->mod, global, 2*ptr_size, ptr_size);
+	void *elements_per_cell = tb_global_add_region(m->mod, global, 3*ptr_size, ptr_size);
+
+	cg_write_uint_at_ptr(size_of_type,      type_size_of(type),  t_uintptr);
+	cg_write_uint_at_ptr(align_of_type,     type_align_of(type), t_uintptr);
+	cg_write_uint_at_ptr(size_of_cell,      size,                t_uintptr);
+	cg_write_uint_at_ptr(elements_per_cell, len,                 t_uintptr);
+
+	map_set(&m->map_cell_info_map, type, cast(TB_Symbol *)global);
+
+	return cast(TB_Symbol *)global;
+}
+
+
+gb_internal cgValue cg_builtin_map_cell_info(cgProcedure *p, Type *type) {
+	type = core_type(type);
+	TB_Symbol *symbol = cg_builtin_map_cell_info_symbol(p->module, type);
+	TB_Node *node = tb_inst_get_symbol_address(p->func, symbol);
+	return cg_value(node, t_map_cell_info_ptr);
+}
+
+gb_internal cgValue cg_builtin_map_info(cgProcedure *p, Type *map_type) {
+	map_type = base_type(map_type);
+	GB_ASSERT(map_type->kind == Type_Map);
+
+	cgModule *m = p->module;
+	MUTEX_GUARD(&m->map_info_mutex);
+	TB_Global *global = nullptr;
+	TB_Symbol **found = map_get(&m->map_info_map, map_type);
+	if (found) {
+		global = cast(TB_Global *)*found;
+	} else {
+		global = tb_global_create(m->mod, 0, "", cg_debug_type(m, t_map_info), TB_LINKAGE_PRIVATE);
+		tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(t_map_info), type_align_of(t_map_info), 4);
+
+		TB_Symbol *key_cell_info   = cg_builtin_map_cell_info_symbol(m, map_type->Map.key);
+		TB_Symbol *value_cell_info = cg_builtin_map_cell_info_symbol(m, map_type->Map.value);
+		cgProcedure *key_hasher    = cg_hasher_proc_for_type(p->module, map_type->Map.key);
+		cgProcedure *key_equal     = cg_equal_proc_for_type (p->module, map_type->Map.key);
+
+		tb_global_add_symbol_reloc(p->module->mod, global, 0*build_context.ptr_size, key_cell_info);
+		tb_global_add_symbol_reloc(p->module->mod, global, 1*build_context.ptr_size, value_cell_info);
+		tb_global_add_symbol_reloc(p->module->mod, global, 2*build_context.ptr_size, key_hasher->symbol);
+		tb_global_add_symbol_reloc(p->module->mod, global, 3*build_context.ptr_size, key_equal->symbol);
+
+		map_set(&m->map_info_map, map_type, cast(TB_Symbol *)global);
+	}
+
+	GB_ASSERT(global != nullptr);
+	TB_Node *node = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global);
+	return cg_value(node, t_map_info_ptr);
+}
+
+
+
 
 gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) {
 	ast_node(ce, CallExpr, expr);
@@ -434,6 +504,65 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr
 
 	case BuiltinProc_type_hasher_proc:
 		return cg_hasher_proc_value_for_type(p, ce->args[0]->tav.type);
+
+	case BuiltinProc_type_map_cell_info:
+		return cg_builtin_map_cell_info(p, ce->args[0]->tav.type);
+	case BuiltinProc_type_map_info:
+		return cg_builtin_map_info(p, ce->args[0]->tav.type);
+
+	case BuiltinProc_expect:
+		{
+			Type *t = default_type(expr->tav.type);
+			cgValue x = cg_emit_conv(p, cg_build_expr(p, ce->args[0]), t);
+			cgValue y = cg_emit_conv(p, cg_build_expr(p, ce->args[1]), t);
+			gb_unused(y);
+			return x;
+		}
+
+	case BuiltinProc_count_leading_zeros:
+		{
+			cgValue n = cg_build_expr(p, ce->args[0]);
+			n = cg_emit_conv(p, n, default_type(expr->tav.type));
+			GB_ASSERT(n.kind == cgValue_Value);
+			TB_Node *val = tb_inst_clz(p->func, n.node);
+			val = tb_inst_zxt(p->func, val, cg_data_type(n.type));
+			return cg_value(val, n.type);
+		}
+
+
+	case BuiltinProc_count_trailing_zeros:
+		{
+			cgValue n = cg_build_expr(p, ce->args[0]);
+			n = cg_emit_conv(p, n, default_type(expr->tav.type));
+			GB_ASSERT(n.kind == cgValue_Value);
+			TB_Node *val = tb_inst_ctz(p->func, n.node);
+			val = tb_inst_zxt(p->func, val, cg_data_type(n.type));
+			return cg_value(val, n.type);
+		}
+
+	case BuiltinProc_count_ones:
+		{
+			cgValue n = cg_build_expr(p, ce->args[0]);
+			n = cg_emit_conv(p, n, default_type(expr->tav.type));
+			GB_ASSERT(n.kind == cgValue_Value);
+			TB_Node *val = tb_inst_popcount(p->func, n.node);
+			val = tb_inst_zxt(p->func, val, cg_data_type(n.type));
+			return cg_value(val, n.type);
+		}
+
+	case BuiltinProc_count_zeros:
+		{
+			cgValue n = cg_build_expr(p, ce->args[0]);
+			n = cg_emit_conv(p, n, default_type(expr->tav.type));
+			GB_ASSERT(n.kind == cgValue_Value);
+			TB_DataType dt = cg_data_type(n.type);
+			TB_Node *ones = tb_inst_popcount(p->func, n.node);
+			ones = tb_inst_zxt(p->func, ones, dt);
+
+			cgValue size = cg_const_int(p, n.type, 8*type_size_of(n.type));
+			return cg_emit_arith(p, Token_Sub, size, cg_value(ones, n.type), n.type);
+		}
+
 	}
 
 

+ 11 - 2
src/tilde_const.cpp

@@ -96,7 +96,11 @@ gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, Strin
 	return cg_lvalue_addr(ptr, t_source_code_location);
 }
 
-
+gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, Ast *node) {
+	String proc_name = p->name;
+	TokenPos pos = ast_token(node).pos;
+	return cg_emit_source_code_location_as_global(p, proc_name, pos);
+}
 
 gb_internal void cg_write_big_int_at_ptr(void *dst, BigInt const *a, Type *original_type) {
 	GB_ASSERT(build_context.endian_kind == TargetEndian_Little);
@@ -949,7 +953,12 @@ gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const
 		GB_ASSERT(!TB_IS_VOID_TYPE(dt));
 		// GB_ASSERT(dt.raw != TB_TYPE_I128.raw);
 		if (is_type_unsigned(type)) {
-			u64 i = exact_value_to_u64(value);
+			u64 i = 0;
+			if (value.kind == ExactValue_Integer && value.value_integer.sign) {
+				i = exact_value_to_i64(value);
+			} else {
+				i = exact_value_to_u64(value);
+			}
 			return cg_value(tb_inst_uint(p->func, dt, i), type);
 		} else {
 			i64 i = exact_value_to_i64(value);

+ 93 - 10
src/tilde_expr.cpp

@@ -3416,9 +3416,93 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 	         token_pos_to_string(token_pos));
 
 	return {};
+}
+
+
+gb_internal cgValue cg_map_data_uintptr(cgProcedure *p, cgValue value) {
+	GB_ASSERT(is_type_map(value.type) || are_types_identical(value.type, t_raw_map));
+	cgValue data = cg_emit_struct_ev(p, value, 0);
+	u64 mask_value = 0;
+	if (build_context.ptr_size == 4) {
+		mask_value = 0xfffffffful & ~(MAP_CACHE_LINE_SIZE-1);
+	} else {
+		mask_value = 0xffffffffffffffffull & ~(MAP_CACHE_LINE_SIZE-1);
+	}
+	cgValue mask = cg_const_int(p, t_uintptr, mask_value);
+	return cg_emit_arith(p, Token_And, data, mask, t_uintptr);
+}
+
+gb_internal cgValue cg_gen_map_key_hash(cgProcedure *p, cgValue const &map_ptr, cgValue key, cgValue *key_ptr_) {
+	TEMPORARY_ALLOCATOR_GUARD();
+
+	cgValue key_ptr = cg_address_from_load_or_generate_local(p, key);
+	key_ptr = cg_emit_conv(p, key_ptr, t_rawptr);
 
+	if (key_ptr_) *key_ptr_ = key_ptr;
+
+	Type* key_type = base_type(type_deref(map_ptr.type))->Map.key;
+
+	cgValue hasher = cg_hasher_proc_value_for_type(p, key_type);
+
+	Slice<cgValue> args = {};
+	args = slice_make<cgValue>(temporary_allocator(), 1);
+	args[0] = cg_map_data_uintptr(p, cg_emit_load(p, map_ptr));
+	cgValue seed = cg_emit_runtime_call(p, "map_seed_from_map_data", args);
+
+	args = slice_make<cgValue>(temporary_allocator(), 2);
+	args[0] = key_ptr;
+	args[1] = seed;
+	return cg_emit_call(p, hasher, args);
 }
 
+gb_internal cgValue cg_internal_dynamic_map_get_ptr(cgProcedure *p, cgValue const &map_ptr, cgValue const &key) {
+	TEMPORARY_ALLOCATOR_GUARD();
+
+	Type *map_type = base_type(type_deref(map_ptr.type));
+	GB_ASSERT(map_type->kind == Type_Map);
+
+	cgValue ptr = {};
+	cgValue key_ptr = {};
+	cgValue hash = cg_gen_map_key_hash(p, map_ptr, key, &key_ptr);
+
+	auto args = slice_make<cgValue>(temporary_allocator(), 4);
+	args[0] = cg_emit_transmute(p, map_ptr, t_raw_map_ptr);
+	args[1] = cg_builtin_map_info(p, map_type);
+	args[2] = hash;
+	args[3] = key_ptr;
+
+	ptr = cg_emit_runtime_call(p, "__dynamic_map_get", args);
+
+	return cg_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
+}
+
+
+gb_internal void cg_internal_dynamic_map_set(cgProcedure *p, cgValue const &map_ptr, Type *map_type,
+                                             cgValue const &map_key, cgValue const &map_value, Ast *node) {
+	TEMPORARY_ALLOCATOR_GUARD();
+
+	map_type = base_type(map_type);
+	GB_ASSERT(map_type->kind == Type_Map);
+
+	cgValue key_ptr = {};
+	cgValue hash = cg_gen_map_key_hash(p, map_ptr, map_key, &key_ptr);
+
+	cgValue v = cg_emit_conv(p, map_value, map_type->Map.value);
+	cgValue value_ptr = cg_address_from_load_or_generate_local(p, v);
+
+	auto args = slice_make<cgValue>(temporary_allocator(), 6);
+	args[0] = cg_emit_conv(p, map_ptr, t_raw_map_ptr);
+	args[1] = cg_builtin_map_info(p, map_type);
+	args[2] = hash;
+	args[3] = cg_emit_conv(p, key_ptr, t_rawptr);
+	args[4] = cg_emit_conv(p, value_ptr, t_rawptr);
+	args[5] = cg_emit_source_code_location_as_global(p, node);
+	cg_emit_runtime_call(p, "__dynamic_map_set", args);
+}
+
+
+
+
 gb_internal cgValue cg_build_addr_ptr(cgProcedure *p, Ast *expr) {
 	cgAddr addr = cg_build_addr(p, expr);
 	return cg_addr_get_ptr(p, addr);
@@ -3501,17 +3585,16 @@ gb_internal cgAddr cg_build_addr_index_expr(cgProcedure *p, Ast *expr) {
 	GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr));
 
 	if (is_type_map(t)) {
-		GB_PANIC("TODO(bill): map indexing");
-		// lbAddr map_addr = lb_build_addr(p, ie->expr);
-		// lbValue key = lb_build_expr(p, ie->index);
-		// key = lb_emit_conv(p, key, t->Map.key);
+		cgAddr map_addr = cg_build_addr(p, ie->expr);
+		cgValue key = cg_build_expr(p, ie->index);
+		key = cg_emit_conv(p, key, t->Map.key);
 
-		// Type *result_type = type_of_expr(expr);
-		// lbValue map_ptr = lb_addr_get_ptr(p, map_addr);
-		// if (is_type_pointer(type_deref(map_ptr.type))) {
-		// 	map_ptr = lb_emit_load(p, map_ptr);
-		// }
-		// return lb_addr_map(map_ptr, key, t, result_type);
+		Type *result_type = type_of_expr(expr);
+		cgValue map_ptr = cg_addr_get_ptr(p, map_addr);
+		if (is_type_pointer(type_deref(map_ptr.type))) {
+			map_ptr = cg_emit_load(p, map_ptr);
+		}
+		return cg_addr_map(map_ptr, key, t, result_type);
 	}
 
 	switch (t->kind) {

+ 5 - 1
src/tilde_proc.cpp

@@ -388,7 +388,7 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) {
 
 	// emit ir
 	if (
-	    // string_starts_with(p->name, str_lit("bug@main")) ||
+	    string_starts_with(p->name, str_lit("main@")) ||
 	    // p->name == str_lit("runtime@_windows_default_alloc_or_resize") ||
 	    false
 	) { // IR Printing
@@ -398,6 +398,7 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) {
 
 		tb_pass_print(passes);
 		fprintf(stdout, "\n");
+		fflush(stdout);
 	}
 	if (false) { // GraphViz printing
 		tb_function_print(p->func, tb_default_print_callback, stdout);
@@ -408,6 +409,7 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) {
 	if (emit_asm) {
 		tb_output_print_asm(output, stdout);
 		fprintf(stdout, "\n");
+		fflush(stdout);
 	}
 
 	return 0;
@@ -1018,6 +1020,7 @@ gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type) {
 
 	cgProcedure *p = cg_procedure_create_dummy(m, proc_name, t_equal_proc);
 	map_set(&m->equal_procs, type, p);
+	p->split_returns_index = 2;
 
 	cg_procedure_begin(p);
 
@@ -1168,6 +1171,7 @@ gb_internal cgProcedure *cg_hasher_proc_for_type(cgModule *m, Type *type) {
 
 	cgProcedure *p = cg_procedure_create_dummy(m, proc_name, t_hasher_proc);
 	map_set(&m->hasher_procs, type, p);
+	p->split_returns_index = 2;
 
 	cg_procedure_begin(p);
 	defer (cg_procedure_end(p));

+ 33 - 3
src/tilde_stmt.cpp

@@ -77,7 +77,7 @@ gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue src, bool is
 	GB_ASSERT(is_type_pointer(dst.type));
 	Type *dst_type = type_deref(dst.type);
 
-	GB_ASSERT_MSG(are_types_identical(dst_type, src.type), "%s vs %s", type_to_string(dst_type), type_to_string(src.type));
+	GB_ASSERT_MSG(are_types_identical(core_type(dst_type), core_type(src.type)), "%s vs %s", type_to_string(dst_type), type_to_string(src.type));
 
 	TB_DataType dt = cg_data_type(dst_type);
 	TB_DataType st = cg_data_type(src.type);
@@ -225,6 +225,35 @@ gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr) {
 	switch (addr.kind) {
 	case cgAddr_Default:
 		return cg_emit_load(p, addr.addr);
+
+	case cgAddr_Map:
+		{
+			Type *map_type = base_type(type_deref(addr.addr.type));
+			GB_ASSERT(map_type->kind == Type_Map);
+			cgAddr v_addr = cg_add_local(p, map_type->Map.value, nullptr, true);
+
+			cgValue ptr = cg_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
+			cgValue ok = cg_emit_conv(p, cg_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
+
+			TB_Node *then = cg_control_region(p, "map.get.then");
+			TB_Node *done = cg_control_region(p, "map.get.done");
+			cg_emit_if(p, ok, then, done);
+			tb_inst_set_control(p->func, then);
+			{
+				cgValue value = cg_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
+				value = cg_emit_load(p, value);
+				cg_addr_store(p, v_addr, value);
+			}
+			cg_emit_goto(p, done);
+			tb_inst_set_control(p->func, done);
+
+			cgValue v = cg_addr_load(p, v_addr);
+			if (is_type_tuple(addr.map.result)) {
+				return cg_value_multi2(v, ok, addr.map.result);
+			} else {
+				return v;
+			}
+		}
 	}
 	GB_PANIC("TODO(bill): cg_addr_load %p", addr.addr.node);
 	return {};
@@ -254,7 +283,8 @@ gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value) {
 	} else if (addr.kind == cgAddr_RelativeSlice) {
 		GB_PANIC("TODO(bill): cgAddr_RelativeSlice");
 	} else if (addr.kind == cgAddr_Map) {
-		GB_PANIC("TODO(bill): cgAddr_Map");
+		cg_internal_dynamic_map_set(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt);
+		return;
 	} else if (addr.kind == cgAddr_Context) {
 		cgAddr old_addr = cg_find_or_generate_context_ptr(p);
 
@@ -1096,7 +1126,7 @@ gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice<cgValue> co
 		}
 
 	} else {
-		GB_ASSERT(!is_calling_convention_odin(p->type->Proc.calling_convention));
+		GB_ASSERT_MSG(!is_calling_convention_odin(p->type->Proc.calling_convention), "missing %s", proc_calling_convention_strings[p->type->Proc.calling_convention]);
 
 		if (p->return_by_ptr) {
 			Entity *e = tuple->variables[return_count-1];

+ 3 - 3
src/tilde_type_info.cpp

@@ -332,14 +332,14 @@ gb_internal void cg_setup_type_info_data(cgModule *m) {
 				char const *name = CG_TYPE_INFO_TYPES_NAME;
 				Type *t = alloc_type_array(t_type_info_ptr, count);
 				TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE);
-				tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count*2);
+				tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count*3);
 				cg_global_type_info_member_types = GlobalTypeInfoData{g, t, t_type_info_ptr, 0};
 			}
 			{
 				char const *name = CG_TYPE_INFO_NAMES_NAME;
 				Type *t = alloc_type_array(t_string, count);
 				TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE);
-				tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count*2);
+				tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count*3);
 				cg_global_type_info_member_names = GlobalTypeInfoData{g, t, t_string, 0};
 			}
 			{
@@ -362,7 +362,7 @@ gb_internal void cg_setup_type_info_data(cgModule *m) {
 				char const *name = CG_TYPE_INFO_TAGS_NAME;
 				Type *t = alloc_type_array(t_string, count);
 				TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE);
-				tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count*2);
+				tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count*3);
 				cg_global_type_info_member_tags = GlobalTypeInfoData{g, t, t_string, 0};
 			}
 		}