From b94247988658f875bfaed6717b3f888d75d5e660 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Dec 2024 15:57:20 +0000 Subject: Minor improvement to type handing on failures --- src/types.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index 4b43662f5..233f903a3 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3888,6 +3888,10 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack min_field_align = 1; } + TypePath path{}; + type_path_init(&path); + defer (type_path_free(&path)); + if (is_raw_union) { for_array(i, fields) { offsets[i] = 0; @@ -3897,7 +3901,7 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack if (fields[i]->kind != Entity_Variable) { offsets[i] = -1; } else { - i64 size = type_size_of(fields[i]->type); + i64 size = type_size_of_internal(fields[i]->type, &path); offsets[i] = curr_offset; curr_offset += size; } @@ -3908,11 +3912,11 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack offsets[i] = -1; } else { Type *t = fields[i]->type; - i64 align = gb_max(type_align_of(t), min_field_align); + i64 align = gb_max(type_align_of_internal(t, &path), min_field_align); if (max_field_align > min_field_align) { align = gb_min(align, max_field_align); } - i64 size = gb_max(type_size_of( t), 0); + i64 size = gb_max(type_size_of_internal(t, &path), 0); curr_offset = align_formula(curr_offset, align); offsets[i] = curr_offset; curr_offset += size; @@ -3925,15 +3929,13 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack gb_internal bool type_set_offsets(Type *t) { t = base_type(t); if (t->kind == Type_Struct) { - if (mutex_try_lock(&t->Struct.offset_mutex)) { - defer (mutex_unlock(&t->Struct.offset_mutex)); - if (!t->Struct.are_offsets_set) { - t->Struct.are_offsets_being_processed = true; - t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align); - t->Struct.are_offsets_being_processed = false; - t->Struct.are_offsets_set = true; - return true; - } + MUTEX_GUARD(&t->Struct.offset_mutex); + if (!t->Struct.are_offsets_set) { + t->Struct.are_offsets_being_processed = true; + t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align); + t->Struct.are_offsets_being_processed = false; + t->Struct.are_offsets_set = true; + return true; } } else if (is_type_tuple(t)) { MUTEX_GUARD(&t->Tuple.mutex); -- cgit v1.2.3 From b25ca0bb11f64a2af887801d451bd8638dba9e76 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 21 Jan 2025 20:37:02 -0500 Subject: fixes compiler crash on syntax error (issue 4738) --- src/types.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index 233f903a3..0b6e6d334 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4773,7 +4773,9 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha case Type_BitSet: str = gb_string_appendc(str, "bit_set["); - if (is_type_enum(type->BitSet.elem)) { + if (type->BitSet.elem == nullptr) { + str = gb_string_appendc(str, ""); + } else if (is_type_enum(type->BitSet.elem)) { str = write_type_to_string(str, type->BitSet.elem); } else { str = gb_string_append_fmt(str, "%lld", type->BitSet.lower); -- cgit v1.2.3 From f80bea5b1142c6b317f8f52bb9b3814afe5d3c1b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 5 Feb 2025 10:27:17 +0000 Subject: Remove transmute suggestion with `-vet-cast` when transmuting native <-> endian-specific types --- src/check_expr.cpp | 3 ++- src/types.cpp | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src/types.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 83b6181c0..550a7749c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3649,7 +3649,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type gb_string_free(oper_str); gb_string_free(to_type); } else if (is_type_integer(src_t) && is_type_integer(dst_t) && - types_have_same_internal_endian(src_t, dst_t)) { + types_have_same_internal_endian(src_t, dst_t) && + type_endian_kind_of(src_t) == type_endian_kind_of(dst_t)) { gbString oper_type = type_to_string(src_t); gbString to_type = type_to_string(dst_t); error(o->expr, "Use of 'transmute' where 'cast' would be preferred since both are integers of the same endianness, from '%s' to '%s'", oper_type, to_type); diff --git a/src/types.cpp b/src/types.cpp index 0b6e6d334..412448cbc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1801,6 +1801,27 @@ gb_internal bool is_type_union_maybe_pointer_original_alignment(Type *t) { } +enum TypeEndianKind { + TypeEndian_Platform, + TypeEndian_Little, + TypeEndian_Big, +}; + +gb_internal TypeEndianKind type_endian_kind_of(Type *t) { + t = core_type(t); + if (t->kind == Type_Basic) { + if (t->Basic.flags & BasicFlag_EndianLittle) { + return TypeEndian_Little; + } + if (t->Basic.flags & BasicFlag_EndianBig) { + return TypeEndian_Big; + } + } else if (t->kind == Type_BitSet) { + return type_endian_kind_of(bit_set_to_int(t)); + } + return TypeEndian_Platform; +} + gb_internal bool is_type_endian_big(Type *t) { t = core_type(t); -- cgit v1.2.3 From 98201962e0cbf0448628b36e5b2bb78cfc25906c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Feb 2025 17:29:38 +0000 Subject: Begin work on producing a canonicalized type string for hashing types. --- src/types.cpp | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 248 insertions(+), 27 deletions(-) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index 412448cbc..5df062677 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1,5 +1,5 @@ -struct Scope; struct Ast; +struct Scope; struct Entity; enum BasicKind { @@ -161,10 +161,10 @@ struct TypeStruct { struct TypeUnion { Slice variants; - + Ast * node; Scope * scope; - + i64 variant_block_size; i64 custom_align; Type * polymorphic_params; // Type_Tuple @@ -1438,7 +1438,7 @@ gb_internal bool is_type_matrix(Type *t) { gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { t = base_type(t); GB_ASSERT(t->kind == Type_Matrix); - + Type *elem = t->Matrix.elem; i64 row_count = gb_max(t->Matrix.row_count, 1); i64 column_count = gb_max(t->Matrix.column_count, 1); @@ -1450,15 +1450,15 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { i64 elem_align = type_align_of_internal(elem, tp); if (pop) type_path_pop(tp); - + i64 elem_size = type_size_of(elem); - + // NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding // It would be better for performance to pad each column so that each column // could be maximally aligned but as a compromise, having no padding will be // beneficial to third libraries that assume no padding - + i64 total_expected_size = row_count*column_count*elem_size; // i64 min_alignment = prev_pow2(elem_align * row_count); i64 min_alignment = prev_pow2(total_expected_size); @@ -1466,7 +1466,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { min_alignment >>= 1; } min_alignment = gb_max(min_alignment, elem_align); - + i64 align = gb_min(min_alignment, build_context.max_simd_align); return align; } @@ -1480,7 +1480,7 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) { } else if (t->Matrix.row_count == 0) { return 0; } - + i64 elem_size; if (tp != nullptr) { elem_size = type_size_of_internal(t->Matrix.elem, tp); @@ -1489,7 +1489,7 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) { } i64 stride_in_bytes = 0; - + // NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding // It would be better for performance to pad each column/row so that each column/row // could be maximally aligned but as a compromise, having no padding will be @@ -1545,7 +1545,7 @@ gb_internal i64 matrix_row_major_index_to_offset(Type *t, i64 index) { gb_internal i64 matrix_column_major_index_to_offset(Type *t, i64 index) { t = base_type(t); GB_ASSERT(t->kind == Type_Matrix); - + i64 row_index = index%t->Matrix.row_count; i64 column_index = index/t->Matrix.row_count; return matrix_indices_to_offset(t, row_index, column_index); @@ -1566,7 +1566,7 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) { return true; } else if (is_type_complex(t)) { return true; - } + } if (t->kind == Type_Generic) { return true; } @@ -2119,6 +2119,23 @@ gb_internal bool is_type_sliceable(Type *t) { return false; } +gb_internal Entity *type_get_polymorphic_parent(Type *t, Type **params_) { + t = base_type(t); + Type *parent = nullptr; + if (t->kind == Type_Struct) { + parent = t->Struct.polymorphic_parent; + if (params_) *params_ = t->Struct.polymorphic_params; + } else if (t->kind == Type_Union) { + parent = t->Union.polymorphic_parent; + if (params_) *params_ = t->Union.polymorphic_params; + } + if (parent != nullptr) { + GB_ASSERT(parent->kind == Type_Named); + + return parent->Named.type_name; + } + return nullptr; +} gb_internal bool is_type_polymorphic_record(Type *t) { t = base_type(t); @@ -2485,7 +2502,7 @@ gb_internal bool is_type_simple_compare(Type *t) { case Type_Proc: case Type_BitSet: return true; - + case Type_Matrix: return is_type_simple_compare(t->Matrix.elem); @@ -2732,7 +2749,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Array: return (x->Array.count == y->Array.count) && are_types_identical(x->Array.elem, y->Array.elem); - + case Type_Matrix: return x->Matrix.row_count == y->Matrix.row_count && x->Matrix.column_count == y->Matrix.column_count && @@ -3592,7 +3609,7 @@ gb_internal bool are_struct_fields_reordered(Type *type) { return false; } GB_ASSERT(type->Struct.offsets != nullptr); - + i64 prev_offset = 0; for_array(i, type->Struct.fields) { i64 offset = type->Struct.offsets[i]; @@ -3613,9 +3630,9 @@ gb_internal Slice struct_fields_index_by_increasing_offset(gbAllocator allo return {}; } GB_ASSERT(type->Struct.offsets != nullptr); - + auto indices = slice_make(allocator, type->Struct.fields.count); - + i64 prev_offset = 0; bool is_ordered = true; for_array(i, indices) { @@ -3630,14 +3647,14 @@ gb_internal Slice struct_fields_index_by_increasing_offset(gbAllocator allo isize n = indices.count; for (isize i = 1; i < n; i++) { isize j = i; - + while (j > 0 && type->Struct.offsets[indices[j-1]] > type->Struct.offsets[indices[j]]) { gb_swap(i32, indices[j-1], indices[j]); j -= 1; - } + } } } - + return indices; } @@ -3887,8 +3904,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { // IMPORTANT TODO(bill): Figure out the alignment of vector types return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_simd_align*2); } - - case Type_Matrix: + + case Type_Matrix: return matrix_align_of(t, path); case Type_SoaPointer: @@ -4175,7 +4192,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { Type *elem = t->SimdVector.elem; return count * type_size_of_internal(elem, path); } - + case Type_Matrix: { i64 stride_in_bytes = matrix_type_stride_in_bytes(t, path); if (t->Matrix.is_row_major) { @@ -4580,7 +4597,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha break; case Type_Array: - str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count)); + str = gb_string_appendc(str, gb_bprintf("[%lld]", cast(long long)type->Array.count)); str = write_type_to_string(str, type->Array.elem); break; @@ -4753,10 +4770,10 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha } break; case ProcCC_CDecl: - str = gb_string_appendc(str, " \"cdecl\" "); + str = gb_string_appendc(str, " \"c\" "); break; case ProcCC_StdCall: - str = gb_string_appendc(str, " \"stdcall\" "); + str = gb_string_appendc(str, " \"std\" "); break; case ProcCC_FastCall: str = gb_string_appendc(str, " \"fastcall\" "); @@ -4814,7 +4831,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_append_fmt(str, "#simd[%d]", cast(int)type->SimdVector.count); str = write_type_to_string(str, type->SimdVector.elem); break; - + case Type_Matrix: if (type->Matrix.is_row_major) { str = gb_string_appendc(str, "#row_major "); @@ -4856,5 +4873,209 @@ gb_internal gbString type_to_string_shorthand(Type *type) { return type_to_string(type, true); } +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +gb_internal gbString write_canonical_params(gbString w, Type *params) { + w = gb_string_appendc(w, "("); + if (params) { + GB_ASSERT(params->kind == Type_Tuple); + for_array(i, params->Tuple.variables) { + Entity *v = params->Tuple.variables[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + if (v->kind == Entity_Variable) { + if (v->flags&EntityFlag_CVarArg) { + w = gb_string_appendc(w, "#c_vararg"); + } + if (v->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(v->type); + w = gb_string_appendc(w, ".."); + GB_ASSERT(v->type->kind == Type_Slice); + w = write_type_to_canonical_string(w, slice->Slice.elem); + } else { + w = write_type_to_canonical_string(w, v->type); + } + } else if (v->kind == Entity_TypeName) { + w = gb_string_appendc(w, "$"); + w = write_type_to_canonical_string(w, v->type); + } else if (v->kind == Entity_Constant) { + w = gb_string_appendc(w, "$$"); + w = write_exact_value_to_string(w, v->Constant.value); + } else { + GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); + } + } + } + return gb_string_appendc(w, ")"); +} + +gb_internal u64 type_hash_canonical_type(Type *type) { + if (type == nullptr) { + return 0; + } + TEMPORARY_ALLOCATOR_GUARD(); + gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); + u64 hash = fnv64a(w, gb_string_length(w)); + return hash; +} + +// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { + if (type == nullptr) { + return gb_string_appendc(w, "<>"); // none/void type + } + + type = default_type(type); + GB_ASSERT(!is_type_untyped(type)); + switch (type->kind) { + case Type_Basic: + return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); + case Type_Pointer: + w = gb_string_append_rune(w, '^'); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_MultiPointer: + w = gb_string_appendc(w, "[^]"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_SoaPointer: + w = gb_string_appendc(w, "#soa^"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_EnumeratedArray: + if (type->EnumeratedArray.is_sparse) { + w = gb_string_appendc(w, "#sparse"); + } + w = gb_string_append_rune(w, '['); + w = write_type_to_canonical_string(w, type->EnumeratedArray.index); + w = gb_string_append_rune(w, ']'); + return write_type_to_canonical_string(w, type->EnumeratedArray.elem); + case Type_Array: + w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_Slice: + w = gb_string_appendc(w, "[]"); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_DynamicArray: + w = gb_string_appendc(w, "[dynamic]"); + return write_type_to_canonical_string(w, type->DynamicArray.elem); + case Type_SimdVector: + w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); + return write_type_to_canonical_string(w, type->SimdVector.elem); + case Type_Matrix: + if (type->Matrix.is_row_major) { + w = gb_string_appendc(w, "#row_major "); + } + w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); + return write_type_to_canonical_string(w, type->Matrix.elem); + case Type_Map: + w = gb_string_appendc(w, "map["); + w = write_type_to_canonical_string(w, type->Map.key); + w = gb_string_appendc(w, "]"); + return write_type_to_canonical_string(w, type->Map.value); + + case Type_Enum: + w = gb_string_appendc(w, "enum"); + if (type->Enum.base_type != nullptr) { + w = gb_string_append_rune(w, ' '); + w = write_type_to_canonical_string(w, type->Enum.base_type); + w = gb_string_append_rune(w, ' '); + } + w = gb_string_append_rune(w, '{'); + for_array(i, type->Enum.fields) { + Entity *f = type->Enum.fields[i]; + GB_ASSERT(f->kind == Entity_Constant); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, "="); + w = write_exact_value_to_string(w, f->Constant.value); + } + return gb_string_append_rune(w, '}'); + case Type_BitSet: + w = gb_string_appendc(w, "bit_set["); + if (type->BitSet.elem == nullptr) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else if (is_type_enum(type->BitSet.elem)) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else { + w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); + w = gb_string_append_fmt(w, "..="); + w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); + } + if (type->BitSet.underlying != nullptr) { + w = gb_string_appendc(w, ";"); + w = write_type_to_canonical_string(w, type->BitSet.underlying); + } + return gb_string_appendc(w, "]"); + + case Type_Union: + w = gb_string_appendc(w, "union"); + return w; + case Type_Struct: + w = gb_string_appendc(w, "struct"); + return w; + + case Type_BitField: + w = gb_string_appendc(w, "bit_field"); + w = write_type_to_canonical_string(w, type->BitField.backing_type); + w = gb_string_appendc(w, " {"); + for (isize i = 0; i < type->BitField.fields.count; i++) { + Entity *f = type->BitField.fields[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, ":"); + w = write_type_to_canonical_string(w, f->type); + w = gb_string_appendc(w, "|"); + w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); + } + return gb_string_appendc(w, " }"); + + case Type_Proc: + w = gb_string_appendc(w, "proc"); + if (default_calling_convention() != type->Proc.calling_convention) { + w = gb_string_appendc(w, "\""); + w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); + w = gb_string_appendc(w, "\""); + } + + w = write_canonical_params(w, type->Proc.params); + if (type->Proc.result_count > 0) { + w = gb_string_appendc(w, "->"); + w = write_canonical_params(w, type->Proc.results); + } + return w; + + case Type_Generic: + GB_PANIC("Type_Generic should never be hit"); + return w; + + case Type_Named: + if (type->Named.type_name != nullptr) { + Entity *e = type->Named.type_name; + if (e->pkg != nullptr) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + w = gb_string_appendc(w, "."); + } + Type *params = nullptr; + Entity *parent = type_get_polymorphic_parent(type, ¶ms); + if (parent) { + w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); + w = write_canonical_params(w, params); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + } else { + w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); + } + // Handle parapoly stuff here? + return w; + + default: + GB_PANIC("unknown type kind %d", type->kind); + break; + } + return w; +} \ No newline at end of file -- cgit v1.2.3 From 2a5933513ca47d75c1f29efae2e9f948c3ae8103 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Feb 2025 12:32:05 +0000 Subject: Fill in more canonical types --- src/types.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index 5df062677..c88878b9c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -5010,10 +5010,57 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { case Type_Union: w = gb_string_appendc(w, "union"); - return w; + + switch (type->Union.kind) { + case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; + case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; + } + if (type->Union.custom_align != 0) { + w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); + } + w = gb_string_appendc(w, "{"); + for_array(i, type->Union.variants) { + Type *t = type->Union.variants[i]; + if (i > 0) w = gb_string_appendc(w, ", "); + w = write_type_to_canonical_string(w, t); + } + return gb_string_appendc(w, "}"); case Type_Struct: + if (type->Struct.soa_kind != StructSoa_None) { + switch (type->Struct.soa_kind) { + case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; + case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; + case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; + default: GB_PANIC("Unknown StructSoaKind"); break; + } + return write_type_to_canonical_string(w, type->Struct.soa_elem); + } + w = gb_string_appendc(w, "struct"); - return w; + if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); + if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); + if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); + if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); + if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); + if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); + w = gb_string_appendc(w, "{"); + for_array(i, type->Struct.fields) { + Entity *f = type->Struct.fields[i]; + GB_ASSERT(f->kind == Entity_Variable); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length (w, f->token.string.text, f->token.string.len); + w = gb_string_appendc (w, ":"); + w = write_type_to_canonical_string(w, f->type); + String tag = type->Struct.tags[i]; + if (tag.len != 0) { + String s = quote_to_ascii(heap_allocator(), tag); + w = gb_string_append_length(w, s.text, s.len); + gb_free(heap_allocator(), s.text); + } + } + return gb_string_appendc(w, "}"); case Type_BitField: w = gb_string_appendc(w, "bit_field"); -- cgit v1.2.3 From 4eba3698aa1dde15abd22de1452229293282efee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 09:47:49 +0000 Subject: Begin work on nested declarations --- src/types.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index c88878b9c..42530eccc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4919,6 +4919,12 @@ gb_internal u64 type_hash_canonical_type(Type *type) { return hash; } +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { + gbString w = gb_string_make(allocator, ""); + w = write_type_to_canonical_string(w, type); + return make_string(cast(u8 const *)w, gb_string_length(w)); +} + // NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { if (type == nullptr) { @@ -5101,6 +5107,15 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { case Type_Named: if (type->Named.type_name != nullptr) { Entity *e = type->Named.type_name; + + if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || + e->flags & EntityFlag_NotExported) { + if (e->scope->flags & ScopeFlag_Proc) { + GB_PANIC("NESTED IN PROC\n"); + } else if (e->scope->flags & ScopeFlag_File) { + GB_PANIC("PRIVATE TO FILE\n"); + } + } if (e->pkg != nullptr) { w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); w = gb_string_appendc(w, "."); -- cgit v1.2.3 From 99d91ccd31366e78c7ec0e94b5e3d473806721ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 11:32:49 +0000 Subject: Work on making name mangling deterministic --- src/check_decl.cpp | 6 + src/check_expr.cpp | 2 +- src/checker.cpp | 1 + src/checker.hpp | 2 + src/entity.cpp | 1 + src/gb/gb.h | 2 +- src/llvm_backend.hpp | 2 +- src/llvm_backend_general.cpp | 43 ++++- src/llvm_backend_stmt.cpp | 3 +- src/name_canonicalization.cpp | 419 ++++++++++++++++++++++++++++++++++++++++++ src/types.cpp | 269 --------------------------- 11 files changed, 475 insertions(+), 275 deletions(-) create mode 100644 src/name_canonicalization.cpp (limited to 'src/types.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 9084f15f0..d6f8e6fa7 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1784,6 +1784,10 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de ctx->curr_proc_sig = type; ctx->curr_proc_calling_convention = type->Proc.calling_convention; + if (decl->parent && decl->entity && decl->parent->entity) { + decl->entity->parent_proc_decl = decl->parent; + } + if (ctx->pkg->name != "runtime") { switch (type->Proc.calling_convention) { case ProcCC_None: @@ -1873,6 +1877,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de check_open_scope(ctx, body); { + ctx->scope->decl_info = decl; + for (auto const &entry : using_entities) { Entity *uvar = entry.uvar; Entity *prev = scope_insert(ctx->scope, uvar); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 550a7749c..f0021e67f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -345,7 +345,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice const &nodes, check_collect_entities(c, nodes); for (auto const &entry : s->elements) { - Entity *e = entry.value; + Entity *e = entry.value;\ switch (e->kind) { case Entity_Constant: case Entity_TypeName: diff --git a/src/checker.cpp b/src/checker.cpp index bfcabe4fa..c74a72a14 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3894,6 +3894,7 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) { #include "check_expr.cpp" #include "check_builtin.cpp" #include "check_type.cpp" +#include "name_canonicalization.cpp" #include "check_decl.cpp" #include "check_stmt.cpp" diff --git a/src/checker.hpp b/src/checker.hpp index 4634047c0..472ab8e50 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -276,6 +276,8 @@ struct Scope { StringMap elements; PtrSet imported; + DeclInfo *decl_info; + i32 flags; // ScopeFlag union { AstPackage *pkg; diff --git a/src/entity.cpp b/src/entity.cpp index d137a8674..b2148aa7b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -257,6 +257,7 @@ struct Entity { bool has_instrumentation : 1; bool is_memcpy_like : 1; bool uses_branch_location : 1; + bool is_anonymous : 1; } Procedure; struct { Array entities; diff --git a/src/gb/gb.h b/src/gb/gb.h index 59611ceb6..98c362e93 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -5856,7 +5856,7 @@ gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) { gb_inline char *gb_bprintf_va(char const *fmt, va_list va) { - gb_local_persist char buffer[4096]; + gb_thread_local gb_local_persist char buffer[4096]; gb_snprintf_va(buffer, gb_size_of(buffer), fmt, va); return buffer; } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index a0775ac3b..dd6f1a083 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -399,7 +399,7 @@ struct lbProcedure { gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c); gb_internal String lb_mangle_name(Entity *e); -gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String name = {}); +gb_internal String lb_get_entity_name(lbModule *m, Entity *e); gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0); gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7425b9fd7..dc212e51d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1444,6 +1444,7 @@ gb_internal void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { } gb_internal String lb_mangle_name(Entity *e) { +#if 1 String name = e->token.string; AstPackage *pkg = e->pkg; @@ -1483,9 +1484,18 @@ gb_internal String lb_mangle_name(Entity *e) { String mangled_name = make_string((u8 const *)new_name, new_name_len-1); return mangled_name; +#else + gbString w = gb_string_make(gb_heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + gb_printf_err(">> %s\n", w); + + String mangled_name = make_string(cast(u8 const *)w, gb_string_length(w)); + return mangled_name; +#endif } gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p, lbModule *module) { +#if 0 // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration // and as a result, the declaration does not have time to determine what it should be @@ -1516,6 +1526,7 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur } } + // NOTE(bill): Generate a new name // parent_proc.name-guid String ts_name = e->token.string; @@ -1528,6 +1539,12 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur String name = make_string(cast(u8 *)name_text, name_len-1); e->TypeName.ir_mangled_name = name; + + { + String s = type_to_canonical_string(temporary_allocator(), e->type); + gb_printf_err("1) %.*s\n", LIT(s)); + gb_printf_err("2) %.*s\n", LIT(name)); + } return name; } else { // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now @@ -1538,11 +1555,18 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur String name = make_string(cast(u8 *)name_text, name_len-1); e->TypeName.ir_mangled_name = name; + + { + String s = type_to_canonical_string(temporary_allocator(), e->type); + gb_printf_err("3) %.*s\n", LIT(s)); + gb_printf_err("4) %.*s\n", LIT(name)); + } return name; } +#endif } -gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_name) { +gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { GB_ASSERT(m != nullptr); if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { return e->TypeName.ir_mangled_name; @@ -1553,6 +1577,13 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam return e->token.string; } +#if 1 + gbString w = gb_string_make(heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + defer (gb_string_free(w)); + + String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); +#else if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { return lb_set_nested_type_name_ir_mangled_name(e, nullptr, m); } @@ -1576,11 +1607,17 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam if (!no_name_mangle) { name = lb_mangle_name(e); + + gbString w = gb_string_make(gb_heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + if (w[0] == 0) { + gb_printf_err(">> %s %.*s\n", w, LIT(name)); + } } if (name.len == 0) { name = e->token.string; } - +#endif if (e->kind == Entity_TypeName) { e->TypeName.ir_mangled_name = name; } else if (e->kind == Entity_Procedure) { @@ -2869,6 +2906,8 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr pl->decl->code_gen_module = m; e->decl_info = pl->decl; pl->decl->entity = e; + e->parent_proc_decl = pl->decl->parent; + e->Procedure.is_anonymous = true; e->flags |= EntityFlag_ProcBodyChecked; lbProcedure *p = lb_create_procedure(m, e); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index b05df0b46..b83472075 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -32,7 +32,8 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) continue; } - lb_set_nested_type_name_ir_mangled_name(e, p, p->module); + String name = lb_get_entity_name(p->module, e); + gb_unused(name); } for_array(i, vd->names) { diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp new file mode 100644 index 000000000..fa09f27c0 --- /dev/null +++ b/src/name_canonicalization.cpp @@ -0,0 +1,419 @@ +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +gb_internal gbString write_canonical_params(gbString w, Type *params) { + w = gb_string_appendc(w, "("); + if (params) { + GB_ASSERT(params->kind == Type_Tuple); + for_array(i, params->Tuple.variables) { + Entity *v = params->Tuple.variables[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + if (v->kind == Entity_Variable) { + if (v->flags&EntityFlag_CVarArg) { + w = gb_string_appendc(w, "#c_vararg"); + } + if (v->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(v->type); + w = gb_string_appendc(w, ".."); + GB_ASSERT(v->type->kind == Type_Slice); + w = write_type_to_canonical_string(w, slice->Slice.elem); + } else { + w = write_type_to_canonical_string(w, v->type); + } + } else if (v->kind == Entity_TypeName) { + w = gb_string_appendc(w, "$"); + w = write_type_to_canonical_string(w, v->type); + } else if (v->kind == Entity_Constant) { + w = gb_string_appendc(w, "$$"); + w = write_exact_value_to_string(w, v->Constant.value); + } else { + GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); + } + } + } + return gb_string_appendc(w, ")"); +} + +gb_internal u64 type_hash_canonical_type(Type *type) { + if (type == nullptr) { + return 0; + } + TEMPORARY_ALLOCATOR_GUARD(); + gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); + u64 hash = fnv64a(w, gb_string_length(w)); + return hash; +} + +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { + gbString w = gb_string_make(allocator, ""); + w = write_type_to_canonical_string(w, type); + return make_string(cast(u8 const *)w, gb_string_length(w)); +} + +gb_internal void print_scope_flags(Scope *s) { + if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg "); + if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin "); + if (s->flags & ScopeFlag_Global) gb_printf_err("Global "); + if (s->flags & ScopeFlag_File) gb_printf_err("File "); + if (s->flags & ScopeFlag_Init) gb_printf_err("Init "); + if (s->flags & ScopeFlag_Proc) gb_printf_err("Proc "); + if (s->flags & ScopeFlag_Type) gb_printf_err("Type "); + if (s->flags & ScopeFlag_HasBeenImported) gb_printf_err("HasBeenImported "); + if (s->flags & ScopeFlag_ContextDefined) gb_printf_err("ContextDefined "); + gb_printf_err("\n"); +} + + + +gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool ignore_final_dot=false) { + GB_ASSERT(e != nullptr); + + // auto const &parent_entity = [](Scope *s) -> Entity* { + // while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { + // s = s->parent; + // } + // if (s->decl_info && s->decl_info->entity) { + // return s->decl_info->entity; + // } + // return nullptr; + // }; + + if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export || e->Procedure.is_foreign) { + // no prefix + return w; + } + if (e->parent_proc_decl) { + Entity *p = e->parent_proc_decl->entity; + w = write_canonical_parent_prefix(w, p); + w = gb_string_append_length(w, p->token.string.text, p->token.string.len); + if (is_type_polymorphic(p->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, p->type); + } + w = gb_string_appendc(w, "."); + + } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, "."); + } else { + String file_name = filename_without_directory(e->file->fullpath); + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + } + } else if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export || e->Procedure.is_foreign) { + // no prefix + return w; + } + GB_PANIC("TODO(bill): handle entity kind: %d", e->kind); + } + + if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { + w = gb_string_appendc(w, gb_bprintf("$anon%d", e->token.pos.offset)); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + + if (is_type_polymorphic(e->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, e->type); + } + if (!ignore_final_dot) { + w = gb_string_appendc(w, "."); + } + + return w; +} + +gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { + GB_ASSERT(e != nullptr); + + if (e->token.string == "_") { + GB_PANIC("_ string"); + } + if (e->token.string.len == 0) { + GB_PANIC("empty string"); + } + + if (e->kind == Entity_Variable) { + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + if (e->Variable.link_name.len > 0) { + w = gb_string_append_length(w, e->Variable.link_name.text, e->Variable.link_name.len); + return w; + } else if (is_foreign || is_export) { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + return w; + } + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + w = gb_string_append_length(w, e->Procedure.link_name.text, e->Procedure.link_name.len); + return w; + } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + return w; + } + + if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || + e->flags & EntityFlag_NotExported) { + + Scope *s = e->scope; + while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { + s = s->parent; + } + + if (s->decl_info != nullptr && s->decl_info->entity) { + w = write_canonical_parent_prefix(w, s->decl_info->entity); + goto write_base_name; + } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) { + String file_name = filename_without_directory(s->file->fullpath); + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + goto write_base_name; + } + gb_printf_err("%s HERE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); + print_scope_flags(s); + GB_PANIC("weird entity"); + } + if (e->pkg != nullptr) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + w = gb_string_appendc(w, "."); + } + +write_base_name: + + switch (e->kind) { + case Entity_TypeName: + { + Type *params = nullptr; + Entity *parent = type_get_polymorphic_parent(e->type, ¶ms); + if (parent) { + w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); + w = write_canonical_params(w, params); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + } + // Handle parapoly stuff here? + return w; + + case Entity_Procedure: + case Entity_Variable: + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + if (is_type_polymorphic(e->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, e->type); + } + return w; + + default: + GB_PANIC("TODO(bill): entity kind %d", e->kind); + break; + } + return w; +} + +// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { + if (type == nullptr) { + return gb_string_appendc(w, "<>"); // none/void type + } + + type = default_type(type); + GB_ASSERT(!is_type_untyped(type)); + + switch (type->kind) { + case Type_Basic: + return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); + case Type_Pointer: + w = gb_string_append_rune(w, '^'); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_MultiPointer: + w = gb_string_appendc(w, "[^]"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_SoaPointer: + w = gb_string_appendc(w, "#soa^"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_EnumeratedArray: + if (type->EnumeratedArray.is_sparse) { + w = gb_string_appendc(w, "#sparse"); + } + w = gb_string_append_rune(w, '['); + w = write_type_to_canonical_string(w, type->EnumeratedArray.index); + w = gb_string_append_rune(w, ']'); + return write_type_to_canonical_string(w, type->EnumeratedArray.elem); + case Type_Array: + w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_Slice: + w = gb_string_appendc(w, "[]"); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_DynamicArray: + w = gb_string_appendc(w, "[dynamic]"); + return write_type_to_canonical_string(w, type->DynamicArray.elem); + case Type_SimdVector: + w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); + return write_type_to_canonical_string(w, type->SimdVector.elem); + case Type_Matrix: + if (type->Matrix.is_row_major) { + w = gb_string_appendc(w, "#row_major "); + } + w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); + return write_type_to_canonical_string(w, type->Matrix.elem); + case Type_Map: + w = gb_string_appendc(w, "map["); + w = write_type_to_canonical_string(w, type->Map.key); + w = gb_string_appendc(w, "]"); + return write_type_to_canonical_string(w, type->Map.value); + + case Type_Enum: + w = gb_string_appendc(w, "enum"); + if (type->Enum.base_type != nullptr) { + w = gb_string_append_rune(w, ' '); + w = write_type_to_canonical_string(w, type->Enum.base_type); + w = gb_string_append_rune(w, ' '); + } + w = gb_string_append_rune(w, '{'); + for_array(i, type->Enum.fields) { + Entity *f = type->Enum.fields[i]; + GB_ASSERT(f->kind == Entity_Constant); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, "="); + w = write_exact_value_to_string(w, f->Constant.value); + } + return gb_string_append_rune(w, '}'); + case Type_BitSet: + w = gb_string_appendc(w, "bit_set["); + if (type->BitSet.elem == nullptr) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else if (is_type_enum(type->BitSet.elem)) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else { + w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); + w = gb_string_append_fmt(w, "..="); + w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); + } + if (type->BitSet.underlying != nullptr) { + w = gb_string_appendc(w, ";"); + w = write_type_to_canonical_string(w, type->BitSet.underlying); + } + return gb_string_appendc(w, "]"); + + case Type_Union: + w = gb_string_appendc(w, "union"); + + switch (type->Union.kind) { + case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; + case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; + } + if (type->Union.custom_align != 0) { + w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); + } + w = gb_string_appendc(w, "{"); + for_array(i, type->Union.variants) { + Type *t = type->Union.variants[i]; + if (i > 0) w = gb_string_appendc(w, ", "); + w = write_type_to_canonical_string(w, t); + } + return gb_string_appendc(w, "}"); + case Type_Struct: + if (type->Struct.soa_kind != StructSoa_None) { + switch (type->Struct.soa_kind) { + case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; + case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; + case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; + default: GB_PANIC("Unknown StructSoaKind"); break; + } + return write_type_to_canonical_string(w, type->Struct.soa_elem); + } + + w = gb_string_appendc(w, "struct"); + if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); + if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); + if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); + if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); + if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); + if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); + w = gb_string_appendc(w, "{"); + for_array(i, type->Struct.fields) { + Entity *f = type->Struct.fields[i]; + GB_ASSERT(f->kind == Entity_Variable); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length (w, f->token.string.text, f->token.string.len); + w = gb_string_appendc (w, ":"); + w = write_type_to_canonical_string(w, f->type); + String tag = type->Struct.tags[i]; + if (tag.len != 0) { + String s = quote_to_ascii(heap_allocator(), tag); + w = gb_string_append_length(w, s.text, s.len); + gb_free(heap_allocator(), s.text); + } + } + return gb_string_appendc(w, "}"); + + case Type_BitField: + w = gb_string_appendc(w, "bit_field"); + w = write_type_to_canonical_string(w, type->BitField.backing_type); + w = gb_string_appendc(w, " {"); + for (isize i = 0; i < type->BitField.fields.count; i++) { + Entity *f = type->BitField.fields[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, ":"); + w = write_type_to_canonical_string(w, f->type); + w = gb_string_appendc(w, "|"); + w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); + } + return gb_string_appendc(w, " }"); + + case Type_Proc: + w = gb_string_appendc(w, "proc"); + if (default_calling_convention() != type->Proc.calling_convention) { + w = gb_string_appendc(w, "\""); + w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); + w = gb_string_appendc(w, "\""); + } + + w = write_canonical_params(w, type->Proc.params); + if (type->Proc.result_count > 0) { + w = gb_string_appendc(w, "->"); + w = write_canonical_params(w, type->Proc.results); + } + return w; + + case Type_Generic: + GB_PANIC("Type_Generic should never be hit"); + return w; + + case Type_Named: + if (type->Named.type_name != nullptr) { + return write_canonical_entity_name(w, type->Named.type_name); + } else { + w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); + } + // Handle parapoly stuff here? + return w; + + default: + GB_PANIC("unknown type kind %d", type->kind); + break; + } + + return w; +} \ No newline at end of file diff --git a/src/types.cpp b/src/types.cpp index 42530eccc..d6dea56ad 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4872,272 +4872,3 @@ gb_internal gbString type_to_string(Type *type, bool shorthand) { gb_internal gbString type_to_string_shorthand(Type *type) { return type_to_string(type, true); } - -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); -gb_internal gbString write_canonical_params(gbString w, Type *params) { - w = gb_string_appendc(w, "("); - if (params) { - GB_ASSERT(params->kind == Type_Tuple); - for_array(i, params->Tuple.variables) { - Entity *v = params->Tuple.variables[i]; - if (i > 0) { - w = gb_string_appendc(w, ","); - } - if (v->kind == Entity_Variable) { - if (v->flags&EntityFlag_CVarArg) { - w = gb_string_appendc(w, "#c_vararg"); - } - if (v->flags&EntityFlag_Ellipsis) { - Type *slice = base_type(v->type); - w = gb_string_appendc(w, ".."); - GB_ASSERT(v->type->kind == Type_Slice); - w = write_type_to_canonical_string(w, slice->Slice.elem); - } else { - w = write_type_to_canonical_string(w, v->type); - } - } else if (v->kind == Entity_TypeName) { - w = gb_string_appendc(w, "$"); - w = write_type_to_canonical_string(w, v->type); - } else if (v->kind == Entity_Constant) { - w = gb_string_appendc(w, "$$"); - w = write_exact_value_to_string(w, v->Constant.value); - } else { - GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); - } - } - } - return gb_string_appendc(w, ")"); -} - -gb_internal u64 type_hash_canonical_type(Type *type) { - if (type == nullptr) { - return 0; - } - TEMPORARY_ALLOCATOR_GUARD(); - gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); - u64 hash = fnv64a(w, gb_string_length(w)); - return hash; -} - -gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { - gbString w = gb_string_make(allocator, ""); - w = write_type_to_canonical_string(w, type); - return make_string(cast(u8 const *)w, gb_string_length(w)); -} - -// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { - if (type == nullptr) { - return gb_string_appendc(w, "<>"); // none/void type - } - - type = default_type(type); - GB_ASSERT(!is_type_untyped(type)); - - switch (type->kind) { - case Type_Basic: - return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); - case Type_Pointer: - w = gb_string_append_rune(w, '^'); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_MultiPointer: - w = gb_string_appendc(w, "[^]"); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_SoaPointer: - w = gb_string_appendc(w, "#soa^"); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_EnumeratedArray: - if (type->EnumeratedArray.is_sparse) { - w = gb_string_appendc(w, "#sparse"); - } - w = gb_string_append_rune(w, '['); - w = write_type_to_canonical_string(w, type->EnumeratedArray.index); - w = gb_string_append_rune(w, ']'); - return write_type_to_canonical_string(w, type->EnumeratedArray.elem); - case Type_Array: - w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); - return write_type_to_canonical_string(w, type->Array.elem); - case Type_Slice: - w = gb_string_appendc(w, "[]"); - return write_type_to_canonical_string(w, type->Array.elem); - case Type_DynamicArray: - w = gb_string_appendc(w, "[dynamic]"); - return write_type_to_canonical_string(w, type->DynamicArray.elem); - case Type_SimdVector: - w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); - return write_type_to_canonical_string(w, type->SimdVector.elem); - case Type_Matrix: - if (type->Matrix.is_row_major) { - w = gb_string_appendc(w, "#row_major "); - } - w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); - return write_type_to_canonical_string(w, type->Matrix.elem); - case Type_Map: - w = gb_string_appendc(w, "map["); - w = write_type_to_canonical_string(w, type->Map.key); - w = gb_string_appendc(w, "]"); - return write_type_to_canonical_string(w, type->Map.value); - - case Type_Enum: - w = gb_string_appendc(w, "enum"); - if (type->Enum.base_type != nullptr) { - w = gb_string_append_rune(w, ' '); - w = write_type_to_canonical_string(w, type->Enum.base_type); - w = gb_string_append_rune(w, ' '); - } - w = gb_string_append_rune(w, '{'); - for_array(i, type->Enum.fields) { - Entity *f = type->Enum.fields[i]; - GB_ASSERT(f->kind == Entity_Constant); - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, "="); - w = write_exact_value_to_string(w, f->Constant.value); - } - return gb_string_append_rune(w, '}'); - case Type_BitSet: - w = gb_string_appendc(w, "bit_set["); - if (type->BitSet.elem == nullptr) { - w = write_type_to_canonical_string(w, type->BitSet.elem); - } else if (is_type_enum(type->BitSet.elem)) { - w = write_type_to_canonical_string(w, type->BitSet.elem); - } else { - w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); - w = gb_string_append_fmt(w, "..="); - w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); - } - if (type->BitSet.underlying != nullptr) { - w = gb_string_appendc(w, ";"); - w = write_type_to_canonical_string(w, type->BitSet.underlying); - } - return gb_string_appendc(w, "]"); - - case Type_Union: - w = gb_string_appendc(w, "union"); - - switch (type->Union.kind) { - case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; - case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; - } - if (type->Union.custom_align != 0) { - w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); - } - w = gb_string_appendc(w, "{"); - for_array(i, type->Union.variants) { - Type *t = type->Union.variants[i]; - if (i > 0) w = gb_string_appendc(w, ", "); - w = write_type_to_canonical_string(w, t); - } - return gb_string_appendc(w, "}"); - case Type_Struct: - if (type->Struct.soa_kind != StructSoa_None) { - switch (type->Struct.soa_kind) { - case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; - case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; - case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; - default: GB_PANIC("Unknown StructSoaKind"); break; - } - return write_type_to_canonical_string(w, type->Struct.soa_elem); - } - - w = gb_string_appendc(w, "struct"); - if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); - if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); - if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); - if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); - if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); - if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); - w = gb_string_appendc(w, "{"); - for_array(i, type->Struct.fields) { - Entity *f = type->Struct.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length (w, f->token.string.text, f->token.string.len); - w = gb_string_appendc (w, ":"); - w = write_type_to_canonical_string(w, f->type); - String tag = type->Struct.tags[i]; - if (tag.len != 0) { - String s = quote_to_ascii(heap_allocator(), tag); - w = gb_string_append_length(w, s.text, s.len); - gb_free(heap_allocator(), s.text); - } - } - return gb_string_appendc(w, "}"); - - case Type_BitField: - w = gb_string_appendc(w, "bit_field"); - w = write_type_to_canonical_string(w, type->BitField.backing_type); - w = gb_string_appendc(w, " {"); - for (isize i = 0; i < type->BitField.fields.count; i++) { - Entity *f = type->BitField.fields[i]; - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, ":"); - w = write_type_to_canonical_string(w, f->type); - w = gb_string_appendc(w, "|"); - w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); - } - return gb_string_appendc(w, " }"); - - case Type_Proc: - w = gb_string_appendc(w, "proc"); - if (default_calling_convention() != type->Proc.calling_convention) { - w = gb_string_appendc(w, "\""); - w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); - w = gb_string_appendc(w, "\""); - } - - w = write_canonical_params(w, type->Proc.params); - if (type->Proc.result_count > 0) { - w = gb_string_appendc(w, "->"); - w = write_canonical_params(w, type->Proc.results); - } - return w; - - case Type_Generic: - GB_PANIC("Type_Generic should never be hit"); - return w; - - case Type_Named: - if (type->Named.type_name != nullptr) { - Entity *e = type->Named.type_name; - - if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || - e->flags & EntityFlag_NotExported) { - if (e->scope->flags & ScopeFlag_Proc) { - GB_PANIC("NESTED IN PROC\n"); - } else if (e->scope->flags & ScopeFlag_File) { - GB_PANIC("PRIVATE TO FILE\n"); - } - } - if (e->pkg != nullptr) { - w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); - w = gb_string_appendc(w, "."); - } - Type *params = nullptr; - Entity *parent = type_get_polymorphic_parent(type, ¶ms); - if (parent) { - w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); - w = write_canonical_params(w, params); - } else { - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); - } - } else { - w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); - } - // Handle parapoly stuff here? - return w; - - default: - GB_PANIC("unknown type kind %d", type->kind); - break; - } - - return w; -} \ No newline at end of file -- cgit v1.2.3 From 9b26bb2e6a1e32e17102550b481c6909549b87e5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 13:10:38 +0000 Subject: Begin work on hash types --- src/checker.cpp | 44 +++++++++++++++++++++++++++++++++++++++++-- src/checker.hpp | 7 ++++++- src/llvm_backend.cpp | 7 ++++--- src/llvm_backend_general.cpp | 2 -- src/llvm_backend_type.cpp | 6 +++--- src/name_canonicalization.cpp | 25 +++++++++++++++++++----- src/ptr_set.cpp | 10 +++++----- src/types.cpp | 36 +++++++++++++++++++++++++++++++++-- 8 files changed, 114 insertions(+), 23 deletions(-) (limited to 'src/types.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index c74a72a14..054d6aeb0 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3,7 +3,10 @@ #include "entity.cpp" #include "types.cpp" -String get_final_microarchitecture(); + +gb_internal u64 type_hash_canonical_type(Type *type); + +gb_internal String get_final_microarchitecture(); gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression); gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr); @@ -2037,7 +2040,8 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { // Unique entry // NOTE(bill): map entries grow linearly and in order ti_index = c->info->type_info_types.count; - array_add(&c->info->type_info_types, t); + Type_Info_Type tt = {t, type_hash_canonical_type(t)}; + array_add(&c->info->type_info_types, tt); } map_set(&c->checker->info.type_info_map, t, ti_index); @@ -6725,6 +6729,42 @@ gb_internal void check_parsed_files(Checker *c) { add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value); } + TIME_SECTION("check for type hash collisions"); + { + PtrSet found = {}; + ptr_set_init(&found, c->info.type_info_types.count); + defer (ptr_set_destroy(&found)); + for (auto const &tt : c->info.type_info_types) { + if (ptr_set_update(&found, cast(uintptr)tt.hash)) { + Type *other_type = nullptr; + for (auto const &other : c->info.type_info_types) { + if (&tt == &other) { + continue; + } + if (cast(uintptr)other.hash == cast(uintptr)tt.hash && + !are_types_identical(tt.type, other.type)) { + other_type = other.type; + break; + } + } + if (other_type != nullptr) { + String ts = type_to_canonical_string(temporary_allocator(), tt.type); + String os = type_to_canonical_string(temporary_allocator(), other_type); + if (ts != os) { + compiler_error("%s found type hash collision with %s (hash = %llu)\n" + "%s vs %s\n", + type_to_string(tt.type), type_to_string(other_type), cast(unsigned long long)tt.hash, + temp_canonical_string(tt.type), + temp_canonical_string(other_type) + ); + } + } + } + } + } + + + TIME_SECTION("sort init and fini procedures"); check_sort_init_and_fini_procedures(c); diff --git a/src/checker.hpp b/src/checker.hpp index 472ab8e50..c9a0c3302 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -409,6 +409,11 @@ struct Defineable { String pos_str; }; +struct Type_Info_Type { + Type *type; + u64 hash; // see: type_hash_canonical_type +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -453,7 +458,7 @@ struct CheckerInfo { PtrMap gen_types; BlockingMutex type_info_mutex; // NOT recursive - Array type_info_types; + Array type_info_types; PtrMap type_info_map; BlockingMutex foreign_mutex; // NOT recursive diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0896ea8c7..8cb480dd4 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -24,7 +24,7 @@ #include "llvm_backend_stmt.cpp" #include "llvm_backend_proc.cpp" -String get_default_microarchitecture() { +gb_internal String get_default_microarchitecture() { String default_march = str_lit("generic"); if (build_context.metrics.arch == TargetArch_amd64) { // NOTE(bill): x86-64-v2 is more than enough for everyone @@ -47,7 +47,7 @@ String get_default_microarchitecture() { return default_march; } -String get_final_microarchitecture() { +gb_internal String get_final_microarchitecture() { BuildContext *bc = &build_context; String microarch = bc->microarch; @@ -3182,7 +3182,8 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { isize count = 0; isize offsets_extra = 0; - for (Type *t : m->info->type_info_types) { + for (auto const &tt : m->info->type_info_types) { + Type *t = tt.type; isize index = lb_type_info_index(m->info, t, false); if (index < 0) { continue; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7fdfa0bb2..b9ae3d254 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1460,8 +1460,6 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { w = write_canonical_entity_name(w, e); defer (gb_string_free(w)); - gb_printf_err("%s\n", w); - String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); if (e->kind == Entity_TypeName) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 6c12b37be..6f9f94fbd 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -12,7 +12,7 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count); for (auto const &entry : *set) { isize type_info_index = entry.key; - gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index])); + gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type)); } GB_PANIC("NOT FOUND"); } @@ -280,7 +280,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count); defer (gb_free(heap_allocator(), modified_types)); for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; + Type *t = info->type_info_types[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } @@ -343,7 +343,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ }; for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; + Type *t = info->type_info_types[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 3910c573d..8edb5e968 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -7,7 +7,7 @@ * builtin names - just their normal name e.g. `i32` or `string` * nested - pkg.parent1.parent2.name * file private - pkg.[file_name].name - * Example: `foo.[bar.odin].Type` + * Example: `pkg.[file.odin].Type` * polymorphic procedure/type - pkg.foo::TYPE * naming convention for parameters * type @@ -15,7 +15,7 @@ * $$constant_parameter * Example: `foo.to_thing::proc(u64)->([]u8)` * nested decl in polymorphic procedure - pkg.foo::TYPE.name - * anonymous procedures - pkg.foo.$anon123 + * anonymous procedures - pkg.foo.$anon[file.odin:123] * 123 is the file offset in bytes @@ -38,7 +38,12 @@ #define CANONICAL_NONE_TYPE "<>" + gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +gb_internal u64 type_hash_canonical_type(Type *type); +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type); +gb_internal gbString temp_canonical_string(Type *type); + gb_internal gbString write_canonical_params(gbString w, Type *params) { w = gb_string_appendc(w, "("); if (params) { @@ -81,7 +86,7 @@ gb_internal u64 type_hash_canonical_type(Type *type) { TEMPORARY_ALLOCATOR_GUARD(); gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); u64 hash = fnv64a(w, gb_string_length(w)); - return hash; + return hash ? hash : 1; } gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { @@ -90,6 +95,11 @@ gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { return make_string(cast(u8 const *)w, gb_string_length(w)); } +gb_internal gbString temp_canonical_string(Type *type) { + gbString w = gb_string_make(temporary_allocator(), ""); + return write_type_to_canonical_string(w, type); +} + gb_internal void print_scope_flags(Scope *s) { if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg "); if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin "); @@ -156,7 +166,8 @@ gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool i } if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { - w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "%d", e->token.pos.offset)); + String file_name = filename_without_directory(e->file->fullpath); + w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset)); } else { w = gb_string_append_length(w, e->token.string.text, e->token.string.len); } @@ -449,8 +460,12 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { } return w; + case Type_Tuple: + w = gb_string_appendc(w, "params"); + w = write_canonical_params(w, type); + return w; default: - GB_PANIC("unknown type kind %d", type->kind); + GB_PANIC("unknown type kind %d %.*s", type->kind, LIT(type_strings[type->kind])); break; } diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index ff4befc37..5097e2bb6 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -42,7 +42,7 @@ gb_internal void ptr_set_destroy(PtrSet *s) { template gb_internal isize ptr_set__find(PtrSet *s, T ptr) { - GB_ASSERT(ptr != nullptr); + GB_ASSERT(ptr != 0); if (s->count != 0) { #if 0 for (usize i = 0; i < s->capacity; i++) { @@ -58,7 +58,7 @@ gb_internal isize ptr_set__find(PtrSet *s, T ptr) { T key = s->keys[hash_index]; if (key == ptr) { return hash_index; - } else if (key == nullptr) { + } else if (key == 0) { return -1; } hash_index = (hash_index+1)&mask; @@ -122,7 +122,7 @@ gb_internal bool ptr_set_update(PtrSet *s, T ptr) { // returns true if it pre for (usize i = 0; i < s->capacity; i++) { T *key = &s->keys[hash_index]; GB_ASSERT(*key != ptr); - if (*key == (T)PtrSet::TOMBSTONE || *key == nullptr) { + if (*key == (T)PtrSet::TOMBSTONE || *key == 0) { *key = ptr; s->count++; return false; @@ -169,7 +169,7 @@ struct PtrSetIterator { return *this; } T key = set->keys[index]; - if (key != nullptr && key != (T)PtrSet::TOMBSTONE) { + if (key != 0 && key != (T)PtrSet::TOMBSTONE) { return *this; } } @@ -191,7 +191,7 @@ gb_internal PtrSetIterator begin(PtrSet &set) noexcept { usize index = 0; while (index < set.capacity) { T key = set.keys[index]; - if (key != nullptr && key != (T)PtrSet::TOMBSTONE) { + if (key != 0 && key != (T)PtrSet::TOMBSTONE) { break; } index++; diff --git a/src/types.cpp b/src/types.cpp index d6dea56ad..15e1bcf45 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2774,7 +2774,37 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Enum: - return x == y; // NOTE(bill): All enums are unique + if (x == y) { + return true; + } + if (x->Enum.fields.count != y->Enum.fields.count) { + return false; + } + if (!are_types_identical(x->Enum.base_type, y->Enum.base_type)) { + return false; + } + if (x->Enum.min_value_index != y->Enum.min_value_index) { + return false; + } + if (x->Enum.max_value_index != y->Enum.max_value_index) { + return false; + } + + for (isize i = 0; i < x->Enum.fields.count; i++) { + Entity *a = x->Enum.fields[i]; + Entity *b = y->Enum.fields[i]; + if (a->token.string != b->token.string) { + return false; + } + GB_ASSERT(a->kind == b->kind); + GB_ASSERT(a->kind == Entity_Constant); + bool same = compare_exact_values(Token_CmpEq, a->Constant.value, b->Constant.value); + if (!same) { + return false; + } + } + + return true; case Type_Union: if (x->Union.variants.count == y->Union.variants.count && @@ -2832,7 +2862,9 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple return false; } } - return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params); + // TODO(bill): Which is the correct logic here? + // return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params); + return true; } break; -- cgit v1.2.3 From 0ab323012e4fd0303a7e41587a5919c9be028561 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 11:12:59 +0000 Subject: Use `TypeSet` instead of `PtrSet` --- src/check_stmt.cpp | 8 ++++---- src/types.cpp | 34 ---------------------------------- 2 files changed, 4 insertions(+), 38 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1708f7c81..e81996566 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1446,8 +1446,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ Ast *nil_seen = nullptr; - PtrSet seen = {}; - defer (ptr_set_destroy(&seen)); + TypeSet seen = {}; + defer (type_set_destroy(&seen)); for (Ast *stmt : bs->stmts) { if (stmt->kind != Ast_CaseClause) { @@ -1515,7 +1515,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ GB_PANIC("Unknown type to type switch statement"); } - if (type_ptr_set_update(&seen, y.type)) { + if (type_set_update(&seen, y.type)) { TokenPos pos = cc->token.pos; gbString expr_str = expr_to_string(y.expr); error(y.expr, @@ -1569,7 +1569,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ auto unhandled = array_make(temporary_allocator(), 0, variants.count); for (Type *t : variants) { - if (!type_ptr_set_exists(&seen, t)) { + if (!type_set_exists(&seen, t)) { array_add(&unhandled, t); } } diff --git a/src/types.cpp b/src/types.cpp index 15e1bcf45..9b23fad0f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -856,40 +856,6 @@ gb_internal void type_path_pop(TypePath *tp) { #define FAILURE_SIZE 0 #define FAILURE_ALIGNMENT 0 -gb_internal bool type_ptr_set_exists(PtrSet *s, Type *t); - -gb_internal bool type_ptr_set_update(PtrSet *s, Type *t) { - if (t == nullptr) { - return true; - } - if (type_ptr_set_exists(s, t)) { - return true; - } - ptr_set_add(s, t); - return false; -} - -gb_internal bool type_ptr_set_exists(PtrSet *s, Type *t) { - if (t == nullptr) { - return true; - } - - if (ptr_set_exists(s, t)) { - return true; - } - - // TODO(bill, 2019-10-05): This is very slow and it's probably a lot - // faster to cache types correctly - for (Type *f : *s) { - if (are_types_identical(t, f)) { - ptr_set_add(s, t); - return true; - } - } - - return false; -} - gb_internal Type *base_type(Type *t) { for (;;) { if (t == nullptr) { -- cgit v1.2.3 From 5489a889832ac05e5edca7355b4601c1a82c2d27 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 14:10:45 +0000 Subject: Change `typeid` definition to be based around the canonical type hash `typeid` used to be a fancy index with extra metadata stored on it. Now it is direct hash of the type. This is safe to do in practice since any possible collisions are checked at compile time AND the chances of having a 1% collision are around 1 in 600K (see the Birthday Paradox). Therefore accessing a `^Type_Info` is now a hash table lookup with linear probing. The table is twice the size than necessary so prevent too much probing due to an overly dense hash table. --- base/runtime/core.odin | 56 ++++++++-------------------------------------- odin.rdi | Bin 6593532 -> 0 bytes src/checker.cpp | 45 ++++++++++++++++++++++++------------- src/checker.hpp | 1 + src/llvm_backend.cpp | 5 +++-- src/llvm_backend_type.cpp | 52 ++++++++++++------------------------------ src/types.cpp | 16 ++++++------- 7 files changed, 64 insertions(+), 111 deletions(-) delete mode 100644 odin.rdi (limited to 'src/types.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index e47f3ecbc..94a126082 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -239,47 +239,6 @@ Type_Info :: struct { }, } -// NOTE(bill): This must match the compiler's -Typeid_Kind :: enum u8 { - Invalid, - Integer, - Rune, - Float, - Complex, - Quaternion, - String, - Boolean, - Any, - Type_Id, - Pointer, - Multi_Pointer, - Procedure, - Array, - Enumerated_Array, - Dynamic_Array, - Slice, - Tuple, - Struct, - Union, - Enum, - Map, - Bit_Set, - Simd_Vector, - Matrix, - Soa_Pointer, - Bit_Field, -} -#assert(len(Typeid_Kind) < 32) - -Typeid_Bit_Field :: bit_field uintptr { - index: uintptr | 8*size_of(uintptr) - 8, - kind: Typeid_Kind | 5, // Typeid_Kind - named: bool | 1, - special: bool | 1, // signed, cstring, etc - reserved: bool | 1, -} -#assert(size_of(Typeid_Bit_Field) == size_of(uintptr)) - // NOTE(bill): only the ones that are needed (not all types) // This will be set by the compiler type_table: []^Type_Info @@ -686,13 +645,16 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { type_info_base_without_enum :: type_info_core __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check { - MASK :: 1<<(8*size_of(typeid) - 8) - 1 - data := transmute(uintptr)id - n := int(data & MASK) - if n < 0 || n >= len(type_table) { - n = 0 + n := u64(len(type_table)) + i := transmute(u64)id % n + for k in 0..info.type_info_types, type_info_pair_cmp); + array_init(&c->info.type_info_types_hash_map, heap_allocator(), c->info.type_info_types.count*2 + 1); map_reserve(&c->info.minimum_dependency_type_info_index_map, c->info.type_info_types.count); - for_array(i, c->info.type_info_types) { - auto const &tt = c->info.type_info_types[i]; - bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, tt.hash, i); - if (!exists) { - continue; - } - for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { - if (entry.key != tt.hash) { + isize hash_map_len = c->info.type_info_types_hash_map.count; + for (auto const &tt : c->info.type_info_types) { + isize index = tt.hash % hash_map_len; + // NOTE(bill): no need for a sanity check since there + // will always be enough space for the entries + for (;;) { + if (index == 0 || c->info.type_info_types_hash_map[index].hash != 0) { + index = (index+1) % hash_map_len; continue; } - auto const &other = c->info.type_info_types[entry.value]; - if (are_types_identical_unique_tuples(tt.type, other.type)) { - continue; + break; + } + c->info.type_info_types_hash_map[index] = tt; + + bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, tt.hash, index); + if (exists) { + for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { + if (entry.key != tt.hash) { + continue; + } + auto const &other = c->info.type_info_types[entry.value]; + if (are_types_identical_unique_tuples(tt.type, other.type)) { + continue; + } + gbString t = temp_canonical_string(tt.type); + gbString o = temp_canonical_string(other.type); + GB_PANIC("%s (%s) %llu vs %s (%s) %llu", + type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash, + type_to_string(other.type, false), o, cast(unsigned long long)other.hash); } - gbString t = temp_canonical_string(tt.type); - gbString o = temp_canonical_string(other.type); - GB_PANIC("%s (%s) %llu vs %s (%s) %llu", - type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash, - type_to_string(other.type, false), o, cast(unsigned long long)other.hash); } } + GB_ASSERT(c->info.minimum_dependency_type_info_index_map.count <= c->info.type_info_types.count); } diff --git a/src/checker.hpp b/src/checker.hpp index 3d1e5b6eb..d482f396c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -432,6 +432,7 @@ struct CheckerInfo { PtrMap minimum_dependency_type_info_index_map; TypeSet min_dep_type_info_set; Array type_info_types; // sorted after filled + Array type_info_types_hash_map; // 2 * type_info_types.count Array testing_procedures; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 908117501..4ebcf7578 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3154,9 +3154,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lbModule *m = default_module; { // Add type info data - GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count); + // GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count); - isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1; + // isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1; + isize max_type_info_count = info->type_info_types_hash_map.count; Type *t = alloc_type_array(t_type_info_ptr, max_type_info_count); // IMPORTANT NOTE(bill): As LLVM does not have a union type, an array of unions cannot be initialized diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 8e0f15f35..170da5b2b 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -2,13 +2,13 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err_on_not_found=true) { isize index = type_info_index(info, pair, err_on_not_found); if (index >= 0) { - return index+1; + return index; } if (err_on_not_found) { gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(pair.type), index, info->minimum_dependency_type_info_index_map.count); for (auto const &entry : info->minimum_dependency_type_info_index_map) { isize type_info_index = entry.key; - gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type)); + gb_printf_err("\t%s\n", type_to_string(info->type_info_types_hash_map[type_info_index].type)); } GB_PANIC("NOT FOUND"); } @@ -73,37 +73,8 @@ gb_internal lbValue lb_typeid(lbModule *m, Type *type) { type = default_type(type); - u64 id = cast(u64)lb_type_info_index(m->info, type); - GB_ASSERT(id >= 0); - - u64 kind = lb_typeid_kind(m, type, id); - u64 named = is_type_named(type) && type->kind != Type_Basic; - u64 special = 0; - u64 reserved = 0; - - if (is_type_cstring(type)) { - special = 1; - } else if (is_type_integer(type) && !is_type_unsigned(type)) { - special = 1; - } - - u64 data = 0; - if (build_context.ptr_size == 4) { - GB_ASSERT(id <= (1u<<24u)); - data |= (id &~ (1u<<24)) << 0u; // index - data |= (kind &~ (1u<<5)) << 24u; // kind - data |= (named &~ (1u<<1)) << 29u; // named - data |= (special &~ (1u<<1)) << 30u; // special - data |= (reserved &~ (1u<<1)) << 31u; // reserved - } else { - GB_ASSERT(build_context.ptr_size == 8); - GB_ASSERT(id <= (1ull<<56u)); - data |= (id &~ (1ull<<56)) << 0ul; // index - data |= (kind &~ (1ull<<5)) << 56ull; // kind - data |= (named &~ (1ull<<1)) << 61ull; // named - data |= (special &~ (1ull<<1)) << 62ull; // special - data |= (reserved &~ (1ull<<1)) << 63ull; // reserved - } + u64 data = type_hash_canonical_type(type); + GB_ASSERT(data != 0); lbValue res = {}; res.value = LLVMConstInt(lb_type(m, t_typeid), data, false); @@ -279,8 +250,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count); defer (gb_free(heap_allocator(), modified_types)); - for_array(type_info_type_index, info->type_info_types) { - auto const &tt = info->type_info_types[type_info_type_index]; + for_array(type_info_type_index, info->type_info_types_hash_map) { + auto const &tt = info->type_info_types_hash_map[type_info_type_index]; Type *t = tt.type; if (t == nullptr || t == t_invalid) { continue; @@ -343,8 +314,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ return giant_const_values[index]; }; - for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index].type; + for_array(type_info_type_index, info->type_info_types_hash_map) { + Type *t = info->type_info_types_hash_map[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } @@ -1072,7 +1043,12 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ LLVMSetInitializer(giant_const_values[entry_index], LLVMConstNamedStruct(stype, small_const_values, variant_index+1)); } for (isize i = 0; i < global_type_info_data_entity_count; i++) { - giant_const_values[i] = LLVMConstPointerCast(giant_const_values[i], lb_type(m, t_type_info_ptr)); + auto *ptr = &giant_const_values[i]; + if (*ptr != nullptr) { + *ptr = LLVMConstPointerCast(*ptr, lb_type(m, t_type_info_ptr)); + } else { + *ptr = LLVMConstNull(lb_type(m, t_type_info_ptr)); + } } diff --git a/src/types.cpp b/src/types.cpp index 9b23fad0f..fedb85230 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -503,9 +503,9 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}}, {Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}}, {Type_Basic, {Basic_cstring, BasicFlag_String, -1, STR_LIT("cstring")}}, - {Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}}, + {Type_Basic, {Basic_any, 0, 16, STR_LIT("any")}}, - {Type_Basic, {Basic_typeid, 0, -1, STR_LIT("typeid")}}, + {Type_Basic, {Basic_typeid, 0, 8, STR_LIT("typeid")}}, // Endian {Type_Basic, {Basic_i16le, BasicFlag_Integer | BasicFlag_EndianLittle, 2, STR_LIT("i16le")}}, @@ -3700,7 +3700,7 @@ gb_internal i64 type_size_of(Type *t) { switch (t->Basic.kind) { case Basic_string: size = 2*build_context.int_size; break; case Basic_cstring: size = build_context.ptr_size; break; - case Basic_any: size = 2*build_context.ptr_size; break; + case Basic_any: size = 16; break; case Basic_typeid: size = build_context.ptr_size; break; case Basic_int: case Basic_uint: @@ -3763,7 +3763,7 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { switch (t->Basic.kind) { case Basic_string: return build_context.int_size; case Basic_cstring: return build_context.ptr_size; - case Basic_any: return build_context.ptr_size; + case Basic_any: return 8; case Basic_typeid: return build_context.ptr_size; case Basic_int: case Basic_uint: @@ -4014,7 +4014,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { switch (kind) { case Basic_string: return 2*build_context.int_size; case Basic_cstring: return build_context.ptr_size; - case Basic_any: return 2*build_context.ptr_size; + case Basic_any: return 16; case Basic_typeid: return build_context.ptr_size; case Basic_int: case Basic_uint: @@ -4251,7 +4251,7 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) { return 0; // data case 1: if (field_type_) *field_type_ = t_typeid; - return build_context.ptr_size; // id + return 8; // id } } break; @@ -4322,8 +4322,8 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) { } } else if (t->Basic.kind == Basic_any) { switch (index) { - case 0: t = t_type_info_ptr; break; - case 1: t = t_rawptr; break; + case 0: t = t_rawptr; break; + case 1: t = t_typeid; break; } } break; -- cgit v1.2.3 From 614c0dd7401271f7ddad5eaeb4de234021fe387c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 17:09:28 +0000 Subject: Fix `typeid` size for 32-bit platforms --- base/runtime/core.odin | 2 ++ src/types.cpp | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/types.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 285883c2b..db5e4d698 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -442,10 +442,12 @@ Raw_Any :: struct { data: rawptr, id: typeid, } +#assert(size_of(Raw_Any) == size_of(any)) Raw_Cstring :: struct { data: [^]byte, } +#assert(size_of(Raw_Cstring) == size_of(cstring)) Raw_Soa_Pointer :: struct { data: rawptr, diff --git a/src/types.cpp b/src/types.cpp index fedb85230..056737af5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3701,7 +3701,7 @@ gb_internal i64 type_size_of(Type *t) { case Basic_string: size = 2*build_context.int_size; break; case Basic_cstring: size = build_context.ptr_size; break; case Basic_any: size = 16; break; - case Basic_typeid: size = build_context.ptr_size; break; + case Basic_typeid: size = 8; break; case Basic_int: case Basic_uint: size = build_context.int_size; @@ -3764,7 +3764,7 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { case Basic_string: return build_context.int_size; case Basic_cstring: return build_context.ptr_size; case Basic_any: return 8; - case Basic_typeid: return build_context.ptr_size; + case Basic_typeid: return 8; case Basic_int: case Basic_uint: return build_context.int_size; @@ -4015,7 +4015,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { case Basic_string: return 2*build_context.int_size; case Basic_cstring: return build_context.ptr_size; case Basic_any: return 16; - case Basic_typeid: return build_context.ptr_size; + case Basic_typeid: return 8; case Basic_int: case Basic_uint: return build_context.int_size; -- cgit v1.2.3 From d0d5cf800eb0dc039c124cc62cea74589b6e2f6c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 15:49:49 +0000 Subject: Fix `nullptr` check --- src/types.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index 056737af5..43fe625f2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2087,6 +2087,9 @@ gb_internal bool is_type_sliceable(Type *t) { gb_internal Entity *type_get_polymorphic_parent(Type *t, Type **params_) { t = base_type(t); + if (t == nullptr) { + return nullptr; + } Type *parent = nullptr; if (t->kind == Type_Struct) { parent = t->Struct.polymorphic_parent; -- cgit v1.2.3