From f6f3a760bcdbad183a4141738b19779e88ed7dfc Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 21 Feb 2024 22:05:11 +0100 Subject: Promote types in `#c_varargs` according to C rules --- src/types.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index 2f1994574..c31b6e1bd 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -548,6 +548,14 @@ gb_global Type *t_f16 = &basic_types[Basic_f16]; gb_global Type *t_f32 = &basic_types[Basic_f32]; gb_global Type *t_f64 = &basic_types[Basic_f64]; +gb_global Type *t_f16be = &basic_types[Basic_f16be]; +gb_global Type *t_f32be = &basic_types[Basic_f32be]; +gb_global Type *t_f64be = &basic_types[Basic_f64be]; + +gb_global Type *t_f16le = &basic_types[Basic_f16le]; +gb_global Type *t_f32le = &basic_types[Basic_f32le]; +gb_global Type *t_f64le = &basic_types[Basic_f64le]; + gb_global Type *t_complex32 = &basic_types[Basic_complex32]; gb_global Type *t_complex64 = &basic_types[Basic_complex64]; gb_global Type *t_complex128 = &basic_types[Basic_complex128]; @@ -2795,6 +2803,44 @@ gb_internal Type *default_type(Type *type) { return type; } +// See https://en.cppreference.com/w/c/language/conversion#Default_argument_promotions +gb_internal Type *c_vararg_promote_type(Type *type) { + GB_ASSERT(type != nullptr); + + Type *core = core_type(type); + if (core->kind == Type_Basic) { + switch (core->Basic.kind) { + case Basic_f32: + case Basic_UntypedFloat: + return t_f64; + case Basic_f32le: + return t_f64le; + case Basic_f32be: + return t_f64be; + + case Basic_UntypedBool: + case Basic_bool: + case Basic_b8: + case Basic_b16: + case Basic_i8: + case Basic_i16: + case Basic_u8: + case Basic_u16: + return t_i32; + + case Basic_i16le: + case Basic_u16le: + return t_i32le; + + case Basic_i16be: + case Basic_u16be: + return t_i32be; + } + } + + return type; +} + gb_internal bool union_variant_index_types_equal(Type *v, Type *vt) { if (are_types_identical(v, vt)) { return true; -- cgit v1.2.3 From 213b2fd0f8059751b0cdd05b904c49109b21d474 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 14:01:23 +0000 Subject: Add `bit_field` as a keyword --- core/odin/tokenizer/token.odin | 2 ++ src/tokenizer.cpp | 1 + src/types.cpp | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/types.cpp') diff --git a/core/odin/tokenizer/token.odin b/core/odin/tokenizer/token.odin index 23808cf44..cd8953841 100644 --- a/core/odin/tokenizer/token.odin +++ b/core/odin/tokenizer/token.odin @@ -137,6 +137,7 @@ Token_Kind :: enum u32 { Union, // union Enum, // enum Bit_Set, // bit_set + Bit_Field, // bit_field Map, // map Dynamic, // dynamic Auto_Cast, // auto_cast @@ -270,6 +271,7 @@ tokens := [Token_Kind.COUNT]string { "union", "enum", "bit_set", + "bit_field", "map", "dynamic", "auto_cast", diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index dd9908be5..3d5348074 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -106,6 +106,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \ TOKEN_KIND(Token_union, "union"), \ TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_bit_set, "bit_set"), \ + TOKEN_KIND(Token_bit_field, "bit_field"), \ TOKEN_KIND(Token_map, "map"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \ TOKEN_KIND(Token_auto_cast, "auto_cast"), \ diff --git a/src/types.cpp b/src/types.cpp index 2f1994574..78d281715 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4114,8 +4114,10 @@ gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isi } if (allow_polymorphic && dst_is_polymorphic) { Type *fb = base_type(type_deref(f->type)); - if (fb->kind == Type_Struct && fb->Struct.polymorphic_parent == dst) { - return true; + if (fb->kind == Type_Struct) { + if (fb->Struct.polymorphic_parent == dst) { + return true; + } } } -- cgit v1.2.3 From a4b8c1ea1779ce93349b203aaf56c5aeca316b61 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 15:55:20 +0000 Subject: Begin work adding `bit_field` --- base/runtime/core.odin | 9 +++ base/runtime/print.odin | 14 ++++ core/encoding/json/marshal.odin | 3 + core/fmt/fmt.odin | 65 +++++++++++++++++ core/reflect/reflect.odin | 10 +++ core/reflect/types.odin | 31 ++++++++ src/check_type.cpp | 152 ++++++++++++++++++++++++++++++++++++++++ src/checker.cpp | 18 +++++ src/llvm_backend.cpp | 8 ++- src/llvm_backend_debug.cpp | 36 ++++++++++ src/llvm_backend_general.cpp | 4 +- src/llvm_backend_type.cpp | 67 ++++++++++++++++++ src/parser.cpp | 78 +++++++++++++++++++++ src/parser.hpp | 15 ++++ src/parser_pos.cpp | 3 + src/types.cpp | 24 +++++++ 16 files changed, 535 insertions(+), 2 deletions(-) (limited to 'src/types.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 85e64242d..dcc1e7476 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -181,6 +181,13 @@ Type_Info_Matrix :: struct { Type_Info_Soa_Pointer :: struct { elem: ^Type_Info, } +Type_Info_Bit_Field :: struct { + backing_type: ^Type_Info, + names: []string, + types: []^Type_Info, + bit_sizes: []uintptr, + bit_offsets: []uintptr, +} Type_Info_Flag :: enum u8 { Comparable = 0, @@ -223,6 +230,7 @@ Type_Info :: struct { Type_Info_Relative_Multi_Pointer, Type_Info_Matrix, Type_Info_Soa_Pointer, + Type_Info_Bit_Field, }, } @@ -256,6 +264,7 @@ Typeid_Kind :: enum u8 { Relative_Multi_Pointer, Matrix, Soa_Pointer, + Bit_Field, } #assert(len(Typeid_Kind) < 32) diff --git a/base/runtime/print.odin b/base/runtime/print.odin index 41ff9e1bb..c93c2ab49 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -459,6 +459,20 @@ print_type :: proc "contextless" (ti: ^Type_Info) { } print_byte(']') + case Type_Info_Bit_Field: + print_string("bit_field ") + print_type(info.backing_type) + print_string(" {") + for name, i in info.names { + if i > 0 { print_string(", ") } + print_string(name) + print_string(": ") + print_type(info.types[i]) + print_string(" | ") + print_u64(u64(info.bit_sizes[i])) + } + print_byte('}') + case Type_Info_Simd_Vector: print_string("#simd[") diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index e9285364b..e237892c3 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -228,6 +228,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Matrix: return .Unsupported_Type + case runtime.Type_Info_Bit_Field: + return .Unsupported_Type + case runtime.Type_Info_Array: opt_write_start(w, opt, '[') or_return for i in 0.. (res: u64) { + for i in 0.. 0 { + io.write_string(fi.writer, ", ") + } + if hash { + fmt_write_indent(fi) + } + + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) + + + bit_offset := info.bit_offsets[i] + bit_size := info.bit_sizes[i] + + value := read_bits(([^]byte)(v.data), bit_offset, bit_size) + + fmt_value(fi, any{&value, info.types[i].id}, verb) + if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) } + + } +} + + + // Formats a value based on its type and formatting verb // // Inputs: @@ -2611,6 +2673,9 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Matrix: fmt_matrix(fi, v, verb, info) + + case runtime.Type_Info_Bit_Field: + fmt_bit_field(fi, v, verb, info) } } // Formats a complex number based on the given formatting verb diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 0af23b18e..de5dec2e3 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -35,6 +35,7 @@ Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer Type_Info_Relative_Multi_Pointer :: runtime.Type_Info_Relative_Multi_Pointer Type_Info_Matrix :: runtime.Type_Info_Matrix Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer +Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value @@ -70,6 +71,7 @@ Type_Kind :: enum { Relative_Multi_Pointer, Matrix, Soa_Pointer, + Bit_Field, } @@ -106,6 +108,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer case Type_Info_Matrix: return .Matrix case Type_Info_Soa_Pointer: return .Soa_Pointer + case Type_Info_Bit_Field: return .Bit_Field } } @@ -1604,6 +1607,13 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ } } return true + + case Type_Info_Bit_Field: + x, y := a, b + x.id = v.backing_type.id + y.id = v.backing_type.id + return equal(x, y, including_indirect_array_recursion, recursion_level+0) + } runtime.print_typeid(a.id) diff --git a/core/reflect/types.odin b/core/reflect/types.odin index cbe108d82..2b96dd4fb 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -174,6 +174,23 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { if x.row_count != y.row_count { return false } if x.column_count != y.column_count { return false } return are_types_identical(x.elem, y.elem) + + case Type_Info_Bit_Field: + y := b.variant.(Type_Info_Bit_Field) or_return + if !are_types_identical(x.backing_type, y.backing_type) { return false } + if len(x.names) != len(y.names) { return false } + for _, i in x.names { + if x.names[i] != y.names[i] { + return false + } + if !are_types_identical(x.types[i], y.types[i]) { + return false + } + if x.bit_sizes[i] != y.bit_sizes[i] { + return false + } + } + return true } return false @@ -639,6 +656,20 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - } io.write_byte(w, ']', &n) or_return + case Type_Info_Bit_Field: + io.write_string(w, "bit_field ", &n) or_return + write_type(w, info.backing_type, &n) or_return + io.write_string(w, " {", &n) or_return + for name, i in info.names { + if i > 0 { io.write_string(w, ", ", &n) or_return } + io.write_string(w, name, &n) or_return + io.write_string(w, ": ", &n) or_return + write_type(w, info.types[i], &n) or_return + io.write_string(w, " | ", &n) or_return + io.write_u64(w, u64(info.bit_sizes[i]), 10, &n) or_return + } + io.write_string(w, "}", &n) or_return + case Type_Info_Simd_Vector: io.write_string(w, "#simd[", &n) or_return io.write_i64(w, i64(info.count), 10, &n) or_return diff --git a/src/check_type.cpp b/src/check_type.cpp index 8a140d95e..8afac2fc5 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -925,6 +925,144 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam enum_type->Enum.max_value_index = max_value_index; } +gb_internal bool is_valid_bit_field_backing_type(Type *type) { + if (type == nullptr) { + return nullptr; + } + type = base_type(type); + if (is_type_untyped(type)) { + return false; + } + if (is_type_integer(type)) { + return true; + } + if (type->kind == Type_Array) { + return is_type_integer(type->Array.elem); + } + return false; +} + +gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Type *named_type, Ast *node) { + ast_node(bf, BitFieldType, node); + GB_ASSERT(is_type_bit_field(bit_field_type)); + + Type *backing_type = check_type(ctx, bf->backing_type); + if (backing_type == nullptr || !is_valid_bit_field_backing_type(backing_type)) { + error(node, "Backing type for a bit_field must be an integer or an array of an integer"); + return; + } + + bit_field_type->BitField.backing_type = backing_type; + bit_field_type->BitField.scope = ctx->scope; + + auto fields = array_make(permanent_allocator(), 0, bf->fields.count); + auto bit_sizes = array_make (permanent_allocator(), 0, bf->fields.count); + + u64 maximum_bit_size = 8 * type_size_of(backing_type); + u64 total_bit_size = 0; + + for_array(i, bf->fields) { + i32 field_src_index = cast(i32)i; + Ast *field = bf->fields[i]; + if (field->kind != Ast_BitFieldField) { + error(field, "Invalid AST for a bit_field"); + continue; + } + ast_node(f, BitFieldField, field); + if (f->name == nullptr || f->name->kind != Ast_Ident) { + error(field, "A bit_field's field name must be an identifier"); + continue; + } + CommentGroup *docs = f->docs; + CommentGroup *comment = f->comment; + + String name = f->name->Ident.token.string; + + if (f->type == nullptr) { + error(field, "A bit_field's field must have a type"); + continue; + } + + Type *type = check_type(ctx, f->type); + if (type_size_of(type) > 8) { + error(f->type, "The type of a bit_field's field must be <= 8 bytes, got %lld", cast(long long)type_size_of(type)); + } + + if (is_type_untyped(type)) { + gbString s = type_to_string(type); + error(f->type, "The type of a bit_field's field must be a typed integer, enum, or boolean, got %s", s); + gb_string_free(s); + } else if (!(is_type_integer(type) || is_type_enum(type) || is_type_boolean(type))) { + gbString s = type_to_string(type); + error(f->type, "The type of a bit_field's field must be an integer, enum, or boolean, got %s", s); + gb_string_free(s); + } + + if (f->bit_size == nullptr) { + error(field, "A bit_field's field must have a specified bit size"); + continue; + } + + + Operand o = {}; + check_expr(ctx, &o, f->bit_size); + if (o.mode != Addressing_Constant) { + error(f->bit_size, "A bit_field's specified bit size must be a constant"); + o.mode = Addressing_Invalid; + } + if (o.value.kind == ExactValue_Float) { + o.value = exact_value_to_integer(o.value); + } + + ExactValue bit_size = o.value; + + if (bit_size.kind != ExactValue_Integer) { + gbString s = expr_to_string(f->bit_size); + error(f->bit_size, "Expected an integer constant value for the specified bit size, got %s", s); + gb_string_free(s); + } + + if (scope_lookup_current(ctx->scope, name) != nullptr) { + error(f->name, "'%.*s' is already declared in this bit_field", LIT(name)); + } else { + i64 bit_size_i64 = exact_value_to_i64(bit_size); + u8 bit_size_u8 = 0; + if (bit_size_i64 <= 0) { + error(f->bit_size, "A bit_field's specified bit size cannot be <= 0, got %lld", cast(long long)bit_size_i64); + bit_size_i64 = 1; + } + if (bit_size_i64 > 64) { + error(f->bit_size, "A bit_field's specified bit size cannot exceed 64 bits, got %lld", cast(long long)bit_size_i64); + bit_size_i64 = 64; + } + bit_size_u8 = cast(u8)bit_size_i64; + + Entity *e = alloc_entity_field(ctx->scope, f->name->Ident.token, type, false, field_src_index); + e->Variable.docs = docs; + e->Variable.comment = comment; + + add_entity(ctx, ctx->scope, nullptr, e); + array_add(&fields, e); + array_add(&bit_sizes, bit_size_u8); + add_entity_use(ctx, field, e); + } + } + + GB_ASSERT(fields.count <= bf->fields.count); + + if (total_bit_size > maximum_bit_size) { + gbString s = type_to_string(backing_type); + error(node, "The numbers required %llu exceeds the backing type's (%s) bit size %llu", + cast(unsigned long long)total_bit_size, + s, + cast(unsigned long long)maximum_bit_size); + gb_string_free(s); + } + + bit_field_type->BitField.fields = slice_from_array(fields); + bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); +} + gb_internal bool is_type_valid_bit_set_range(Type *t) { if (is_type_integer(t)) { return true; @@ -3051,6 +3189,20 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T return true; case_end; + case_ast_node(bf, BitFieldType, e); + bool ips = ctx->in_polymorphic_specialization; + defer (ctx->in_polymorphic_specialization = ips); + ctx->in_polymorphic_specialization = false; + + *type = alloc_type_bit_field(); + set_base_type(named_type, *type); + check_open_scope(ctx, e); + check_bit_field_type(ctx, *type, named_type, e); + check_close_scope(ctx); + (*type)->BitField.node = e; + return true; + case_end; + case_ast_node(pt, ProcType, e); bool ips = ctx->in_polymorphic_specialization; diff --git a/src/checker.cpp b/src/checker.cpp index 569a3c76f..5827fc695 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -313,6 +313,7 @@ gb_internal void add_scope(CheckerContext *c, Ast *node, Scope *scope) { case Ast_StructType: node->StructType.scope = scope; break; case Ast_UnionType: node->UnionType.scope = scope; break; case Ast_EnumType: node->EnumType.scope = scope; break; + case Ast_BitFieldType: node->BitFieldType.scope = scope; break; default: GB_PANIC("Invalid node for add_scope: %.*s", LIT(ast_strings[node->kind])); } } @@ -334,6 +335,7 @@ gb_internal Scope *scope_of_node(Ast *node) { case Ast_StructType: return node->StructType.scope; case Ast_UnionType: return node->UnionType.scope; case Ast_EnumType: return node->EnumType.scope; + case Ast_BitFieldType: return node->BitFieldType.scope; } GB_PANIC("Invalid node for add_scope: %.*s", LIT(ast_strings[node->kind])); return nullptr; @@ -355,6 +357,7 @@ gb_internal void check_open_scope(CheckerContext *c, Ast *node) { case Ast_EnumType: case Ast_UnionType: case Ast_BitSetType: + case Ast_BitFieldType: scope->flags |= ScopeFlag_Type; break; } @@ -2060,6 +2063,12 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_type_internal(c, bt->SoaPointer.elem); break; + case Type_BitField: + add_type_info_type_internal(c, bt->BitField.backing_type); + for (Entity *f : bt->BitField.fields) { + add_type_info_type_internal(c, f->type); + } + break; case Type_Generic: break; @@ -2309,6 +2318,13 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->SoaPointer.elem); break; + case Type_BitField: + add_min_dep_type_info(c, bt->BitField.backing_type); + for (Entity *f : bt->BitField.fields) { + add_min_dep_type_info(c, f->type); + } + break; + default: GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind])); break; @@ -2907,6 +2923,7 @@ gb_internal void init_core_type_info(Checker *c) { t_type_info_relative_multi_pointer = find_core_type(c, str_lit("Type_Info_Relative_Multi_Pointer")); t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix")); t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer")); + t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field")); t_type_info_named_ptr = alloc_type_pointer(t_type_info_named); t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); @@ -2936,6 +2953,7 @@ gb_internal void init_core_type_info(Checker *c) { t_type_info_relative_multi_pointer_ptr = alloc_type_pointer(t_type_info_relative_multi_pointer); t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix); t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer); + t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field); } gb_internal void init_mem_allocator(Checker *c) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index fa76ac22f..45d903b43 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2719,6 +2719,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { { // Type info member buffer // NOTE(bill): Removes need for heap allocation by making it global memory isize count = 0; + isize offsets_extra = 0; for (Type *t : m->info->type_info_types) { isize index = lb_type_info_index(m->info, t, false); @@ -2736,6 +2737,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { case Type_Tuple: count += t->Tuple.variables.count; break; + case Type_BitField: + count += t->BitField.fields.count; + // Twice is needed for the bit_offsets + offsets_extra += t->BitField.fields.count; + break; } } @@ -2752,7 +2758,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lb_global_type_info_member_types = global_type_info_make(m, LB_TYPE_INFO_TYPES_NAME, t_type_info_ptr, count); lb_global_type_info_member_names = global_type_info_make(m, LB_TYPE_INFO_NAMES_NAME, t_string, count); - lb_global_type_info_member_offsets = global_type_info_make(m, LB_TYPE_INFO_OFFSETS_NAME, t_uintptr, count); + lb_global_type_info_member_offsets = global_type_info_make(m, LB_TYPE_INFO_OFFSETS_NAME, t_uintptr, count+offsets_extra); lb_global_type_info_member_usings = global_type_info_make(m, LB_TYPE_INFO_USINGS_NAME, t_bool, count); lb_global_type_info_member_tags = global_type_info_make(m, LB_TYPE_INFO_TAGS_NAME, t_string, count); } diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index f45cf0cbc..7d3692a53 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -461,6 +461,42 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { lb_debug_type(m, type->Matrix.elem), subscripts, gb_count_of(subscripts)); } + + case Type_BitField: { + LLVMMetadataRef parent_scope = nullptr; + LLVMMetadataRef scope = nullptr; + LLVMMetadataRef file = nullptr; + unsigned line = 0; + u64 size_in_bits = 8*cast(u64)type_size_of(type); + u32 align_in_bits = 8*cast(u32)type_align_of(type); + LLVMDIFlags flags = LLVMDIFlagZero; + + unsigned element_count = cast(unsigned)type->BitField.fields.count; + LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count); + + u64 offset_in_bits = 0; + for (unsigned i = 0; i < element_count; i++) { + Entity *f = type->BitField.fields[i]; + u8 bit_size = type->BitField.bit_sizes[i]; + GB_ASSERT(f->kind == Entity_Variable); + String name = f->token.string; + unsigned field_line = 0; + LLVMDIFlags field_flags = LLVMDIFlagZero; + elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line, + bit_size, offset_in_bits, offset_in_bits, + field_flags, lb_debug_type(m, f->type) + ); + + offset_in_bits += bit_size; + } + + + return LLVMDIBuilderCreateStructType(m->debug_builder, parent_scope, "", 0, file, line, + size_in_bits, align_in_bits, flags, + nullptr, elements, element_count, 0, nullptr, + "", 0 + ); + } } GB_PANIC("Invalid type %s", type_to_string(type)); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index f0f5327c6..2102420f8 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2216,7 +2216,9 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } return LLVMStructTypeInContext(ctx, fields, field_count, false); } - + + case Type_BitField: + return lb_type_internal(m, type->BitField.backing_type); } GB_PANIC("Invalid type %s", type_to_string(type)); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index e291e40a5..3567a550b 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -1788,6 +1788,73 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup lb_emit_store(p, tag, res); } break; + + case Type_BitField: + { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_field_ptr); + LLVMValueRef vals[5] = {}; + + vals[0] = lb_type_info(m, t->BitField.backing_type).value; + isize count = t->BitField.fields.count; + if (count > 0) { + i64 names_offset = 0; + i64 types_offset = 0; + i64 bit_sizes_offset = 0; + i64 bit_offsets_offset = 0; + lbValue memory_names = lb_type_info_member_names_offset (m, count, &names_offset); + lbValue memory_types = lb_type_info_member_types_offset (m, count, &types_offset); + lbValue memory_bit_sizes = lb_type_info_member_offsets_offset(m, count, &bit_sizes_offset); + lbValue memory_bit_offsets = lb_type_info_member_offsets_offset(m, count, &bit_offsets_offset); + + u64 bit_offset = 0; + for (isize source_index = 0; source_index < count; source_index++) { + Entity *f = t->BitField.fields[source_index]; + u64 bit_size = cast(u64)t->BitField.bit_sizes[source_index]; + + lbValue index = lb_const_int(m, t_int, source_index); + if (f->token.string.len > 0) { + lbValue name = lb_emit_ptr_offset(p, memory_names, index); + lb_emit_store(p, name, lb_const_string(m, f->token.string)); + } + lbValue type_ptr = lb_emit_ptr_offset(p, memory_types, index); + lbValue bit_size_ptr = lb_emit_ptr_offset(p, memory_bit_sizes, index); + lbValue bit_offset_ptr = lb_emit_ptr_offset(p, memory_bit_offsets, index); + + lb_emit_store(p, type_ptr, lb_type_info(m, f->type)); + lb_emit_store(p, bit_size_ptr, lb_const_int(m, t_uintptr, bit_size)); + lb_emit_store(p, bit_offset_ptr, lb_const_int(m, t_uintptr, bit_offset)); + + // lb_global_type_info_member_types_values [types_offset +source_index] = get_type_info_ptr(m, f->type); + // lb_global_type_info_member_offsets_values[bit_sizes_offset +source_index] = lb_const_int(m, t_uintptr, bit_size).value; + // lb_global_type_info_member_offsets_values[bit_offsets_offset+source_index] = lb_const_int(m, t_uintptr, bit_offset).value; + // if (f->token.string.len > 0) { + // lb_global_type_info_member_names_values[names_offset+source_index] = lb_const_string(m, f->token.string).value; + // } + + bit_offset += bit_size; + } + + lbValue cv = lb_const_int(m, t_int, count); + vals[1] = llvm_const_slice(m, memory_names, cv); + vals[2] = llvm_const_slice(m, memory_types, cv); + vals[3] = llvm_const_slice(m, memory_bit_sizes, cv); + vals[4] = llvm_const_slice(m, memory_bit_offsets, cv); + } + + for (isize i = 0; i < gb_count_of(vals); i++) { + if (vals[i] == nullptr) { + vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i))); + } + } + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + + break; + } + } diff --git a/src/parser.cpp b/src/parser.cpp index 78ac29dfd..70da9414d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -350,6 +350,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { n->Field.names = clone_ast_array(n->Field.names, f); n->Field.type = clone_ast(n->Field.type, f); break; + case Ast_BitFieldField: + n->BitFieldField.name = clone_ast(n->BitFieldField.name, f); + n->BitFieldField.type = clone_ast(n->BitFieldField.type, f); + n->BitFieldField.bit_size = clone_ast(n->BitFieldField.bit_size, f); + break; case Ast_FieldList: n->FieldList.list = clone_ast_array(n->FieldList.list, f); break; @@ -406,6 +411,10 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { n->BitSetType.elem = clone_ast(n->BitSetType.elem, f); n->BitSetType.underlying = clone_ast(n->BitSetType.underlying, f); break; + case Ast_BitFieldType: + n->BitFieldType.backing_type = clone_ast(n->BitFieldType.backing_type, f); + n->BitFieldType.fields = clone_ast_array(n->BitFieldType.fields, f); + break; case Ast_MapType: n->MapType.count = clone_ast(n->MapType.count, f); n->MapType.key = clone_ast(n->MapType.key, f); @@ -1045,6 +1054,17 @@ gb_internal Ast *ast_field(AstFile *f, Array const &names, Ast *type, Ast return result; } +gb_internal Ast *ast_bit_field_field(AstFile *f, Ast *name, Ast *type, Ast *bit_size, + CommentGroup *docs, CommentGroup *comment) { + Ast *result = alloc_ast_node(f, Ast_BitFieldField); + result->BitFieldField.name = name; + result->BitFieldField.type = type; + result->BitFieldField.bit_size = bit_size; + result->BitFieldField.docs = docs; + result->BitFieldField.comment = comment; + return result; +} + gb_internal Ast *ast_field_list(AstFile *f, Token token, Array const &list) { Ast *result = alloc_ast_node(f, Ast_FieldList); result->FieldList.token = token; @@ -1178,6 +1198,17 @@ gb_internal Ast *ast_bit_set_type(AstFile *f, Token token, Ast *elem, Ast *under return result; } +gb_internal Ast *ast_bit_field_type(AstFile *f, Token token, Ast *backing_type, Token open, Array const &fields, Token close) { + Ast *result = alloc_ast_node(f, Ast_BitFieldType); + result->BitFieldType.token = token; + result->BitFieldType.backing_type = backing_type; + result->BitFieldType.open = open; + result->BitFieldType.fields = slice_from_array(fields); + result->BitFieldType.close = close; + return result; +} + + gb_internal Ast *ast_map_type(AstFile *f, Token token, Ast *key, Ast *value) { Ast *result = alloc_ast_node(f, Ast_MapType); result->MapType.token = token; @@ -2549,6 +2580,53 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { return ast_matrix_type(f, token, row_count, column_count, type); } break; + case Token_bit_field: { + Token token = expect_token(f, Token_bit_field); + isize prev_level; + + prev_level = f->expr_level; + f->expr_level = -1; + + Ast *backing_type = parse_type_or_ident(f); + if (backing_type == nullptr) { + Token token = advance_token(f); + syntax_error(token, "Expected a backing type for a 'bit_field'"); + backing_type = ast_bad_expr(f, token, f->curr_token); + } + + skip_possible_newline_for_literal(f); + Token open = expect_token_after(f, Token_OpenBrace, "bit_field"); + + + auto fields = array_make(ast_allocator(f), 0, 0); + + while (f->curr_token.kind != Token_CloseBrace && + f->curr_token.kind != Token_EOF) { + CommentGroup *docs = nullptr; + CommentGroup *comment = nullptr; + + Ast *name = parse_ident(f); + expect_token(f, Token_Colon); + Ast *type = parse_type(f); + expect_token(f, Token_Or); + Ast *bit_size = parse_expr(f, true); + + Ast *bf_field = ast_bit_field_field(f, name, type, bit_size, docs, comment); + array_add(&fields, bf_field); + + if (!allow_field_separator(f)) { + break; + } + } + + Token close = expect_closing_brace_of_field_list(f); + + f->expr_level = prev_level; + + return ast_bit_field_type(f, token, backing_type, open, fields, close); + } + + case Token_struct: { Token token = expect_token(f, Token_struct); Ast *polymorphic_params = nullptr; diff --git a/src/parser.hpp b/src/parser.hpp index 1edb1f9dd..ff77c88c7 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -650,6 +650,13 @@ AST_KIND(_DeclEnd, "", bool) \ CommentGroup * docs; \ CommentGroup * comment; \ }) \ + AST_KIND(BitFieldField, "bit field field", struct { \ + Ast * name; \ + Ast * type; \ + Ast * bit_size; \ + CommentGroup *docs; \ + CommentGroup *comment; \ + }) \ AST_KIND(FieldList, "field list", struct { \ Token token; \ Slice list; \ @@ -742,6 +749,14 @@ AST_KIND(_TypeBegin, "", bool) \ Ast * elem; \ Ast * underlying; \ }) \ + AST_KIND(BitFieldType, "bit field type", struct { \ + Scope *scope; \ + Token token; \ + Ast * backing_type; \ + Token open; \ + Slice fields; /* BitFieldField */ \ + Token close; \ + }) \ AST_KIND(MapType, "map type", struct { \ Token token; \ Ast *count; \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index f49c40f16..b2e12999b 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -111,6 +111,7 @@ gb_internal Token ast_token(Ast *node) { case Ast_UnionType: return node->UnionType.token; case Ast_EnumType: return node->EnumType.token; case Ast_BitSetType: return node->BitSetType.token; + case Ast_BitFieldType: return node->BitFieldType.token; case Ast_MapType: return node->MapType.token; case Ast_MatrixType: return node->MatrixType.token; } @@ -364,6 +365,8 @@ Token ast_end_token(Ast *node) { return ast_end_token(node->BitSetType.underlying); } return ast_end_token(node->BitSetType.elem); + case Ast_BitFieldType: + return node->BitFieldType.close; case Ast_MapType: return ast_end_token(node->MapType.value); case Ast_MatrixType: return ast_end_token(node->MatrixType.elem); } diff --git a/src/types.cpp b/src/types.cpp index 78d281715..1c28e6583 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -282,6 +282,13 @@ struct TypeProc { Type *generic_column_count; \ i64 stride_in_bytes; \ }) \ + TYPE_KIND(BitField, struct { \ + Scope * scope; \ + Type * backing_type; \ + Slice fields; \ + Slice bit_sizes; \ + Ast * node; \ + }) \ TYPE_KIND(SoaPointer, struct { Type *elem; }) @@ -355,6 +362,7 @@ enum Typeid_Kind : u8 { Typeid_Relative_Multi_Pointer, Typeid_Matrix, Typeid_SoaPointer, + Typeid_Bit_Field, }; // IMPORTANT NOTE(bill): This must match the same as the in core.odin @@ -641,6 +649,7 @@ gb_global Type *t_type_info_relative_pointer = nullptr; gb_global Type *t_type_info_relative_multi_pointer = nullptr; gb_global Type *t_type_info_matrix = nullptr; gb_global Type *t_type_info_soa_pointer = nullptr; +gb_global Type *t_type_info_bit_field = nullptr; gb_global Type *t_type_info_named_ptr = nullptr; gb_global Type *t_type_info_integer_ptr = nullptr; @@ -670,6 +679,7 @@ gb_global Type *t_type_info_relative_pointer_ptr = nullptr; gb_global Type *t_type_info_relative_multi_pointer_ptr = nullptr; gb_global Type *t_type_info_matrix_ptr = nullptr; gb_global Type *t_type_info_soa_pointer_ptr = nullptr; +gb_global Type *t_type_info_bit_field_ptr = nullptr; gb_global Type *t_allocator = nullptr; gb_global Type *t_allocator_ptr = nullptr; @@ -1040,6 +1050,11 @@ gb_internal Type *alloc_type_enum() { return t; } +gb_internal Type *alloc_type_bit_field() { + Type *t = alloc_type(Type_BitField); + return t; +} + gb_internal Type *alloc_type_relative_pointer(Type *pointer_type, Type *base_integer) { GB_ASSERT(is_type_pointer(pointer_type)); GB_ASSERT(is_type_integer(base_integer)); @@ -1707,6 +1722,10 @@ gb_internal bool is_type_bit_set(Type *t) { t = base_type(t); return (t->kind == Type_BitSet); } +gb_internal bool is_type_bit_field(Type *t) { + t = base_type(t); + return (t->kind == Type_BitField); +} gb_internal bool is_type_map(Type *t) { t = base_type(t); return t->kind == Type_Map; @@ -3568,6 +3587,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { case Type_Slice: return build_context.int_size; + case Type_BitField: + return type_align_of_internal(t->BitField.backing_type, path); case Type_Tuple: { i64 max = 1; @@ -3943,6 +3964,9 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { return stride_in_bytes * t->Matrix.column_count; } + case Type_BitField: + return type_size_of_internal(t->BitField.backing_type, path); + case Type_RelativePointer: return type_size_of_internal(t->RelativePointer.base_integer, path); case Type_RelativeMultiPointer: -- cgit v1.2.3 From bb23648c7133a1827373bfbb8922504f20e0478c Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 22 Feb 2024 18:17:52 +0100 Subject: Also convert and promote bit_set types for #c_varargs --- src/types.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index c31b6e1bd..9f52ed17d 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2808,6 +2808,11 @@ gb_internal Type *c_vararg_promote_type(Type *type) { GB_ASSERT(type != nullptr); Type *core = core_type(type); + + if (core->kind == Type_BitSet) { + core = core_type(bit_set_to_int(core)); + } + if (core->kind == Type_Basic) { switch (core->Basic.kind) { case Basic_f32: -- cgit v1.2.3 From 5a84a0822596fac47dd35bf1c2f1d9bb60bbe5c1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 17:24:42 +0000 Subject: Add general support for `bit_field`s --- base/runtime/internal.odin | 22 ++++++++++++ core/fmt/fmt.odin | 10 ++++-- src/check_expr.cpp | 86 ++++++++++++++++++++++++++++++++++++++------ src/check_stmt.cpp | 10 ++++++ src/check_type.cpp | 21 +++++++++-- src/checker.hpp | 1 + src/entity.cpp | 2 ++ src/llvm_backend.hpp | 8 +++++ src/llvm_backend_expr.cpp | 16 +++++++++ src/llvm_backend_general.cpp | 51 ++++++++++++++++++++++++-- src/parser.hpp | 1 + src/types.cpp | 34 ++++++++++++++++++ 12 files changed, 245 insertions(+), 17 deletions(-) (limited to 'src/types.cpp') diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin index 691f76ff1..62bee8620 100644 --- a/base/runtime/internal.odin +++ b/base/runtime/internal.odin @@ -1034,3 +1034,25 @@ fixdfti :: proc(a: u64) -> i128 { } } + + + +__write_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uintptr) { + for i in 0..value.kind == ExactValue_Integer) { gbString b = type_to_string(type); i64 sz = type_size_of(type); + i64 bit_size = 8*sz; + bool size_changed = false; + if (max_bit_size > 0) { + size_changed = (bit_size != max_bit_size); + bit_size = gb_min(bit_size, max_bit_size); + } BigInt *bi = &o->value.value_integer; if (is_type_unsigned(type)) { if (big_int_is_neg(bi)) { @@ -2083,25 +2089,36 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } else { BigInt one = big_int_make_u64(1); BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(8*sz); + BigInt bits = big_int_make_i64(bit_size); big_int_shl_eq(&max_size, &bits); big_int_sub_eq(&max_size, &one); String max_size_str = big_int_to_string(temporary_allocator(), &max_size); - error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + + if (size_changed) { + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + } else { + error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } } } else { BigInt zero = big_int_make_u64(0); BigInt one = big_int_make_u64(1); BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(8*sz - 1); + BigInt bits = big_int_make_i64(bit_size - 1); big_int_shl_eq(&max_size, &bits); + + String max_size_str = {}; if (big_int_is_neg(bi)) { big_int_neg(&max_size, &max_size); - String max_size_str = big_int_to_string(temporary_allocator(), &max_size); - error_line("\tThe minimum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + max_size_str = big_int_to_string(temporary_allocator(), &max_size); } else { big_int_sub_eq(&max_size, &one); - String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + max_size_str = big_int_to_string(temporary_allocator(), &max_size); + } + + if (size_changed) { + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + } else { error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); } } @@ -2112,7 +2129,7 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } return false; } -gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { +gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); defer( @@ -2143,7 +2160,7 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o error_line("\t whereas slices in general are assumed to be mutable.\n"); } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { error_line("\tSuggestion: the expression may be casted to %s\n", b); - } else if (check_integer_exceed_suggestion(c, o, type)) { + } else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) { return; } } @@ -2217,13 +2234,18 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s', got %s", a, b, s); } else { + i64 max_bit_size = 0; + if (ctx->bit_field_bit_size) { + max_bit_size = ctx->bit_field_bit_size; + } + if (are_types_identical(o->type, type)) { error(o->expr, "Numeric value '%s' from '%s' cannot be represented by '%s'", s, a, b); } else { error(o->expr, "Cannot convert numeric value '%s' from '%s' to '%s' from '%s'", s, a, b, c); } - check_assignment_error_suggestion(ctx, o, type); + check_assignment_error_suggestion(ctx, o, type, max_bit_size); } } else { error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s); @@ -2234,6 +2256,11 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ } gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { + if (o->expr && o->expr->kind == Ast_SelectorExpr) { + if (o->expr->SelectorExpr.is_bit_field) { + return true; + } + } if (o->mode == Addressing_OptionalOk) { Ast *expr = unselector_expr(o->expr); if (expr->kind != Ast_TypeAssertion) { @@ -2306,6 +2333,8 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * Entity *e = entity_of_node(ue->expr); if (e != nullptr && (e->flags & EntityFlag_Param) != 0) { error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str); + } else if (e != nullptr && (e->flags & EntityFlag_BitFieldField) != 0) { + error(op, "Cannot take the pointer address of '%s' which is a bit_field's field", str); } else { switch (o->mode) { case Addressing_Constant: @@ -5067,6 +5096,11 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod operand->type = entity->type; operand->expr = node; + if (entity->flags & EntityFlag_BitFieldField) { + add_package_dependency(c, "runtime", "__write_bits"); + add_package_dependency(c, "runtime", "__read_bits"); + } + switch (entity->kind) { case Entity_Constant: operand->value = entity->Constant.value; @@ -5080,6 +5114,9 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } break; case Entity_Variable: + if (sel.is_bit_field) { + se->is_bit_field = true; + } if (sel.indirect) { operand->mode = Addressing_Variable; } else if (operand->mode == Addressing_Context) { @@ -11115,6 +11152,33 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; + case_ast_node(f, BitFieldField, node); + str = write_expr_to_string(str, f->name, shorthand); + str = gb_string_appendc(str, ": "); + str = write_expr_to_string(str, f->type, shorthand); + str = gb_string_appendc(str, " | "); + str = write_expr_to_string(str, f->bit_size, shorthand); + case_end; + case_ast_node(bf, BitFieldType, node); + str = gb_string_appendc(str, "bit_field "); + if (!shorthand) { + str = write_expr_to_string(str, bf->backing_type, shorthand); + } + str = gb_string_appendc(str, " {"); + if (shorthand) { + str = gb_string_appendc(str, "..."); + } else { + for_array(i, bf->fields) { + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = write_expr_to_string(str, bf->fields[i], false); + } + return str; + } + str = gb_string_appendc(str, "}"); + case_end; + case_ast_node(ia, InlineAsmExpr, node); str = gb_string_appendc(str, "asm("); for_array(i, ia->param_types) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 6897701d6..a7dd9743b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -485,7 +485,17 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } } + Entity *lhs_e = entity_of_node(lhs->expr); + u8 prev_bit_field_bit_size = ctx->bit_field_bit_size; + if (lhs_e && lhs_e->kind == Entity_Variable && lhs_e->Variable.bit_field_bit_size) { + // HACK NOTE(bill): This is a bit of a hack, but it will work fine for this use case + ctx->bit_field_bit_size = lhs_e->Variable.bit_field_bit_size; + } + check_assignment(ctx, rhs, assignment_type, str_lit("assignment")); + + ctx->bit_field_bit_size = prev_bit_field_bit_size; + if (rhs->mode == Addressing_Invalid) { return nullptr; } diff --git a/src/check_type.cpp b/src/check_type.cpp index 8afac2fc5..8c746a2f7 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1035,11 +1035,19 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, error(f->bit_size, "A bit_field's specified bit size cannot exceed 64 bits, got %lld", cast(long long)bit_size_i64); bit_size_i64 = 64; } + i64 sz = 8*type_size_of(type); + if (bit_size_i64 > sz) { + error(f->bit_size, "A bit_field's specified bit size cannot exceed its type, got %lld, expect <=%lld", cast(long long)bit_size_i64, cast(long long)sz); + bit_size_i64 = sz; + } + bit_size_u8 = cast(u8)bit_size_i64; Entity *e = alloc_entity_field(ctx->scope, f->name->Ident.token, type, false, field_src_index); e->Variable.docs = docs; e->Variable.comment = comment; + e->Variable.bit_field_bit_size = bit_size_u8; + e->flags |= EntityFlag_BitFieldField; add_entity(ctx, ctx->scope, nullptr, e); array_add(&fields, e); @@ -1050,6 +1058,14 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, GB_ASSERT(fields.count <= bf->fields.count); + auto bit_offsets = slice_make(permanent_allocator(), fields.count); + i64 curr_offset = 0; + for_array(i, bit_sizes) { + bit_offsets[i] = curr_offset; + curr_offset += cast(i64)bit_sizes[i]; + } + + if (total_bit_size > maximum_bit_size) { gbString s = type_to_string(backing_type); error(node, "The numbers required %llu exceeds the backing type's (%s) bit size %llu", @@ -1059,8 +1075,9 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, gb_string_free(s); } - bit_field_type->BitField.fields = slice_from_array(fields); - bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); + bit_field_type->BitField.fields = slice_from_array(fields); + bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); + bit_field_type->BitField.bit_offsets = bit_offsets; } gb_internal bool is_type_valid_bit_set_range(Type *t) { diff --git a/src/checker.hpp b/src/checker.hpp index 9aee82257..066d6bb4a 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -475,6 +475,7 @@ struct CheckerContext { bool hide_polymorphic_errors; bool in_polymorphic_specialization; bool allow_arrow_right_selector_expr; + u8 bit_field_bit_size; Scope * polymorphic_scope; Ast *assignment_lhs_hint; diff --git a/src/entity.cpp b/src/entity.cpp index e6c46d37e..916c2b2bd 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -43,6 +43,7 @@ enum EntityFlag : u64 { EntityFlag_NoAlias = 1ull<<9, EntityFlag_TypeField = 1ull<<10, EntityFlag_Value = 1ull<<11, + EntityFlag_BitFieldField = 1ull<<12, @@ -212,6 +213,7 @@ struct Entity { Ast *init_expr; // only used for some variables within procedure bodies i32 field_index; i32 field_group_index; + u8 bit_field_bit_size; ParameterValue param_value; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 026454c81..00d1b7a21 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -84,6 +84,8 @@ enum lbAddrKind { lbAddr_Swizzle, lbAddr_SwizzleLarge, + + lbAddr_BitField, }; struct lbAddr { @@ -118,6 +120,12 @@ struct lbAddr { Type *type; Slice indices; } swizzle_large; + struct { + Type *type; + i64 index; + i64 bit_offset; + i64 bit_size; + } bitfield; }; }; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0c06c8c1b..6bef21822 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4627,6 +4627,22 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { Selection sel = lookup_field(type, selector, false); GB_ASSERT(sel.entity != nullptr); + if (sel.is_bit_field) { + lbAddr addr = lb_build_addr(p, se->expr); + Type *bf_type = base_type(type_deref(lb_addr_type(addr))); + GB_ASSERT(bf_type->kind == Type_BitField); + + lbValue a = lb_addr_get_ptr(p, addr); + Selection sub_sel = sel; + sub_sel.index.count -= 1; + i32 index = sel.index[sel.index.count-1]; + + Entity *f = bf_type->BitField.fields[index]; + u8 bit_size = bf_type->BitField.bit_sizes[index]; + i64 bit_offset = bf_type->BitField.bit_offsets[index]; + + return lb_addr_bit_field(a, f->type, index, bit_offset, bit_size); + } if (sel.pseudo_field) { GB_ASSERT(sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup); Entity *e = entity_of_node(sel_node); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 2102420f8..4ff8482a7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -451,6 +451,20 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice(temporary_allocator(), 4); + args[0] = dst; + args[1] = lb_address_from_load_or_generate_local(p, value); + args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset); + args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size); + lb_emit_runtime_call(p, "__write_bits", args); + return; + } else if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); GB_ASSERT(rel_ptr->kind == Type_RelativePointer || rel_ptr->kind == Type_RelativeMultiPointer); @@ -1074,8 +1098,31 @@ gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue value) { gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { GB_ASSERT(addr.addr.value != nullptr); + if (addr.kind == lbAddr_BitField) { + lbAddr dst = lb_add_local_generated(p, addr.bitfield.type, true); + lbValue src = addr.addr; - if (addr.kind == lbAddr_RelativePointer) { + auto args = array_make(temporary_allocator(), 4); + args[0] = dst.addr; + args[1] = src; + args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset); + args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size); + lb_emit_runtime_call(p, "__read_bits", args); + + lbValue r = lb_addr_load(p, dst); + + if (!is_type_unsigned(core_type(addr.bitfield.type))) { + // Sign extension + // m := 1<<(bit_size-1) + // r = (r XOR m) - m + Type *t = addr.bitfield.type; + lbValue m = lb_const_int(p->module, t, 1ull<<(addr.bitfield.bit_size-1)); + r = lb_emit_arith(p, Token_Xor, r, m, t); + r = lb_emit_arith(p, Token_Sub, r, m, t); + } + + return r; + } else if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); Type *base_integer = nullptr; Type *pointer_type = nullptr; diff --git a/src/parser.hpp b/src/parser.hpp index ff77c88c7..1f4ec8726 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -429,6 +429,7 @@ AST_KIND(_ExprBegin, "", bool) \ Ast *expr, *selector; \ u8 swizzle_count; /*maximum of 4 components, if set, count >= 2*/ \ u8 swizzle_indices; /*2 bits per component*/ \ + bool is_bit_field; \ }) \ AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \ AST_KIND(SelectorCallExpr, "selector call expression", struct { \ diff --git a/src/types.cpp b/src/types.cpp index 1c28e6583..be4b8944b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -287,6 +287,7 @@ struct TypeProc { Type * backing_type; \ Slice fields; \ Slice bit_sizes; \ + Slice bit_offsets; \ Ast * node; \ }) \ TYPE_KIND(SoaPointer, struct { Type *elem; }) @@ -408,6 +409,7 @@ struct Selection { bool indirect; // Set if there was a pointer deref anywhere down the line u8 swizzle_count; // maximum components = 4 u8 swizzle_indices; // 2 bits per component, representing which swizzle index + bool is_bit_field; bool pseudo_field; }; gb_global Selection const empty_selection = {0}; @@ -3187,6 +3189,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name else if (field_name == "a") mapped_field_name = str_lit("w"); return lookup_field_with_selection(type, mapped_field_name, is_type, sel, allow_blank_ident); } + } else if (type->kind == Type_BitField) { + for_array(i, type->BitField.fields) { + Entity *f = type->BitField.fields[i]; + if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { + continue; + } + String str = f->token.string; + if (field_name == str) { + selection_add_index(&sel, i); // HACK(bill): Leaky memory + sel.entity = f; + sel.is_bit_field = true; + return sel; + } + } + } else if (type->kind == Type_Basic) { switch (type->Basic.kind) { case Basic_any: { @@ -4551,6 +4568,23 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_appendc(str, gb_bprintf("matrix[%d, %d]", cast(int)type->Matrix.row_count, cast(int)type->Matrix.column_count)); str = write_type_to_string(str, type->Matrix.elem); break; + + case Type_BitField: + str = gb_string_appendc(str, "bit_field "); + str = write_type_to_string(str, type->BitField.backing_type); + str = gb_string_appendc(str, " {"); + for (isize i = 0; i < type->BitField.fields.count; i++) { + Entity *f = type->BitField.fields[i]; + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = gb_string_append_length(str, f->token.string.text, f->token.string.len); + str = gb_string_appendc(str, ": "); + str = write_type_to_string(str, f->type); + str = gb_string_append_fmt(str, " | %u", type->BitField.bit_sizes[i]); + } + str = gb_string_appendc(str, " }"); + break; } return str; -- cgit v1.2.3 From c14b9d461a5c58d4b80957682f00205714063435 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 19:14:16 +0000 Subject: Support `using` of a `bit_field` within a `struct` --- src/check_type.cpp | 2 ++ src/llvm_backend_expr.cpp | 14 +++++++-- src/llvm_backend_utility.cpp | 2 +- src/types.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 83 insertions(+), 6 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 41eae2178..74828f97f 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -89,6 +89,8 @@ gb_internal bool does_field_type_allow_using(Type *t) { return true; } else if (is_type_array(t)) { return t->Array.count <= 4; + } else if (is_type_bit_field(t)) { + return true; } return false; } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7e000c9e8..5bf2642e6 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4679,12 +4679,20 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(sel.entity != nullptr); if (sel.is_bit_field) { lbAddr addr = lb_build_addr(p, se->expr); - Type *bf_type = base_type(type_deref(lb_addr_type(addr))); - GB_ASSERT(bf_type->kind == Type_BitField); - lbValue a = lb_addr_get_ptr(p, addr); + Selection sub_sel = sel; sub_sel.index.count -= 1; + + Type *bf_type = type_from_selection(type, sub_sel); + bf_type = base_type(type_deref(bf_type)); + GB_ASSERT(bf_type->kind == Type_BitField); + + lbValue a = lb_addr_get_ptr(p, addr); + if (sub_sel.index.count > 0) { + a = lb_emit_deep_field_gep(p, a, sub_sel); + } + i32 index = sel.index[sel.index.count-1]; Entity *f = bf_type->BitField.fields[index]; diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index bc5106601..5bd3cd8e2 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1332,7 +1332,7 @@ gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection if (index == 0) { type = t_rawptr; } else if (index == 1) { - type = t_type_info_ptr; + type = t_typeid; } e = lb_emit_struct_ep(p, e, index); break; diff --git a/src/types.cpp b/src/types.cpp index be4b8944b..3945c7111 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -385,6 +385,9 @@ enum : int { gb_internal bool is_type_comparable(Type *t); gb_internal bool is_type_simple_compare(Type *t); +gb_internal Type *type_deref(Type *t, bool allow_multi_pointer=false); +gb_internal Type *base_type(Type *t); +gb_internal Type *alloc_type_multi_pointer(Type *elem); gb_internal u32 type_info_flags_of_type(Type *type) { if (type == nullptr) { @@ -762,7 +765,6 @@ gb_internal bool is_type_proc(Type *t); gb_internal bool is_type_slice(Type *t); gb_internal bool is_type_integer(Type *t); gb_internal bool type_set_offsets(Type *t); -gb_internal Type *base_type(Type *t); gb_internal i64 type_size_of_internal(Type *t, TypePath *path); gb_internal i64 type_align_of_internal(Type *t, TypePath *path); @@ -1157,7 +1159,7 @@ gb_internal Type *alloc_type_simd_vector(i64 count, Type *elem, Type *generic_co //////////////////////////////////////////////////////////////// -gb_internal Type *type_deref(Type *t, bool allow_multi_pointer=false) { +gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) { if (t != nullptr) { Type *bt = base_type(t); if (bt == nullptr) { @@ -4261,6 +4263,71 @@ gb_internal Type *alloc_type_proc_from_types(Type **param_types, unsigned param_ } +gb_internal Type *type_from_selection(Type *type, Selection const &sel) { + for (i32 index : sel.index) { + Type *bt = base_type(type_deref(type)); + switch (bt->kind) { + case Type_Struct: + type = bt->Struct.fields[index]->type; + break; + case Type_Tuple: + type = bt->Tuple.variables[index]->type; + break; + case Type_BitField: + type = bt->BitField.fields[index]->type; + break; + case Type_Array: + type = bt->Array.elem; + break; + case Type_EnumeratedArray: + type = bt->Array.elem; + break; + case Type_Slice: + switch (index) { + case 0: type = alloc_type_multi_pointer(bt->Slice.elem); break; + case 1: type = t_int; break; + } + break; + case Type_DynamicArray: + switch (index) { + case 0: type = alloc_type_multi_pointer(bt->DynamicArray.elem); break; + case 1: type = t_int; break; + case 2: type = t_int; break; + case 3: type = t_allocator; break; + } + break; + case Type_Map: + switch (index) { + case 0: type = t_uintptr; break; + case 1: type = t_int; break; + case 2: type = t_allocator; break; + } + break; + case Type_Basic: + if (is_type_complex_or_quaternion(bt)) { + type = base_complex_elem_type(bt); + } else { + switch (type->Basic.kind) { + case Basic_any: + switch (index) { + case 0: type = t_rawptr; break; + case 1: type = t_typeid; break; + } + break; + case Basic_string: + switch (index) { + case 0: type = t_u8_multi_ptr; break; + case 1: type = t_int; break; + } + break; + } + } + break; + } + } + return type; +} + gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { if (type == nullptr) { -- cgit v1.2.3 From 3060225f460cb5d1ad124fcf449b27b3e2e981f8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 19:24:16 +0000 Subject: Simplify usage code --- src/llvm_backend_expr.cpp | 8 +-- src/types.cpp | 130 +++++++++++++++++++++++----------------------- 2 files changed, 69 insertions(+), 69 deletions(-) (limited to 'src/types.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5bf2642e6..442121f83 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4684,15 +4684,17 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { Selection sub_sel = sel; sub_sel.index.count -= 1; - Type *bf_type = type_from_selection(type, sub_sel); - bf_type = base_type(type_deref(bf_type)); - GB_ASSERT(bf_type->kind == Type_BitField); lbValue a = lb_addr_get_ptr(p, addr); if (sub_sel.index.count > 0) { a = lb_emit_deep_field_gep(p, a, sub_sel); } + + Type *bf_type = type_deref(a.type); + bf_type = base_type(type_deref(bf_type)); + GB_ASSERT(bf_type->kind == Type_BitField); + i32 index = sel.index[sel.index.count-1]; Entity *f = bf_type->BitField.fields[index]; diff --git a/src/types.cpp b/src/types.cpp index 3945c7111..eac834f25 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4262,72 +4262,70 @@ gb_internal Type *alloc_type_proc_from_types(Type **param_types, unsigned param_ return t; } - -gb_internal Type *type_from_selection(Type *type, Selection const &sel) { - for (i32 index : sel.index) { - Type *bt = base_type(type_deref(type)); - switch (bt->kind) { - case Type_Struct: - type = bt->Struct.fields[index]->type; - break; - case Type_Tuple: - type = bt->Tuple.variables[index]->type; - break; - case Type_BitField: - type = bt->BitField.fields[index]->type; - break; - case Type_Array: - type = bt->Array.elem; - break; - case Type_EnumeratedArray: - type = bt->Array.elem; - break; - case Type_Slice: - switch (index) { - case 0: type = alloc_type_multi_pointer(bt->Slice.elem); break; - case 1: type = t_int; break; - } - break; - case Type_DynamicArray: - switch (index) { - case 0: type = alloc_type_multi_pointer(bt->DynamicArray.elem); break; - case 1: type = t_int; break; - case 2: type = t_int; break; - case 3: type = t_allocator; break; - } - break; - case Type_Map: - switch (index) { - case 0: type = t_uintptr; break; - case 1: type = t_int; break; - case 2: type = t_allocator; break; - } - break; - case Type_Basic: - if (is_type_complex_or_quaternion(bt)) { - type = base_complex_elem_type(bt); - } else { - switch (type->Basic.kind) { - case Basic_any: - switch (index) { - case 0: type = t_rawptr; break; - case 1: type = t_typeid; break; - } - break; - case Basic_string: - switch (index) { - case 0: type = t_u8_multi_ptr; break; - case 1: type = t_int; break; - } - break; - } - } - break; - } - } - return type; -} - +// gb_internal Type *type_from_selection(Type *type, Selection const &sel) { +// for (i32 index : sel.index) { +// Type *bt = base_type(type_deref(type)); +// switch (bt->kind) { +// case Type_Struct: +// type = bt->Struct.fields[index]->type; +// break; +// case Type_Tuple: +// type = bt->Tuple.variables[index]->type; +// break; +// case Type_BitField: +// type = bt->BitField.fields[index]->type; +// break; +// case Type_Array: +// type = bt->Array.elem; +// break; +// case Type_EnumeratedArray: +// type = bt->Array.elem; +// break; +// case Type_Slice: +// switch (index) { +// case 0: type = alloc_type_multi_pointer(bt->Slice.elem); break; +// case 1: type = t_int; break; +// } +// break; +// case Type_DynamicArray: +// switch (index) { +// case 0: type = alloc_type_multi_pointer(bt->DynamicArray.elem); break; +// case 1: type = t_int; break; +// case 2: type = t_int; break; +// case 3: type = t_allocator; break; +// } +// break; +// case Type_Map: +// switch (index) { +// case 0: type = t_uintptr; break; +// case 1: type = t_int; break; +// case 2: type = t_allocator; break; +// } +// break; +// case Type_Basic: +// if (is_type_complex_or_quaternion(bt)) { +// type = base_complex_elem_type(bt); +// } else { +// switch (type->Basic.kind) { +// case Basic_any: +// switch (index) { +// case 0: type = t_rawptr; break; +// case 1: type = t_typeid; break; +// } +// break; +// case Basic_string: +// switch (index) { +// case 0: type = t_u8_multi_ptr; break; +// case 1: type = t_int; break; +// } +// break; +// } +// } +// break; +// } +// } +// return type; +// } gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { if (type == nullptr) { -- cgit v1.2.3 From 54515af8ccff67cae71982d1bbf5bd1c31628af3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 19:41:48 +0000 Subject: Add field tags to `bit_field` --- base/runtime/core.odin | 1 + core/fmt/fmt.odin | 25 +++++++++++++++++++++++-- src/check_type.cpp | 10 ++++++++++ src/llvm_backend_type.cpp | 34 +++++++++++++++++++--------------- src/parser.cpp | 10 ++++++++-- src/parser.hpp | 1 + src/types.cpp | 1 + 7 files changed, 63 insertions(+), 19 deletions(-) (limited to 'src/types.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index dcc1e7476..2f63a7ac2 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -187,6 +187,7 @@ Type_Info_Bit_Field :: struct { types: []^Type_Info, bit_sizes: []uintptr, bit_offsets: []uintptr, + tags: []string, } Type_Info_Flag :: enum u8 { diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 51f158cd8..38e125c30 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2297,6 +2297,23 @@ fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit return } + handle_bit_field_tag :: proc(data: rawptr, info: reflect.Type_Info_Bit_Field, idx: int, verb: ^rune) -> (do_continue: bool) { + tag := info.tags[idx] + if vt, ok := reflect.struct_tag_lookup(reflect.Struct_Tag(tag), "fmt"); ok { + value := strings.trim_space(string(vt)) + switch value { + case "": return false + case "-": return true + } + r, w := utf8.decode_rune_in_string(value) + value = value[w:] + if value == "" || value[0] == ',' { + verb^ = r + } + } + return false + } + io.write_string(fi.writer, "bit_field{", &fi.n) hash := fi.hash; defer fi.hash = hash @@ -2318,7 +2335,11 @@ fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit field_count := -1 for name, i in info.names { - _ = i + field_verb := verb + if handle_bit_field_tag(v.data, info, i, &field_verb) { + continue + } + field_count += 1 if !do_trailing_comma && field_count > 0 { @@ -2343,7 +2364,7 @@ fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit value = (value ~ m) - m } - fmt_value(fi, any{&value, type.id}, verb) + fmt_value(fi, any{&value, type.id}, field_verb) if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 74828f97f..1bcae140f 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -959,6 +959,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, auto fields = array_make(permanent_allocator(), 0, bf->fields.count); auto bit_sizes = array_make (permanent_allocator(), 0, bf->fields.count); + auto tags = array_make (permanent_allocator(), 0, bf->fields.count); u64 maximum_bit_size = 8 * type_size_of(backing_type); u64 total_bit_size = 0; @@ -1054,6 +1055,14 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, add_entity(ctx, ctx->scope, nullptr, e); array_add(&fields, e); array_add(&bit_sizes, bit_size_u8); + + String tag = f->tag.string; + if (tag.len != 0 && !unquote_string(permanent_allocator(), &tag, 0, tag.text[0] == '`')) { + error(f->tag, "Invalid string literal"); + tag = {}; + } + array_add(&tags, tag); + add_entity_use(ctx, field, e); } } @@ -1080,6 +1089,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, bit_field_type->BitField.fields = slice_from_array(fields); bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); bit_field_type->BitField.bit_offsets = bit_offsets; + bit_field_type->BitField.tags = tags.data; } gb_internal bool is_type_valid_bit_set_range(Type *t) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 3567a550b..4952d75de 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -1792,19 +1792,21 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup case Type_BitField: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_field_ptr); - LLVMValueRef vals[5] = {}; + LLVMValueRef vals[6] = {}; vals[0] = lb_type_info(m, t->BitField.backing_type).value; isize count = t->BitField.fields.count; if (count > 0) { - i64 names_offset = 0; - i64 types_offset = 0; - i64 bit_sizes_offset = 0; + i64 names_offset = 0; + i64 types_offset = 0; + i64 bit_sizes_offset = 0; i64 bit_offsets_offset = 0; + i64 tags_offset = 0; lbValue memory_names = lb_type_info_member_names_offset (m, count, &names_offset); lbValue memory_types = lb_type_info_member_types_offset (m, count, &types_offset); lbValue memory_bit_sizes = lb_type_info_member_offsets_offset(m, count, &bit_sizes_offset); lbValue memory_bit_offsets = lb_type_info_member_offsets_offset(m, count, &bit_offsets_offset); + lbValue memory_tags = lb_type_info_member_tags_offset (m, count, &tags_offset); u64 bit_offset = 0; for (isize source_index = 0; source_index < count; source_index++) { @@ -1813,8 +1815,8 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup lbValue index = lb_const_int(m, t_int, source_index); if (f->token.string.len > 0) { - lbValue name = lb_emit_ptr_offset(p, memory_names, index); - lb_emit_store(p, name, lb_const_string(m, f->token.string)); + lbValue name_ptr = lb_emit_ptr_offset(p, memory_names, index); + lb_emit_store(p, name_ptr, lb_const_string(m, f->token.string)); } lbValue type_ptr = lb_emit_ptr_offset(p, memory_types, index); lbValue bit_size_ptr = lb_emit_ptr_offset(p, memory_bit_sizes, index); @@ -1824,21 +1826,23 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup lb_emit_store(p, bit_size_ptr, lb_const_int(m, t_uintptr, bit_size)); lb_emit_store(p, bit_offset_ptr, lb_const_int(m, t_uintptr, bit_offset)); - // lb_global_type_info_member_types_values [types_offset +source_index] = get_type_info_ptr(m, f->type); - // lb_global_type_info_member_offsets_values[bit_sizes_offset +source_index] = lb_const_int(m, t_uintptr, bit_size).value; - // lb_global_type_info_member_offsets_values[bit_offsets_offset+source_index] = lb_const_int(m, t_uintptr, bit_offset).value; - // if (f->token.string.len > 0) { - // lb_global_type_info_member_names_values[names_offset+source_index] = lb_const_string(m, f->token.string).value; - // } + if (t->BitField.tags) { + String tag = t->BitField.tags[source_index]; + if (tag.len > 0) { + lbValue tag_ptr = lb_emit_ptr_offset(p, memory_tags, index); + lb_emit_store(p, tag_ptr, lb_const_string(m, tag)); + } + } bit_offset += bit_size; } lbValue cv = lb_const_int(m, t_int, count); - vals[1] = llvm_const_slice(m, memory_names, cv); - vals[2] = llvm_const_slice(m, memory_types, cv); - vals[3] = llvm_const_slice(m, memory_bit_sizes, cv); + vals[1] = llvm_const_slice(m, memory_names, cv); + vals[2] = llvm_const_slice(m, memory_types, cv); + vals[3] = llvm_const_slice(m, memory_bit_sizes, cv); vals[4] = llvm_const_slice(m, memory_bit_offsets, cv); + vals[5] = llvm_const_slice(m, memory_tags, cv); } for (isize i = 0; i < gb_count_of(vals); i++) { diff --git a/src/parser.cpp b/src/parser.cpp index 6a9481693..03d1e7aeb 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1054,12 +1054,13 @@ gb_internal Ast *ast_field(AstFile *f, Array const &names, Ast *type, Ast return result; } -gb_internal Ast *ast_bit_field_field(AstFile *f, Ast *name, Ast *type, Ast *bit_size, +gb_internal Ast *ast_bit_field_field(AstFile *f, Ast *name, Ast *type, Ast *bit_size, Token tag, CommentGroup *docs, CommentGroup *comment) { Ast *result = alloc_ast_node(f, Ast_BitFieldField); result->BitFieldField.name = name; result->BitFieldField.type = type; result->BitFieldField.bit_size = bit_size; + result->BitFieldField.tag = tag; result->BitFieldField.docs = docs; result->BitFieldField.comment = comment; return result; @@ -2611,7 +2612,12 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { expect_token(f, Token_Or); Ast *bit_size = parse_expr(f, true); - Ast *bf_field = ast_bit_field_field(f, name, type, bit_size, docs, comment); + Token tag = {}; + if (f->curr_token.kind == Token_String) { + tag = expect_token(f, Token_String); + } + + Ast *bf_field = ast_bit_field_field(f, name, type, bit_size, tag, docs, comment); array_add(&fields, bf_field); if (!allow_field_separator(f)) { diff --git a/src/parser.hpp b/src/parser.hpp index 1f4ec8726..f410419d4 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -655,6 +655,7 @@ AST_KIND(_DeclEnd, "", bool) \ Ast * name; \ Ast * type; \ Ast * bit_size; \ + Token tag; \ CommentGroup *docs; \ CommentGroup *comment; \ }) \ diff --git a/src/types.cpp b/src/types.cpp index eac834f25..90cb130b6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -286,6 +286,7 @@ struct TypeProc { Scope * scope; \ Type * backing_type; \ Slice fields; \ + String * tags; /*count == fields.count*/ \ Slice bit_sizes; \ Slice bit_offsets; \ Ast * node; \ -- cgit v1.2.3 From 51edf011629a424481a64f00e6aab9ca3726e389 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 27 Feb 2024 15:07:55 +0000 Subject: Change type info table to be initializable constantly []Type_Info -> []^Type_Info --- base/runtime/core.odin | 4 +- src/llvm_backend.cpp | 19 +- src/llvm_backend_type.cpp | 988 ++++------------------------------------------ src/types.cpp | 3 + 4 files changed, 95 insertions(+), 919 deletions(-) (limited to 'src/types.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 2f63a7ac2..8f27ca674 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -280,7 +280,7 @@ Typeid_Kind :: enum u8 { // NOTE(bill): only the ones that are needed (not all types) // This will be set by the compiler -type_table: []Type_Info +type_table: []^Type_Info args__: []cstring @@ -609,7 +609,7 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check if n < 0 || n >= len(type_table) { n = 0 } - return &type_table[n] + return type_table[n] } when !ODIN_NO_RTTI { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 45d903b43..d3a2f25d2 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1069,10 +1069,6 @@ gb_internal lbProcedure *lb_create_startup_type_info(lbModule *m) { // lb_add_attribute_to_proc(p->module, p->value, "norecurse"); // lb_add_attribute_to_proc(p->module, p->value, "nosync"); // lb_add_attribute_to_proc(p->module, p->value, "willreturn"); - if (!LB_USE_GIANT_PACKED_STRUCT) { - lb_add_attribute_to_proc(m, p->value, "optnone"); - lb_add_attribute_to_proc(m, p->value, "noinline"); - } lb_begin_procedure_body(p); @@ -2691,17 +2687,19 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { { // Add type info data isize max_type_info_count = info->minimum_dependency_type_info_set.count+1; - Type *t = alloc_type_array(t_type_info, max_type_info_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 // at compile time without cheating in some way. This means to emulate an array of unions is to use // a giant packed struct of "corrected" data types. - LLVMTypeRef internal_llvm_type = lb_setup_type_info_data_internal_type(m, max_type_info_count); + LLVMTypeRef internal_llvm_type = lb_type(m, t); LLVMValueRef g = LLVMAddGlobal(m->mod, internal_llvm_type, LB_TYPE_INFO_DATA_NAME); LLVMSetInitializer(g, LLVMConstNull(internal_llvm_type)); LLVMSetLinkage(g, USE_SEPARATE_MODULES ? LLVMExternalLinkage : LLVMInternalLinkage); + LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr); + LLVMSetGlobalConstant(g, /*true*/false); lbValue value = {}; value.value = g; @@ -2710,11 +2708,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lb_global_type_info_data_entity = alloc_entity_variable(nullptr, make_token_ident(LB_TYPE_INFO_DATA_NAME), t, EntityState_Resolved); lb_add_entity(m, lb_global_type_info_data_entity, value); - if (LB_USE_GIANT_PACKED_STRUCT) { - LLVMSetLinkage(g, LLVMPrivateLinkage); - LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr); - LLVMSetGlobalConstant(g, /*true*/false); - } } { // Type info member buffer // NOTE(bill): Removes need for heap allocation by making it global memory @@ -2750,9 +2743,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name); LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); LLVMSetLinkage(g, LLVMInternalLinkage); - if (LB_USE_GIANT_PACKED_STRUCT) { - lb_make_global_private_const(g); - } + lb_make_global_private_const(g); return lb_addr({g, alloc_type_pointer(t)}); }; diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 4952d75de..09a758827 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -180,16 +180,7 @@ gb_internal lbValue lb_type_info_member_tags_offset(lbModule *m, isize count, i6 return offset; } -// enum {LB_USE_GIANT_PACKED_STRUCT = LB_USE_NEW_PASS_SYSTEM}; -enum {LB_USE_GIANT_PACKED_STRUCT = 0}; - -gb_internal LLVMTypeRef lb_setup_type_info_data_internal_type(lbModule *m, isize max_type_info_count) { - if (!LB_USE_GIANT_PACKED_STRUCT) { - Type *t = alloc_type_array(t_type_info, max_type_info_count); - return lb_type(m, t); - } - CheckerInfo *info = m->gen->info; - +gb_internal LLVMTypeRef *lb_setup_modified_types_for_type_info(lbModule *m, isize max_type_info_count) { LLVMTypeRef *element_types = gb_alloc_array(heap_allocator(), LLVMTypeRef, max_type_info_count); defer (gb_free(heap_allocator(), element_types)); @@ -219,8 +210,8 @@ gb_internal LLVMTypeRef lb_setup_type_info_data_internal_type(lbModule *m, isize variant_index = 4; } - LLVMTypeRef modified_types[32] = {}; - GB_ASSERT(gb_count_of(modified_types) >= ut->Union.variants.count); + LLVMTypeRef *modified_types = gb_alloc_array(heap_allocator(), LLVMTypeRef, Typeid__COUNT); + GB_ASSERT(Typeid__COUNT == ut->Union.variants.count); modified_types[0] = element_types[0]; i64 tag_offset = ut->Union.variant_block_size; @@ -242,40 +233,24 @@ gb_internal LLVMTypeRef lb_setup_type_info_data_internal_type(lbModule *m, isize modified_types[i] = modified_type; } - for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; - if (t == nullptr || t == t_invalid) { - continue; - } - isize entry_index = lb_type_info_index(info, t, false); - if (entry_index <= 0) { - continue; - } - - if (entries_handled[entry_index]) { - continue; - } - entries_handled[entry_index] = true; - - - if (t->kind == Type_Named) { - element_types[entry_index] = modified_types[0]; - } else { - i64 variant_index = lb_typeid_kind(m, t); - element_types[entry_index] = modified_types[variant_index]; - } - - GB_ASSERT(element_types[entry_index] != nullptr); - } - - for_array(i, entries_handled) { - GB_ASSERT(entries_handled[i]); + for (isize i = 0; i < Typeid__COUNT; i++) { + GB_ASSERT_MSG(modified_types[i] != nullptr, "%td", ut->Union.variants.count); } - return LLVMStructType(element_types, cast(unsigned)max_type_info_count, true); + return modified_types; } -gb_internal void lb_setup_type_info_data_giant_packed_struct(lbModule *m, i64 global_type_info_data_entity_count, lbProcedure *p) { // NOTE(bill): Setup type_info data +gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_type_info_data_entity_count, lbProcedure *p) { // NOTE(bill): Setup type_info data + auto const &ADD_GLOBAL_TYPE_INFO_ENTRY = [](lbModule *m, LLVMTypeRef type, isize index) -> LLVMValueRef { + char name[64] = {}; + gb_snprintf(name, 63, "__$ti-%lld", cast(long long)index); + LLVMValueRef g = LLVMAddGlobal(m->mod, type, name); + LLVMSetLinkage(g, LLVMInternalLinkage); + LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr); + LLVMSetGlobalConstant(g, true); + return g; + }; + CheckerInfo *info = m->info; // Useful types @@ -292,19 +267,47 @@ gb_internal void lb_setup_type_info_data_giant_packed_struct(lbModule *m, i64 gl defer (gb_free(heap_allocator(), entries_handled.data)); entries_handled[0] = true; - LLVMValueRef giant_struct = lb_global_type_info_data_ptr(m).value; - LLVMTypeRef giant_struct_type = LLVMGlobalGetValueType(giant_struct); - GB_ASSERT(LLVMGetTypeKind(giant_struct_type) == LLVMStructTypeKind); - LLVMValueRef *giant_const_values = gb_alloc_array(heap_allocator(), LLVMValueRef, global_type_info_data_entity_count); defer (gb_free(heap_allocator(), giant_const_values)); - giant_const_values[0] = LLVMConstNull(LLVMStructGetTypeAtIndex(giant_struct_type, 0)); + // zero value is just zero data + giant_const_values[0] = ADD_GLOBAL_TYPE_INFO_ENTRY(m, lb_type(m, t_type_info), 0); + LLVMSetInitializer(giant_const_values[0], LLVMConstNull(lb_type(m, t_type_info))); + + + 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]; + if (t == nullptr || t == t_invalid) { + continue; + } + + isize entry_index = lb_type_info_index(info, t, false); + if (entry_index <= 0) { + continue; + } + + if (entries_handled[entry_index]) { + continue; + } + entries_handled[entry_index] = true; + + + LLVMTypeRef stype = modified_types[0]; + if (t->kind != Type_Named) { + stype = modified_types[lb_typeid_kind(m, t)]; + } + giant_const_values[entry_index] = ADD_GLOBAL_TYPE_INFO_ENTRY(m, stype, entry_index); + } + for (isize i = 1; i < global_type_info_data_entity_count; i++) { + entries_handled[i] = false; + } + LLVMValueRef *small_const_values = gb_alloc_array(heap_allocator(), LLVMValueRef, 6); defer (gb_free(heap_allocator(), small_const_values)); - #define type_info_allocate_values(name) \ LLVMValueRef *name##_values = gb_alloc_array(heap_allocator(), LLVMValueRef, type_deref(name.addr.type)->Array.count); \ defer (gb_free(heap_allocator(), name##_values)); \ @@ -316,7 +319,7 @@ gb_internal void lb_setup_type_info_data_giant_packed_struct(lbModule *m, i64 gl (name##_values)[i] = LLVMConstNull(elem); \ } \ } \ - LLVMSetInitializer(name.addr.value, llvm_const_array(elem, name##_values, at->Array.count)); \ + LLVMSetInitializer(name.addr.value, llvm_const_array(elem, name##_values, at->Array.count)); \ }) type_info_allocate_values(lb_global_type_info_member_types); @@ -326,27 +329,13 @@ gb_internal void lb_setup_type_info_data_giant_packed_struct(lbModule *m, i64 gl type_info_allocate_values(lb_global_type_info_member_tags); - i64 const type_info_struct_size = type_size_of(t_type_info); - LLVMTypeRef llvm_u8 = lb_type(m, t_u8); - LLVMTypeRef llvm_int = lb_type(m, t_int); - // LLVMTypeRef llvm_type_info_ptr = lb_type(m, t_type_info_ptr); - auto const get_type_info_ptr = [&](lbModule *m, Type *type) -> LLVMValueRef { type = default_type(type); isize index = lb_type_info_index(m->info, type); GB_ASSERT(index >= 0); - u64 offset = cast(u64)(index * type_info_struct_size); - - LLVMValueRef indices[1] = { - LLVMConstInt(llvm_int, offset, false) - }; - - // LLVMValueRef ptr = LLVMConstInBoundsGEP2(llvm_u8, giant_struct, indices, gb_count_of(indices)); - LLVMValueRef ptr = LLVMConstGEP2(llvm_u8, giant_struct, indices, gb_count_of(indices)); - return ptr; - // return LLVMConstPointerCast(ptr, llvm_type_info_ptr); + return giant_const_values[index]; }; for_array(type_info_type_index, info->type_info_types) { @@ -366,7 +355,10 @@ gb_internal void lb_setup_type_info_data_giant_packed_struct(lbModule *m, i64 gl entries_handled[entry_index] = true; - LLVMTypeRef stype = LLVMStructGetTypeAtIndex(giant_struct_type, cast(unsigned)entry_index); + LLVMTypeRef stype = modified_types[0]; + if (t->kind != Type_Named) { + stype = modified_types[lb_typeid_kind(m, t)]; + } i64 size = type_size_of(t); i64 align = type_align_of(t); @@ -376,6 +368,10 @@ gb_internal void lb_setup_type_info_data_giant_packed_struct(lbModule *m, i64 gl lbValue type_info_flags = lb_const_int(m, t_type_info_flags, flags); + for (isize i = 0; i < 6; i++) { + small_const_values[i] = nullptr; + } + small_const_values[0] = LLVMConstInt(lb_type(m, t_int), size, true); small_const_values[1] = LLVMConstInt(lb_type(m, t_int), align, true); small_const_values[2] = type_info_flags.value; @@ -994,6 +990,7 @@ gb_internal void lb_setup_type_info_data_giant_packed_struct(lbModule *m, i64 gl if (tag_type != nullptr) { tag_index = union_variant_index(ut, tag_type); } + GB_ASSERT(tag_index <= Typeid__COUNT); LLVMValueRef full_variant_values[3] = {}; @@ -1024,11 +1021,16 @@ gb_internal void lb_setup_type_info_data_giant_packed_struct(lbModule *m, i64 gl small_const_values[variant_index] = full_variant_value; - giant_const_values[entry_index] = LLVMConstNamedStruct(stype, small_const_values, variant_index+1); + 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)); } - LLVMValueRef giant_const = LLVMConstNamedStruct(giant_struct_type, giant_const_values, cast(unsigned)global_type_info_data_entity_count); - LLVMSetInitializer(giant_struct, giant_const); + + LLVMValueRef giant_const = LLVMConstArray(lb_type(m, t_type_info_ptr), giant_const_values, cast(unsigned)global_type_info_data_entity_count); + LLVMValueRef giant_array = lb_global_type_info_data_ptr(m).value; + LLVMSetInitializer(giant_array, giant_const); } @@ -1038,845 +1040,25 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup } lbModule *m = p->module; - CheckerInfo *info = m->info; i64 global_type_info_data_entity_count = 0; - { - // NOTE(bill): Set the type_table slice with the global backing array - lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table")); - Type *type = base_type(lb_global_type_info_data_entity->type); - GB_ASSERT(type->kind == Type_Array); - global_type_info_data_entity_count = type->Array.count; - - LLVMValueRef data = lb_global_type_info_data_ptr(m).value; - data = LLVMConstPointerCast(data, lb_type(m, alloc_type_pointer(type->Array.elem))); - LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), type->Array.count, true); - Type *t = type_deref(global_type_table.type); - GB_ASSERT(is_type_slice(t)); - LLVMValueRef slice = llvm_const_slice_internal(m, data, len); - - LLVMSetInitializer(global_type_table.value, slice); - } - - if (LB_USE_GIANT_PACKED_STRUCT) { - lb_setup_type_info_data_giant_packed_struct(m, global_type_info_data_entity_count, p); - return; - } - - // Useful types - Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags")); - Type *t_type_info_flags = type_info_flags_entity->type; - - - auto entries_handled = slice_make(heap_allocator(), cast(isize)global_type_info_data_entity_count); - defer (gb_free(heap_allocator(), entries_handled.data)); - entries_handled[0] = true; - - for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; - if (t == nullptr || t == t_invalid) { - continue; - } - - isize entry_index = lb_type_info_index(info, t, false); - if (entry_index <= 0) { - continue; - } - - if (entries_handled[entry_index]) { - continue; - } - entries_handled[entry_index] = true; - - lbValue global_data_ptr = lb_global_type_info_data_ptr(m); - lbValue tag = {}; - lbValue ti_ptr = lb_emit_array_epi(p, global_data_ptr, cast(i32)entry_index); - - i64 size = type_size_of(t); - i64 align = type_align_of(t); - u32 flags = type_info_flags_of_type(t); - lbValue id = lb_typeid(m, t); - GB_ASSERT_MSG(align != 0, "%lld %s", align, type_to_string(t)); - - lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, flags); - - lbValue size_ptr = lb_emit_struct_ep(p, ti_ptr, 0); - lbValue align_ptr = lb_emit_struct_ep(p, ti_ptr, 1); - lbValue flags_ptr = lb_emit_struct_ep(p, ti_ptr, 2); - lbValue id_ptr = lb_emit_struct_ep(p, ti_ptr, 3); - - lb_emit_store(p, size_ptr, lb_const_int(m, t_int, size)); - lb_emit_store(p, align_ptr, lb_const_int(m, t_int, align)); - lb_emit_store(p, flags_ptr, type_info_flags); - lb_emit_store(p, id_ptr, id); - - lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 4); - - switch (t->kind) { - case Type_Named: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_named_ptr); - - LLVMValueRef pkg_name = nullptr; - if (t->Named.type_name->pkg) { - pkg_name = lb_const_string(m, t->Named.type_name->pkg->name).value; - } else { - pkg_name = LLVMConstNull(lb_type(m, t_string)); - } - - String proc_name = {}; - if (t->Named.type_name->parent_proc_decl) { - DeclInfo *decl = t->Named.type_name->parent_proc_decl; - if (decl->entity && decl->entity->kind == Entity_Procedure) { - proc_name = decl->entity->token.string; - } - } - TokenPos pos = t->Named.type_name->token.pos; - - lbValue loc = lb_emit_source_code_location_const(p, proc_name, pos); - - LLVMValueRef vals[4] = { - lb_const_string(p->module, t->Named.type_name->token.string).value, - lb_type_info(m, t->Named.base).value, - pkg_name, - loc.value - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - - case Type_Basic: - switch (t->Basic.kind) { - case Basic_bool: - case Basic_b8: - case Basic_b16: - case Basic_b32: - case Basic_b64: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_boolean_ptr); - break; - - case Basic_i8: - case Basic_u8: - case Basic_i16: - case Basic_u16: - case Basic_i32: - case Basic_u32: - case Basic_i64: - case Basic_u64: - case Basic_i128: - case Basic_u128: - - case Basic_i16le: - case Basic_u16le: - case Basic_i32le: - case Basic_u32le: - case Basic_i64le: - case Basic_u64le: - case Basic_i128le: - case Basic_u128le: - case Basic_i16be: - case Basic_u16be: - case Basic_i32be: - case Basic_u32be: - case Basic_i64be: - case Basic_u64be: - case Basic_i128be: - case Basic_u128be: - - case Basic_int: - case Basic_uint: - case Basic_uintptr: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_integer_ptr); - - lbValue is_signed = lb_const_bool(m, t_bool, (t->Basic.flags & BasicFlag_Unsigned) == 0); - // NOTE(bill): This is matches the runtime layout - u8 endianness_value = 0; - if (t->Basic.flags & BasicFlag_EndianLittle) { - endianness_value = 1; - } else if (t->Basic.flags & BasicFlag_EndianBig) { - endianness_value = 2; - } - lbValue endianness = lb_const_int(m, t_u8, endianness_value); - - LLVMValueRef vals[2] = { - is_signed.value, - endianness.value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - - case Basic_rune: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_rune_ptr); - break; - - case Basic_f16: - case Basic_f32: - case Basic_f64: - case Basic_f16le: - case Basic_f32le: - case Basic_f64le: - case Basic_f16be: - case Basic_f32be: - case Basic_f64be: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_float_ptr); - - // NOTE(bill): This is matches the runtime layout - u8 endianness_value = 0; - if (t->Basic.flags & BasicFlag_EndianLittle) { - endianness_value = 1; - } else if (t->Basic.flags & BasicFlag_EndianBig) { - endianness_value = 2; - } - lbValue endianness = lb_const_int(m, t_u8, endianness_value); - - LLVMValueRef vals[1] = { - endianness.value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_complex_ptr); - break; - - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_quaternion_ptr); - break; - - case Basic_rawptr: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); - break; - - case Basic_string: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_string_ptr); - break; - - case Basic_cstring: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_string_ptr); - LLVMValueRef vals[1] = { - lb_const_bool(m, t_bool, true).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Basic_any: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_any_ptr); - break; - - case Basic_typeid: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_typeid_ptr); - break; - } - break; - - case Type_Pointer: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); - lbValue gep = lb_type_info(m, t->Pointer.elem); - LLVMValueRef vals[1] = { - gep.value, - }; + // NOTE(bill): Set the type_table slice with the global backing array + lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table")); + Type *type = base_type(lb_global_type_info_data_entity->type); + GB_ASSERT(type->kind == Type_Array); + global_type_info_data_entity_count = type->Array.count; - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_MultiPointer: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr); - lbValue gep = lb_type_info(m, t->MultiPointer.elem); + if (true) { + lb_setup_type_info_data_giant_array(m, global_type_info_data_entity_count, p); + } - LLVMValueRef vals[1] = { - gep.value, - }; + LLVMValueRef data = lb_global_type_info_data_ptr(m).value; + data = LLVMConstPointerCast(data, lb_type(m, alloc_type_pointer(type->Array.elem))); + LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), type->Array.count, true); + Type *t = type_deref(global_type_table.type); + GB_ASSERT(is_type_slice(t)); + LLVMValueRef slice = llvm_const_slice_internal(m, data, len); - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_SoaPointer: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_soa_pointer_ptr); - lbValue gep = lb_type_info(m, t->SoaPointer.elem); - - LLVMValueRef vals[1] = { - gep.value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_Array: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr); - i64 ez = type_size_of(t->Array.elem); - - LLVMValueRef vals[3] = { - lb_type_info(m, t->Array.elem).value, - lb_const_int(m, t_int, ez).value, - lb_const_int(m, t_int, t->Array.count).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_EnumeratedArray: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr); - - LLVMValueRef vals[7] = { - lb_type_info(m, t->EnumeratedArray.elem).value, - lb_type_info(m, t->EnumeratedArray.index).value, - lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value, - lb_const_int(m, t_int, t->EnumeratedArray.count).value, - - // Unions - LLVMConstNull(lb_type(m, t_type_info_enum_value)), - LLVMConstNull(lb_type(m, t_type_info_enum_value)), - - lb_const_bool(m, t_bool, t->EnumeratedArray.is_sparse).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - - // NOTE(bill): Union assignment - lbValue min_value = lb_emit_struct_ep(p, tag, 4); - lbValue max_value = lb_emit_struct_ep(p, tag, 5); - - lbValue min_v = lb_const_value(m, t_i64, *t->EnumeratedArray.min_value); - lbValue max_v = lb_const_value(m, t_i64, *t->EnumeratedArray.max_value); - - lb_emit_store(p, min_value, min_v); - lb_emit_store(p, max_value, max_v); - break; - } - case Type_DynamicArray: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr); - - LLVMValueRef vals[2] = { - lb_type_info(m, t->DynamicArray.elem).value, - lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_Slice: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr); - - LLVMValueRef vals[2] = { - lb_type_info(m, t->Slice.elem).value, - lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_Proc: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_procedure_ptr); - - LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr)); - LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr)); - if (t->Proc.params != nullptr) { - params = lb_type_info(m, t->Proc.params).value; - } - if (t->Proc.results != nullptr) { - results = lb_type_info(m, t->Proc.results).value; - } - - LLVMValueRef vals[4] = { - params, - results, - lb_const_bool(m, t_bool, t->Proc.variadic).value, - lb_const_int(m, t_u8, t->Proc.calling_convention).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_Tuple: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_parameters_ptr); - - lbValue memory_types = lb_type_info_member_types_offset(m, t->Tuple.variables.count); - lbValue memory_names = lb_type_info_member_names_offset(m, t->Tuple.variables.count); - - - for_array(i, t->Tuple.variables) { - // NOTE(bill): offset is not used for tuples - Entity *f = t->Tuple.variables[i]; - - lbValue index = lb_const_int(m, t_int, i); - lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); - - // TODO(bill): Make this constant if possible, 'lb_const_store' does not work - lb_emit_store(p, type_info, lb_type_info(m, f->type)); - if (f->token.string.len > 0) { - lbValue name = lb_emit_ptr_offset(p, memory_names, index); - lb_emit_store(p, name, lb_const_string(m, f->token.string)); - } - } - - lbValue count = lb_const_int(m, t_int, t->Tuple.variables.count); - - LLVMValueRef types_slice = llvm_const_slice(m, memory_types, count); - LLVMValueRef names_slice = llvm_const_slice(m, memory_names, count); - - LLVMValueRef vals[2] = { - types_slice, - names_slice, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - - break; - } - - case Type_Enum: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enum_ptr); - - { - GB_ASSERT(t->Enum.base_type != nullptr); - // GB_ASSERT_MSG(type_size_of(t_type_info_enum_value) == 16, "%lld == 16", cast(long long)type_size_of(t_type_info_enum_value)); - - - LLVMValueRef vals[3] = {}; - vals[0] = lb_type_info(m, t->Enum.base_type).value; - if (t->Enum.fields.count > 0) { - auto fields = t->Enum.fields; - lbValue name_array = lb_generate_global_array(m, t_string, fields.count, - str_lit("$enum_names"), cast(i64)entry_index); - lbValue value_array = lb_generate_global_array(m, t_type_info_enum_value, fields.count, - str_lit("$enum_values"), cast(i64)entry_index); - - - LLVMValueRef *name_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count); - LLVMValueRef *value_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count); - - GB_ASSERT(is_type_integer(t->Enum.base_type)); - - for_array(i, fields) { - name_values[i] = lb_const_string(m, fields[i]->token.string).value; - value_values[i] = lb_const_value(m, t_i64, fields[i]->Constant.value).value; - } - - LLVMValueRef name_init = llvm_const_array(lb_type(m, t_string), name_values, cast(unsigned)fields.count); - LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count); - LLVMSetInitializer(name_array.value, name_init); - LLVMSetInitializer(value_array.value, value_init); - LLVMSetGlobalConstant(name_array.value, true); - LLVMSetGlobalConstant(value_array.value, true); - - lbValue v_count = lb_const_int(m, t_int, fields.count); - - vals[1] = llvm_const_slice(m, lb_array_elem(p, name_array), v_count); - vals[2] = llvm_const_slice(m, lb_array_elem(p, value_array), v_count); - } else { - vals[1] = LLVMConstNull(lb_type(m, base_type(t_type_info_enum)->Struct.fields[1]->type)); - vals[2] = LLVMConstNull(lb_type(m, base_type(t_type_info_enum)->Struct.fields[2]->type)); - } - - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_Union: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_union_ptr); - - { - LLVMValueRef vals[7] = {}; - - isize variant_count = gb_max(0, t->Union.variants.count); - lbValue memory_types = lb_type_info_member_types_offset(m, variant_count); - - // NOTE(bill): Zeroth is nil so ignore it - for (isize variant_index = 0; variant_index < variant_count; variant_index++) { - Type *vt = t->Union.variants[variant_index]; - lbValue tip = lb_type_info(m, vt); - - lbValue index = lb_const_int(m, t_int, variant_index); - lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); - lb_emit_store(p, type_info, lb_type_info(m, vt)); - } - - lbValue count = lb_const_int(m, t_int, variant_count); - vals[0] = llvm_const_slice(m, memory_types, count); - - i64 tag_size = union_tag_size(t); - if (tag_size > 0) { - i64 tag_offset = align_formula(t->Union.variant_block_size, tag_size); - vals[1] = lb_const_int(m, t_uintptr, tag_offset).value; - vals[2] = lb_type_info(m, union_tag_type(t)).value; - } else { - vals[1] = lb_const_int(m, t_uintptr, 0).value; - vals[2] = LLVMConstNull(lb_type(m, t_type_info_ptr)); - } - - if (is_type_comparable(t) && !is_type_simple_compare(t)) { - vals[3] = lb_equal_proc_for_type(m, t).value; - } - - vals[4] = lb_const_bool(m, t_bool, t->Union.custom_align != 0).value; - vals[5] = lb_const_bool(m, t_bool, t->Union.kind == UnionType_no_nil).value; - vals[6] = lb_const_bool(m, t_bool, t->Union.kind == UnionType_shared_nil).value; - - for (isize i = 0; i < gb_count_of(vals); i++) { - if (vals[i] == nullptr) { - vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i))); - } - } - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - - break; - } - - case Type_Struct: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr); - - LLVMValueRef vals[13] = {}; - - - { - lbValue is_packed = lb_const_bool(m, t_bool, t->Struct.is_packed); - lbValue is_raw_union = lb_const_bool(m, t_bool, t->Struct.is_raw_union); - lbValue is_no_copy = lb_const_bool(m, t_bool, t->Struct.is_no_copy); - lbValue is_custom_align = lb_const_bool(m, t_bool, t->Struct.custom_align != 0); - vals[5] = is_packed.value; - vals[6] = is_raw_union.value; - vals[7] = is_no_copy.value; - vals[8] = is_custom_align.value; - if (is_type_comparable(t) && !is_type_simple_compare(t)) { - vals[9] = lb_equal_proc_for_type(m, t).value; - } - - - if (t->Struct.soa_kind != StructSoa_None) { - lbValue kind = lb_emit_struct_ep(p, tag, 10); - Type *kind_type = type_deref(kind.type); - - lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind)); - lbValue soa_type = lb_type_info(m, t->Struct.soa_elem); - lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count); - - vals[10] = soa_kind.value; - vals[11] = soa_type.value; - vals[12] = soa_len.value; - } - } - - isize count = t->Struct.fields.count; - if (count > 0) { - lbValue memory_types = lb_type_info_member_types_offset (m, count); - lbValue memory_names = lb_type_info_member_names_offset (m, count); - lbValue memory_offsets = lb_type_info_member_offsets_offset(m, count); - lbValue memory_usings = lb_type_info_member_usings_offset (m, count); - lbValue memory_tags = lb_type_info_member_tags_offset (m, count); - - type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet - for (isize source_index = 0; source_index < count; source_index++) { - Entity *f = t->Struct.fields[source_index]; - lbValue tip = lb_type_info(m, f->type); - i64 foffset = 0; - if (!t->Struct.is_raw_union) { - GB_ASSERT(t->Struct.offsets != nullptr); - GB_ASSERT(0 <= f->Variable.field_index && f->Variable.field_index < count); - foffset = t->Struct.offsets[source_index]; - } - GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); - - lbValue index = lb_const_int(m, t_int, source_index); - lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); - lbValue offset = lb_emit_ptr_offset(p, memory_offsets, index); - lbValue is_using = lb_emit_ptr_offset(p, memory_usings, index); - - lb_emit_store(p, type_info, lb_type_info(m, f->type)); - if (f->token.string.len > 0) { - lbValue name = lb_emit_ptr_offset(p, memory_names, index); - lb_emit_store(p, name, lb_const_string(m, f->token.string)); - } - lb_emit_store(p, offset, lb_const_int(m, t_uintptr, foffset)); - lb_emit_store(p, is_using, lb_const_bool(m, t_bool, (f->flags&EntityFlag_Using) != 0)); - - if (t->Struct.tags != nullptr) { - String tag_string = t->Struct.tags[source_index]; - if (tag_string.len > 0) { - lbValue tag_ptr = lb_emit_ptr_offset(p, memory_tags, index); - lb_emit_store(p, tag_ptr, lb_const_string(m, tag_string)); - } - } - - } - - lbValue cv = lb_const_int(m, t_int, count); - vals[0] = llvm_const_slice(m, memory_types, cv); - vals[1] = llvm_const_slice(m, memory_names, cv); - vals[2] = llvm_const_slice(m, memory_offsets, cv); - vals[3] = llvm_const_slice(m, memory_usings, cv); - vals[4] = llvm_const_slice(m, memory_tags, cv); - } - for (isize i = 0; i < gb_count_of(vals); i++) { - if (vals[i] == nullptr) { - vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i))); - } - } - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - - break; - } - - case Type_Map: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); - init_map_internal_types(t); - - LLVMValueRef vals[3] = { - lb_type_info(m, t->Map.key).value, - lb_type_info(m, t->Map.value).value, - lb_gen_map_info_ptr(p->module, t).value - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - - case Type_BitSet: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_set_ptr); - - GB_ASSERT(is_type_typed(t->BitSet.elem)); - - - LLVMValueRef vals[4] = { - lb_type_info(m, t->BitSet.elem).value, - LLVMConstNull(lb_type(m, t_type_info_ptr)), - lb_const_int(m, t_i64, t->BitSet.lower).value, - lb_const_int(m, t_i64, t->BitSet.upper).value, - }; - if (t->BitSet.underlying != nullptr) { - vals[1] =lb_type_info(m, t->BitSet.underlying).value; - } - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_SimdVector: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_simd_vector_ptr); - - LLVMValueRef vals[3] = {}; - - vals[0] = lb_type_info(m, t->SimdVector.elem).value; - vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value; - vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_RelativePointer: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr); - LLVMValueRef vals[2] = { - lb_type_info(m, t->RelativePointer.pointer_type).value, - lb_type_info(m, t->RelativePointer.base_integer).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_RelativeMultiPointer: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_multi_pointer_ptr); - LLVMValueRef vals[2] = { - lb_type_info(m, t->RelativeMultiPointer.pointer_type).value, - lb_type_info(m, t->RelativeMultiPointer.base_integer).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_Matrix: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_matrix_ptr); - i64 ez = type_size_of(t->Matrix.elem); - - LLVMValueRef vals[5] = { - lb_type_info(m, t->Matrix.elem).value, - lb_const_int(m, t_int, ez).value, - lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value, - lb_const_int(m, t_int, t->Matrix.row_count).value, - lb_const_int(m, t_int, t->Matrix.column_count).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_BitField: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_field_ptr); - LLVMValueRef vals[6] = {}; - - vals[0] = lb_type_info(m, t->BitField.backing_type).value; - isize count = t->BitField.fields.count; - if (count > 0) { - i64 names_offset = 0; - i64 types_offset = 0; - i64 bit_sizes_offset = 0; - i64 bit_offsets_offset = 0; - i64 tags_offset = 0; - lbValue memory_names = lb_type_info_member_names_offset (m, count, &names_offset); - lbValue memory_types = lb_type_info_member_types_offset (m, count, &types_offset); - lbValue memory_bit_sizes = lb_type_info_member_offsets_offset(m, count, &bit_sizes_offset); - lbValue memory_bit_offsets = lb_type_info_member_offsets_offset(m, count, &bit_offsets_offset); - lbValue memory_tags = lb_type_info_member_tags_offset (m, count, &tags_offset); - - u64 bit_offset = 0; - for (isize source_index = 0; source_index < count; source_index++) { - Entity *f = t->BitField.fields[source_index]; - u64 bit_size = cast(u64)t->BitField.bit_sizes[source_index]; - - lbValue index = lb_const_int(m, t_int, source_index); - if (f->token.string.len > 0) { - lbValue name_ptr = lb_emit_ptr_offset(p, memory_names, index); - lb_emit_store(p, name_ptr, lb_const_string(m, f->token.string)); - } - lbValue type_ptr = lb_emit_ptr_offset(p, memory_types, index); - lbValue bit_size_ptr = lb_emit_ptr_offset(p, memory_bit_sizes, index); - lbValue bit_offset_ptr = lb_emit_ptr_offset(p, memory_bit_offsets, index); - - lb_emit_store(p, type_ptr, lb_type_info(m, f->type)); - lb_emit_store(p, bit_size_ptr, lb_const_int(m, t_uintptr, bit_size)); - lb_emit_store(p, bit_offset_ptr, lb_const_int(m, t_uintptr, bit_offset)); - - if (t->BitField.tags) { - String tag = t->BitField.tags[source_index]; - if (tag.len > 0) { - lbValue tag_ptr = lb_emit_ptr_offset(p, memory_tags, index); - lb_emit_store(p, tag_ptr, lb_const_string(m, tag)); - } - } - - bit_offset += bit_size; - } - - lbValue cv = lb_const_int(m, t_int, count); - vals[1] = llvm_const_slice(m, memory_names, cv); - vals[2] = llvm_const_slice(m, memory_types, cv); - vals[3] = llvm_const_slice(m, memory_bit_sizes, cv); - vals[4] = llvm_const_slice(m, memory_bit_offsets, cv); - vals[5] = llvm_const_slice(m, memory_tags, cv); - } - - for (isize i = 0; i < gb_count_of(vals); i++) { - if (vals[i] == nullptr) { - vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i))); - } - } - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - - break; - } - - } - - - if (tag.value != nullptr) { - Type *tag_type = type_deref(tag.type); - GB_ASSERT(is_type_named(tag_type)); - // lb_emit_store_union_variant(p, variant_ptr, lb_emit_load(p, tag), tag_type); - lb_emit_store_union_variant_tag(p, variant_ptr, tag_type); - } else { - if (t != t_llvm_bool) { - GB_PANIC("Unhandled Type_Info variant: %s", type_to_string(t)); - } - } - } - - for_array(i, entries_handled) { - if (!entries_handled[i]) { - GB_PANIC("UNHANDLED ENTRY %td (%td)", i, entries_handled.count); - } - } + LLVMSetInitializer(global_type_table.value, slice); } diff --git a/src/types.cpp b/src/types.cpp index 90cb130b6..efe7d3f6f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -365,6 +365,9 @@ enum Typeid_Kind : u8 { Typeid_Matrix, Typeid_SoaPointer, Typeid_Bit_Field, + + Typeid__COUNT + }; // IMPORTANT NOTE(bill): This must match the same as the in core.odin -- cgit v1.2.3