From a61ae7c861fa301684ee1582507061317b11426b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Apr 2024 13:31:49 +0100 Subject: Fix #3427 --- src/llvm_backend_utility.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/llvm_backend_utility.cpp') 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; -- cgit v1.2.3 From ece78d22d2b549116a0884d3578972b8f389f983 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 18 Apr 2024 11:22:31 +0100 Subject: Add `-no-type-assert` and `ODIN_NO_TYPE_ASSERT` --- src/build_settings.cpp | 1 + src/checker.cpp | 1 + src/llvm_backend_expr.cpp | 4 +-- src/llvm_backend_utility.cpp | 72 +++++++++++++++++++++++--------------------- src/main.cpp | 9 ++++++ 5 files changed, 51 insertions(+), 36 deletions(-) (limited to 'src/llvm_backend_utility.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 106ae8a28..b806adcd6 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -382,6 +382,7 @@ struct BuildContext { bool keep_temp_files; bool ignore_unknown_attributes; bool no_bounds_check; + bool no_type_assert; bool no_dynamic_literals; bool no_output_files; bool no_crt; diff --git a/src/checker.cpp b/src/checker.cpp index e82836b2a..b7fe2b903 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1112,6 +1112,7 @@ gb_internal void init_universal(void) { add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT); add_global_bool_constant("ODIN_DEFAULT_TO_NIL_ALLOCATOR", bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR); add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check); + add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert); add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR); add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals); add_global_bool_constant("ODIN_NO_CRT", bc->no_crt); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index ad28f2e5e..edd5daeca 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3116,7 +3116,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { Type *dst_type = type; - if ((p->state_flags & StateFlag_no_type_assert) == 0) { + if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) { lbValue src_tag = {}; lbValue dst_tag = {}; if (is_type_union_maybe_pointer(src_type)) { @@ -3156,7 +3156,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { v = lb_emit_load(p, v); } lbValue data_ptr = lb_emit_struct_ev(p, v, 0); - if ((p->state_flags & StateFlag_no_type_assert) == 0) { + if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) { GB_ASSERT(!build_context.no_rtti); lbValue any_id = lb_emit_struct_ev(p, v, 1); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 0d1db2cbf..2dd7fbc38 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -728,29 +728,31 @@ gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type lb_start_block(p, end_block); if (!is_tuple) { - GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0); - // NOTE(bill): Panic on invalid conversion - Type *dst_type = tuple->Tuple.variables[0]->type; - - isize arg_count = 7; - if (build_context.no_rtti) { - arg_count = 4; - } + if (!build_context.no_type_assert) { + GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0); + // NOTE(bill): Panic on invalid conversion + Type *dst_type = tuple->Tuple.variables[0]->type; + + isize arg_count = 7; + if (build_context.no_rtti) { + arg_count = 4; + } - lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(permanent_allocator(), arg_count); - args[0] = ok; + lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); + auto args = array_make(permanent_allocator(), arg_count); + args[0] = ok; - args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(m, t_i32, pos.line); - args[3] = lb_const_int(m, t_i32, pos.column); + args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); + args[2] = lb_const_int(m, t_i32, pos.line); + args[3] = lb_const_int(m, t_i32, pos.column); - if (!build_context.no_rtti) { - args[4] = lb_typeid(m, src_type); - args[5] = lb_typeid(m, dst_type); - args[6] = lb_emit_conv(p, value_, t_rawptr); + if (!build_context.no_rtti) { + args[4] = lb_typeid(m, src_type); + args[5] = lb_typeid(m, dst_type); + args[6] = lb_emit_conv(p, value_, t_rawptr); + } + lb_emit_runtime_call(p, "type_assertion_check2", args); } - lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); } @@ -806,25 +808,27 @@ gb_internal lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *ty if (!is_tuple) { // NOTE(bill): Panic on invalid conversion - lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); + if (!build_context.no_type_assert) { + lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - isize arg_count = 7; - if (build_context.no_rtti) { - arg_count = 4; - } - auto args = array_make(permanent_allocator(), arg_count); - args[0] = ok; + isize arg_count = 7; + if (build_context.no_rtti) { + arg_count = 4; + } + auto args = array_make(permanent_allocator(), arg_count); + args[0] = ok; - args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(m, t_i32, pos.line); - args[3] = lb_const_int(m, t_i32, pos.column); + args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); + args[2] = lb_const_int(m, t_i32, pos.line); + args[3] = lb_const_int(m, t_i32, pos.column); - if (!build_context.no_rtti) { - args[4] = any_typeid; - args[5] = dst_typeid; - args[6] = lb_emit_struct_ev(p, value, 0); + if (!build_context.no_rtti) { + args[4] = any_typeid; + args[5] = dst_typeid; + args[6] = lb_emit_struct_ev(p, value, 0); + } + lb_emit_runtime_call(p, "type_assertion_check2", args); } - lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_addr(lb_emit_struct_ep(p, v.addr, 0)); } diff --git a/src/main.cpp b/src/main.cpp index 063b6c8b3..53103ce3a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -243,6 +243,7 @@ enum BuildFlagKind { BuildFlag_Debug, BuildFlag_DisableAssert, BuildFlag_NoBoundsCheck, + BuildFlag_NoTypeAssert, BuildFlag_NoDynamicLiterals, BuildFlag_NoCRT, BuildFlag_NoEntryPoint, @@ -436,6 +437,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_NoTypeAssert, str_lit("no-type-assert"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); @@ -1013,6 +1015,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_NoBoundsCheck: build_context.no_bounds_check = true; break; + case BuildFlag_NoTypeAssert: + build_context.no_type_assert = true; + break; case BuildFlag_NoDynamicLiterals: build_context.no_dynamic_literals = true; break; @@ -1850,6 +1855,10 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Disables bounds checking program wide."); print_usage_line(0, ""); + print_usage_line(1, "-no-type-assert"); + print_usage_line(2, "Disables type assertion checking program wide."); + print_usage_line(0, ""); + print_usage_line(1, "-no-crt"); print_usage_line(2, "Disables automatic linking with the C Run Time."); print_usage_line(0, ""); -- cgit v1.2.3 From c330e5b5c1b512e1b0ca7181941057e5f2e085e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Apr 2024 14:46:34 +0100 Subject: Improve codegen for `bit_field` compound literals with an integer backing --- src/llvm_backend.hpp | 1 - src/llvm_backend_expr.cpp | 111 +++++++++++++++++++++++++++++++++++++------ src/llvm_backend_general.cpp | 3 +- src/llvm_backend_utility.cpp | 9 ++-- 4 files changed, 101 insertions(+), 23 deletions(-) (limited to 'src/llvm_backend_utility.cpp') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index c4bf2691d..7dc5f6b63 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -122,7 +122,6 @@ struct lbAddr { } 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 edd5daeca..4209ba1ea 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4296,7 +4296,19 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { switch (bt->kind) { default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; - case Type_BitField: + case Type_BitField: { + TEMPORARY_ALLOCATOR_GUARD(); + + // Type *backing_type = core_type(bt->BitField.backing_type); + + struct FieldData { + Type *field_type; + u64 bit_offset; + u64 bit_size; + }; + auto values = array_make(temporary_allocator(), 0, cl->elems.count); + auto fields = array_make(temporary_allocator(), 0, cl->elems.count); + for (Ast *elem : cl->elems) { ast_node(fv, FieldValue, elem); String name = fv->field->Ident.token.string; @@ -4307,26 +4319,97 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { GB_ASSERT(sel.entity != nullptr); i64 index = sel.index[0]; - i64 bit_offset = 0; - i64 bit_size = -1; - for_array(i, bt->BitField.fields) { - Entity *f = bt->BitField.fields[i]; - if (f == sel.entity) { - bit_offset = bt->BitField.bit_offsets[i]; - bit_size = bt->BitField.bit_sizes[i]; - break; - } - } + Entity *f = bt->BitField.fields[index]; + GB_ASSERT(f == sel.entity); + i64 bit_offset = bt->BitField.bit_offsets[index]; + i64 bit_size = bt->BitField.bit_sizes[index]; GB_ASSERT(bit_size > 0); Type *field_type = sel.entity->type; lbValue field_expr = lb_build_expr(p, fv->value); field_expr = lb_emit_conv(p, field_expr, field_type); + array_add(&values, field_expr); + array_add(&fields, FieldData{field_type, cast(u64)bit_offset, cast(u64)bit_size}); + } + + // NOTE(bill): inline insertion sort should be good enough, right? + for (isize i = 1; i < values.count; i++) { + for (isize j = i; + j > 0 && fields[i].bit_offset < fields[j].bit_offset; + j--) { + auto vtmp = values[j]; + values[j] = values[j-1]; + values[j-1] = vtmp; + + auto ftmp = fields[j]; + fields[j] = fields[j-1]; + fields[j-1] = ftmp; + } + } + + if (fields.count == bt->BitField.fields.count) { + Type *backing_type = core_type(bt->BitField.backing_type); + GB_ASSERT(is_type_integer(backing_type) || + (is_type_array(backing_type) && is_type_integer(backing_type->Array.elem))); + + // NOTE(bill): all fields are present + // this means no masking is necessary since on write, the bits will be overridden + + lbValue dst_byte_ptr = lb_emit_conv(p, v.addr, t_u8_ptr); + u64 total_bit_size = cast(u64)(8*type_size_of(bt)); + + if (is_type_integer(backing_type)) { + LLVMTypeRef lbt = lb_type(p->module, backing_type); + + LLVMValueRef res = LLVMConstInt(lbt, 0, false); + + for (isize i = 0; i < fields.count; i++) { + auto const &f = fields[i]; + + LLVMValueRef mask = LLVMConstInt(lbt, 1, false); + mask = LLVMConstShl(mask, LLVMConstInt(lbt, f.bit_size, false)); + mask = LLVMConstSub(mask, LLVMConstInt(lbt, 1, false)); - lbAddr field_addr = lb_addr_bit_field(v.addr, field_type, index, bit_offset, bit_size); - lb_addr_store(p, field_addr, field_expr); + LLVMValueRef elem = values[i].value; + elem = LLVMBuildZExt(p->builder, elem, lbt, ""); + elem = LLVMBuildAnd(p->builder, elem, mask, ""); + + elem = LLVMBuildShl(p->builder, elem, LLVMConstInt(lbt, f.bit_offset, false), ""); + + res = LLVMBuildOr(p->builder, res, elem, ""); + } + LLVMBuildStore(p->builder, res, v.addr.value); + } else { + for_array(i, fields) { + auto const &f = fields[i]; + + if ((f.bit_offset & 7) == 0) { + u64 unpacked_bit_size = cast(u64)(8*type_size_of(f.field_type)); + u64 byte_size = (f.bit_size+7)/8; + + if (f.bit_offset + unpacked_bit_size <= total_bit_size) { + byte_size = unpacked_bit_size/8; + } + lbValue dst = lb_emit_ptr_offset(p, dst_byte_ptr, lb_const_int(p->module, t_int, f.bit_offset/8)); + lbValue src = lb_address_from_load_or_generate_local(p, values[i]); + lb_mem_copy_non_overlapping(p, dst, src, lb_const_int(p->module, t_uintptr, byte_size)); + } else { + lbAddr dst = lb_addr_bit_field(v.addr, f.field_type, f.bit_offset, f.bit_size); + lb_addr_store(p, dst, values[i]); + } + } + } + } else { + // individual storing + for_array(i, values) { + auto const &f = fields[i]; + lbAddr dst = lb_addr_bit_field(v.addr, f.field_type, f.bit_offset, f.bit_size); + lb_addr_store(p, dst, values[i]); + } } + return v; + } case Type_Struct: { // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment. @@ -4771,7 +4854,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { u8 bit_size = bf_type->BitField.bit_sizes[index]; i64 bit_offset = bf_type->BitField.bit_offsets[index]; - return lb_addr_bit_field(ptr, f->type, index, bit_offset, bit_size); + return lb_addr_bit_field(ptr, f->type, bit_offset, bit_size); } { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b8fbd231e..bf23417c6 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -450,14 +450,13 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slicemodule, type); LLVMTypeKind kind = LLVMGetTypeKind(llvm_type); - + i64 sz = type_size_of(type); switch (kind) { case LLVMStructTypeKind: case LLVMArrayTypeKind: - { - // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too - i32 sz = cast(i32)type_size_of(type); - lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false); - } + // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too + lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false); break; default: LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr); -- cgit v1.2.3