From efc3f9916ec4217cd511f561166cb5f4348295c5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Apr 2024 12:30:16 +0100 Subject: Fix #3414 --- src/check_type.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index f1d991acb..f4e5d7c96 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3233,6 +3233,11 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T Type *elem = t_invalid; Operand o = {}; + if (unparen_expr(pt->type) == nullptr) { + error(e, "Invalid pointer type"); + return false; + } + check_expr_or_type(&c, &o, pt->type); if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) { if (o.mode == Addressing_Variable) { -- cgit v1.2.3 From a61ae7c861fa301684ee1582507061317b11426b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Apr 2024 13:31:49 +0100 Subject: Fix #3427 --- src/check_type.cpp | 20 ++++++++++++++------ src/checker.hpp | 5 ++++- src/llvm_backend_general.cpp | 2 +- src/llvm_backend_type.cpp | 2 +- src/llvm_backend_utility.cpp | 4 ++-- src/types.cpp | 1 - 6 files changed, 22 insertions(+), 12 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index f4e5d7c96..3bb1a4fd1 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2495,18 +2495,16 @@ gb_internal Type *get_map_cell_type(Type *type) { return s; } -gb_internal void init_map_internal_types(Type *type) { +gb_internal void init_map_internal_debug_types(Type *type) { GB_ASSERT(type->kind == Type_Map); GB_ASSERT(t_allocator != nullptr); - if (type->Map.lookup_result_type != nullptr) return; + if (type->Map.debug_metadata_type != nullptr) return; Type *key = type->Map.key; Type *value = type->Map.value; GB_ASSERT(key != nullptr); GB_ASSERT(value != nullptr); - - Type *key_cell = get_map_cell_type(key); Type *value_cell = get_map_cell_type(value); @@ -2541,6 +2539,18 @@ gb_internal void init_map_internal_types(Type *type) { gb_unused(type_size_of(debug_type)); type->Map.debug_metadata_type = debug_type; +} + + +gb_internal void init_map_internal_types(Type *type) { + GB_ASSERT(type->kind == Type_Map); + GB_ASSERT(t_allocator != nullptr); + if (type->Map.lookup_result_type != nullptr) return; + + Type *key = type->Map.key; + Type *value = type->Map.value; + GB_ASSERT(key != nullptr); + GB_ASSERT(value != nullptr); type->Map.lookup_result_type = make_optional_ok_type(value); } @@ -2613,8 +2623,6 @@ gb_internal void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { init_core_map_type(ctx->checker); init_map_internal_types(type); - - // error(node, "'map' types are not yet implemented"); } gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) { diff --git a/src/checker.hpp b/src/checker.hpp index 1701da58d..2ade9312e 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -563,4 +563,7 @@ gb_internal void init_mem_allocator(Checker *c); gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped); -gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type); \ No newline at end of file +gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type); + + +gb_internal void init_map_internal_types(Type *type); \ No newline at end of file diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 73e4a00e6..7a5ed5635 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2070,7 +2070,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { break; case Type_Map: - init_map_internal_types(type); + init_map_internal_debug_types(type); GB_ASSERT(t_raw_map != nullptr); return lb_type_internal(m, t_raw_map); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 93e2874a5..0bac2f732 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -903,7 +903,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ case Type_Map: { tag_type = t_type_info_map; - init_map_internal_types(t); + init_map_internal_debug_types(t); LLVMValueRef vals[3] = { get_type_info_ptr(m, t->Map.key), diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 865c3f1ec..0d1db2cbf 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1125,7 +1125,7 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { case 3: result_type = t_allocator; break; } } else if (is_type_map(t)) { - init_map_internal_types(t); + init_map_internal_debug_types(t); Type *itp = alloc_type_pointer(t_raw_map); s = lb_emit_transmute(p, s, itp); @@ -1264,7 +1264,7 @@ gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { case Type_Map: { - init_map_internal_types(t); + init_map_internal_debug_types(t); switch (index) { case 0: result_type = get_struct_field_type(t_raw_map, 0); break; case 1: result_type = get_struct_field_type(t_raw_map, 1); break; diff --git a/src/types.cpp b/src/types.cpp index 97512d29b..18cb12ea1 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -769,7 +769,6 @@ gb_internal gbString type_to_string (Type *type, bool shorthand=true); gb_internal gbString type_to_string (Type *type, gbAllocator allocator, bool shorthand=true); gb_internal i64 type_size_of_internal(Type *t, TypePath *path); gb_internal i64 type_align_of_internal(Type *t, TypePath *path); -gb_internal void init_map_internal_types(Type *type); gb_internal Type * bit_set_to_int(Type *t); gb_internal bool are_types_identical(Type *x, Type *y); -- cgit v1.2.3 From 7cd2bc26f42237f825274198c5bc68f7633b73b1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 17 Apr 2024 13:31:32 +0100 Subject: Clear error message on collisions with `using` on struct fields --- src/check_type.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 3bb1a4fd1..a6dbb8dfc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -29,10 +29,11 @@ gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstF } } -gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) { +gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t, isize level) { if (t == nullptr) { return; } + Type *original_type = t; t = base_type(type_deref(t)); gbString str = nullptr; defer (gb_string_free(str)); @@ -46,16 +47,18 @@ gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Ast String name = f->token.string; Entity *e = scope_lookup_current(ctx->scope, name); if (e != nullptr && name != "_") { + gbString ot = type_to_string(original_type); // TODO(bill): Better type error if (str != nullptr) { - error(e->token, "'%.*s' is already declared in '%s'", LIT(name), str); + error(e->token, "'%.*s' is already declared in '%s', through 'using' from '%s'", LIT(name), str, ot); } else { - error(e->token, "'%.*s' is already declared", LIT(name)); + error(e->token, "'%.*s' is already declared, through 'using' from '%s'", LIT(name), ot); } + gb_string_free(ot); } else { add_entity(ctx, ctx->scope, nullptr, f); if (f->flags & EntityFlag_Using) { - populate_using_entity_scope(ctx, node, field, f->type); + populate_using_entity_scope(ctx, node, field, f->type, level+1); } } } @@ -200,7 +203,7 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slicenames.count > 0) { -- cgit v1.2.3 From ec5a84a5379236a2413b8f3115509629879f5b53 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Apr 2024 13:10:58 +0100 Subject: Improve code generation for loading `bit_field` fields --- src/check_type.cpp | 15 ++++++--- src/llvm_backend_general.cpp | 80 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 75 insertions(+), 20 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index a6dbb8dfc..77ac91c38 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -955,14 +955,19 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, 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.backing_type = backing_type ? backing_type : t_u8; bit_field_type->BitField.scope = ctx->scope; + if (backing_type == nullptr) { + error(bf->backing_type, "Backing type for a bit_field must be an integer or an array of an integer"); + return; + } + if (!is_valid_bit_field_backing_type(backing_type)) { + error(bf->backing_type, "Backing type for a bit_field must be an integer or an array of an integer"); + return; + } + 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); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index da69f94d7..b8fbd231e 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -774,13 +774,23 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { if (addr.kind == lbAddr_BitField) { lbValue dst = addr.addr; + lbValue src = lb_address_from_load_or_generate_local(p, value); - auto args = array_make(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); + if ((addr.bitfield.bit_offset & 7) == 0 && + (addr.bitfield.bit_size & 7) == 0) { + lbValue byte_offset = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset/8); + lbValue byte_size = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size/8); + lbValue dst_offset = lb_emit_conv(p, dst, t_u8_ptr); + dst_offset = lb_emit_ptr_offset(p, dst_offset, byte_offset); + lb_mem_copy_non_overlapping(p, dst_offset, src, byte_size); + } else { + auto args = array_make(temporary_allocator(), 4); + args[0] = dst; + 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, "__write_bits", args); + } return; } else if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); @@ -1088,23 +1098,63 @@ 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); + Type *ct = core_type(addr.bitfield.type); + bool do_mask = false; + if (is_type_unsigned(ct) || is_type_boolean(ct)) { + // Mask + if (addr.bitfield.bit_size != 8*type_size_of(ct)) { + do_mask = true; + } + } + + i64 total_bitfield_bit_size = 8*type_size_of(lb_addr_type(addr)); + i64 dst_byte_size = type_size_of(addr.bitfield.type); + lbAddr dst = lb_add_local_generated(p, addr.bitfield.type, false); lbValue src = addr.addr; - 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 bit_offset = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset); + lbValue bit_size = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size); + lbValue byte_offset = lb_const_int(p->module, t_uintptr, (addr.bitfield.bit_offset+7)/8); + lbValue byte_size = lb_const_int(p->module, t_uintptr, (addr.bitfield.bit_size+7)/8); + + GB_ASSERT(type_size_of(addr.bitfield.type) >= ((addr.bitfield.bit_size+7)/8)); + + if ((addr.bitfield.bit_offset & 7) == 0) { + lbValue copy_size = byte_size; + lbValue src_offset = lb_emit_conv(p, src, t_u8_ptr); + src_offset = lb_emit_ptr_offset(p, src_offset, byte_offset); + if (addr.bitfield.bit_offset + dst_byte_size <= total_bitfield_bit_size) { + do_mask = true; + copy_size = lb_const_int(p->module, t_uintptr, dst_byte_size); + } + lb_mem_copy_non_overlapping(p, dst.addr, src_offset, copy_size, false); + } else { + auto args = array_make(temporary_allocator(), 4); + args[0] = dst.addr; + args[1] = src; + args[2] = bit_offset; + args[3] = bit_size; + lb_emit_runtime_call(p, "__read_bits", args); + } lbValue r = lb_addr_load(p, dst); + Type *t = addr.bitfield.type; + + if (do_mask) { + GB_ASSERT(addr.bitfield.bit_size < 8*type_size_of(ct)); + + LLVMTypeRef lt = lb_type(p->module, t); + LLVMValueRef mask = LLVMConstInt(lt, 1, false); + mask = LLVMConstShl(mask, LLVMConstInt(lt, addr.bitfield.bit_size, false)); + mask = LLVMConstSub(mask, LLVMConstInt(lt, 1, false)); + lbValue m = {mask, t}; + r = lb_emit_arith(p, Token_And, r, m, t); + } - if (!is_type_unsigned(core_type(addr.bitfield.type))) { + if (!is_type_unsigned(ct) && !is_type_boolean(ct)) { // 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); -- cgit v1.2.3 From 94d35d9918a8ce8b3686dba52bab3e468b46729d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Apr 2024 17:28:00 +0100 Subject: Disallow mixing endian types within a `bit_field` --- src/check_type.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 77ac91c38..ab8c0b057 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1101,6 +1101,45 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, gb_string_free(s); } + enum EndianKind { + Endian_Unknown, + Endian_Native, + Endian_Little, + Endian_Big, + }; + auto const &determine_endian_kind = [](Type *type) -> EndianKind { + if (is_type_boolean(type)) { + // NOTE(bill): it doesn't matter, and when it does, + // that api is absolutely stupid + return Endian_Unknown; + } else if (is_type_endian_specific(type)) { + if (is_type_endian_little(type)) { + return Endian_Little; + } else { + return Endian_Big; + } + } + return Endian_Native; + }; + + EndianKind backing_type_endian_kind = determine_endian_kind(core_array_type(backing_type)); + EndianKind endian_kind = Endian_Unknown; + for (Entity *f : fields) { + EndianKind field_kind = determine_endian_kind(f->type); + + if (field_kind && backing_type_endian_kind != field_kind) { + error(f->token, "All 'bit_field' field types must match the same endian kind as the backing type, i.e. all native, all little, or all big"); + } + + if (endian_kind == Endian_Unknown) { + endian_kind = field_kind; + } else if (field_kind && endian_kind != field_kind) { + error(f->token, "All 'bit_field' field types must be of the same endian variety, i.e. all native, all little, or all big"); + } + } + + + if (bit_sizes.count > 0 && is_type_integer(backing_type)) { bool all_booleans = is_type_boolean(fields[0]->type); bool all_ones = bit_sizes[0] == 1; -- cgit v1.2.3