From 549edcc0f90d632587c427e5d4189721323bd4a8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 10 Sep 2025 21:00:43 +0100 Subject: Use a `RwMutex` instead of `BlockingMutex` --- src/llvm_backend_expr.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index ebc3ec158..cff91813e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2563,10 +2563,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { Type *dt = t; + TEMPORARY_ALLOCATOR_GUARD(); + GB_ASSERT(is_type_struct(st) || is_type_raw_union(st)); Selection sel = {}; - sel.index.allocator = heap_allocator(); - defer (array_free(&sel.index)); + sel.index.allocator = temporary_allocator(); if (lookup_subtype_polymorphic_selection(t, src_type, &sel)) { if (sel.entity == nullptr) { GB_PANIC("invalid subtype cast %s -> ", type_to_string(src_type), type_to_string(t)); -- cgit v1.2.3 From 31f0aaa62f2799d7c5e38c10cabe034284ae8e5d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Sep 2025 09:55:22 +0100 Subject: Try to improve const `union` LLVM construction --- src/llvm_backend.cpp | 2 +- src/llvm_backend_const.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++ src/llvm_backend_expr.cpp | 15 +++++++ src/llvm_backend_general.cpp | 78 ++++++++++++++++++++++++++++-------- 4 files changed, 172 insertions(+), 17 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 33b03e235..3af473c3a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1914,7 +1914,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) { lbModule *m = cast(lbModule *)data; if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) { - gb_printf_err("LLVM Error:\n%s\n", llvm_error); + gb_printf_err("LLVM Error in module %s:\n%s\n", m->module_name, llvm_error); if (build_context.keep_temp_files) { TIME_SECTION("LLVM Print Module to File"); String filepath_ll = lb_filepath_ll_for_module(m); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 98e50dd78..781cc52b8 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -537,6 +537,100 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, return lb_is_elem_const(elem, ft); } +gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef variant_value, Type *variant_type, Type *union_type) { + Type *bt = base_type(union_type); + GB_ASSERT(bt->kind == Type_Union); + GB_ASSERT(lb_type(m, variant_type) == LLVMTypeOf(variant_value)); + + if (bt->Union.variants.count == 0) { + GB_ASSERT(LLVMIsNull(variant_value)); + return variant_value; + } + + LLVMTypeRef llvm_type = lb_type(m, union_type); + LLVMTypeRef llvm_variant_type = lb_type(m, variant_type); + + if (is_type_union_maybe_pointer(bt)) { + GB_ASSERT(lb_sizeof(LLVMTypeOf(variant_value)) == lb_sizeof(llvm_type)); + return LLVMConstBitCast(variant_value, llvm_type); + } + + if (bt->Union.variants.count == 1) { + unsigned long long the_tag = cast(unsigned long long)union_variant_index(union_type, variant_type); + LLVMTypeRef tag_type = lb_type(m, union_tag_type(bt)); + + LLVMValueRef values[3] = {}; + unsigned i = 0; + values[i++] = variant_value; + values[i++] = LLVMConstInt(tag_type, the_tag, false); + + i64 used_size = bt->Union.variant_block_size + lb_sizeof(tag_type); + i64 padding = type_size_of(union_type) - used_size; + i64 align = type_align_of(union_type); + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align); + values[i++] = LLVMConstNull(padding_type); + } + + return LLVMConstNamedStruct(llvm_type, values, i); + } + + LLVMTypeRef block_type = LLVMStructGetTypeAtIndex(llvm_type, 0); + + LLVMTypeRef block_padding = nullptr; + i64 block_padding_size = bt->Union.variant_block_size - type_size_of(variant_type); + if (block_padding_size > 0) { + block_padding = lb_type_padding_filler(m, block_padding_size, type_align_of(variant_type)); + return nullptr; + } + + LLVMTypeRef tag_type = lb_type(m, union_tag_type(bt)); + + i64 used_size = bt->Union.variant_block_size + lb_sizeof(tag_type); + i64 padding = type_size_of(union_type) - used_size; + i64 align = type_align_of(union_type); + LLVMTypeRef padding_type = nullptr; + if (padding > 0) { + padding_type = lb_type_padding_filler(m, padding, align); + } + + + unsigned i = 0; + LLVMValueRef values[3] = {}; + + LLVMValueRef variant_value_wrapped = variant_value; + + if (lb_sizeof(llvm_variant_type) == 0) { + variant_value_wrapped = LLVMConstNull(block_type); + } else if (block_type != llvm_variant_type) { + return nullptr; + } + + values[i++] = variant_value_wrapped; + + if (block_padding_size > 0) { + values[i++] = LLVMConstNull(block_padding); + } + unsigned long long the_tag = cast(unsigned long long)union_variant_index(union_type, variant_type); + values[i++] = LLVMConstInt(tag_type, the_tag, false); + if (padding > 0) { + values[i++] = LLVMConstNull(padding_type); + } + return LLVMConstNamedStruct(llvm_type, values, i); +} + +gb_internal bool lb_try_construct_const_union(lbModule *m, lbValue *value, Type *variant_type, Type *union_type) { + if (lb_is_const(*value)) { + LLVMValueRef res = lb_construct_const_union(m, value->value, variant_type, union_type); + if (res != nullptr) { + *value = {res, union_type}; + return true; + } + } + return false; +} + + gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) { if (cc.allow_local) { cc.is_rodata = false; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index cff91813e..4a1f39c19 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2495,6 +2495,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { Type *vt = dst->Union.variants[0]; if (internal_check_is_assignable_to(src_type, vt)) { value = lb_emit_conv(p, value, vt); + if (lb_is_const(value)) { + LLVMValueRef res = lb_construct_const_union(m, value.value, vt, t); + return {res, t}; + } + lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); @@ -2503,11 +2508,18 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { for (Type *vt : dst->Union.variants) { if (src_type == t_llvm_bool && is_type_boolean(vt)) { value = lb_emit_conv(p, value, vt); + if (lb_try_construct_const_union(m, &value, vt, t)) { + return value; + } + lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); } if (are_types_identical(src_type, vt)) { + if (lb_try_construct_const_union(m, &value, vt, t)) { + return value; + } lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); @@ -2545,6 +2557,9 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { if (valid_count == 1) { Type *vt = dst->Union.variants[first_success_index]; value = lb_emit_conv(p, value, vt); + if (lb_try_construct_const_union(m, &value, vt, t)) { + return value; + } lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 3fa7a076e..fc770102c 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1719,8 +1719,69 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t map_set(&m->func_raw_types, type, new_abi_fn_type); return new_abi_fn_type; +} + + +gb_internal LLVMTypeRef lb_type_internal_union_block_type(lbModule *m, Type *type) { + GB_ASSERT(type->kind == Type_Union); + + if (type->Union.variants.count <= 0) { + return nullptr; + } + if (type->Union.variants.count == 1) { + return lb_type(m, type->Union.variants[0]); + } + + i64 align = type_align_of(type); + i64 size = type_size_of(type); + gb_unused(size); + unsigned block_size = cast(unsigned)type->Union.variant_block_size; + + bool all_pointers = align == build_context.ptr_size; + for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (!is_type_internally_pointer_like(t)) { + all_pointers = false; + } + } + if (all_pointers) { + return lb_type(m, t_rawptr); + } + + { + Type *pt = type->Union.variants[0]; + for (isize i = 1; i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (!are_types_identical(pt, t)) { + goto end_check_for_all_the_same; + } + } + return lb_type(m, pt); + } end_check_for_all_the_same:; + + { + Type *first_different = nullptr; + for (isize i = 0; i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (type_size_of(t) == 0) { + continue; + } + if (first_different == nullptr) { + first_different = t; + } else if (!are_types_identical(first_different, t)) { + goto end_rest_zero_except_one; + } + } + if (first_different != nullptr) { + return lb_type(m, first_different); + } + } end_rest_zero_except_one:; + + return lb_type_padding_filler(m, block_size, align); } + + gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { LLVMContextRef ctx = m->ctx; i64 size = type_size_of(type); // Check size @@ -2233,8 +2294,6 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false); } - unsigned block_size = cast(unsigned)type->Union.variant_block_size; - auto fields = array_make(temporary_allocator(), 0, 3); if (is_type_union_maybe_pointer(type)) { LLVMTypeRef variant = lb_type(m, type->Union.variants[0]); @@ -2252,20 +2311,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { array_add(&fields, padding_type); } } else { - LLVMTypeRef block_type = nullptr; - - bool all_pointers = align == build_context.ptr_size; - for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) { - Type *t = type->Union.variants[i]; - if (!is_type_internally_pointer_like(t)) { - all_pointers = false; - } - } - if (all_pointers) { - block_type = lb_type(m, t_rawptr); - } else { - block_type = lb_type_padding_filler(m, block_size, align); - } + LLVMTypeRef block_type = lb_type_internal_union_block_type(m, type); LLVMTypeRef tag_type = lb_type(m, union_tag_type(type)); array_add(&fields, block_type); -- cgit v1.2.3 From 42b9039a1fd0307f8b46cd1c750e11db653acea1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Sep 2025 09:41:08 +0100 Subject: Check for `nullptr` --- src/llvm_backend_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 4a1f39c19..80cab9722 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2497,7 +2497,9 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { value = lb_emit_conv(p, value, vt); if (lb_is_const(value)) { LLVMValueRef res = lb_construct_const_union(m, value.value, vt, t); - return {res, t}; + if (res != nullptr) { + return {res, t}; + } } lbAddr parent = lb_add_local_generated(p, t, true); -- cgit v1.2.3 From a974c51d573618c9cc4496a32885b7f871c317b2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 28 Sep 2025 19:52:52 +0100 Subject: First step towards constant unions --- src/check_expr.cpp | 2 +- src/llvm_backend.hpp | 2 +- src/llvm_backend_const.cpp | 87 ++++++++++++++++++++++++++++++++-------------- src/llvm_backend_expr.cpp | 22 ++++++++++-- 4 files changed, 81 insertions(+), 32 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fdc3bc181..a825ec7bf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3520,7 +3520,7 @@ gb_internal bool is_type_union_constantable(Type *type) { return false; } } - return false; + return true; } gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) { diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index cee46701f..76ec2fe1f 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -455,7 +455,7 @@ static lbConstContext const LB_CONST_CONTEXT_DEFAULT_NO_LOCAL = {false, false, { gb_internal lbValue lb_const_nil(lbModule *m, Type *type); gb_internal lbValue lb_const_undef(lbModule *m, Type *type); -gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT); +gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT, Type *value_type=nullptr); gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value); gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 3aeba0891..415d6743b 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -787,7 +787,7 @@ gb_internal bool lb_try_construct_const_union(lbModule *m, lbValue *value, Type } -gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) { +gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc, Type *value_type) { if (cc.allow_local) { cc.is_rodata = false; } @@ -838,7 +838,6 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb if (is_type_union(type) && is_type_union_constantable(type)) { Type *bt = base_type(type); GB_ASSERT(bt->kind == Type_Union); - GB_ASSERT(bt->Union.variants.count <= 1); if (bt->Union.variants.count == 0) { return lb_const_nil(m, original_type); } else if (bt->Union.variants.count == 1) { @@ -872,6 +871,37 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb res.type = original_type; return res; } + } else { + GB_ASSERT(value_type != nullptr); + + i64 block_size = bt->Union.variant_block_size; + + lbValue cv = lb_const_value(m, value_type, value, cc, value_type); + Type *variant_type = cv.type; + + LLVMValueRef values[4] = {}; + unsigned value_count = 0; + + values[value_count++] = cv.value; + if (type_size_of(variant_type) != block_size) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, block_size - type_size_of(variant_type), 1); + values[value_count++] = LLVMConstNull(padding_type); + } + + Type *tag_type = union_tag_type(bt); + LLVMTypeRef llvm_tag_type = lb_type(m, tag_type); + i64 tag_index = union_variant_index(bt, variant_type); + values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false); + i64 used_size = block_size + type_size_of(tag_type); + i64 union_size = type_size_of(bt); + i64 padding = union_size - used_size; + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, 1); + values[value_count++] = LLVMConstNull(padding_type); + } + + res.value = LLVMConstStructInContext(m->ctx, values, value_count, true); + return res; } } @@ -909,7 +939,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb array_data = llvm_alloca(p, llvm_type, 16); - LLVMBuildStore(p->builder, backing_array.value, array_data); + { + LLVMValueRef ptr = array_data; + ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(LLVMTypeOf(backing_array.value), 0), ""); + LLVMBuildStore(p->builder, backing_array.value, ptr); + } { LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; @@ -931,7 +965,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb String name = make_string(cast(u8 const *)str, gb_string_length(str)); Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value); - array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str); + array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str); LLVMSetInitializer(array_data, backing_array.value); if (cc.link_section.len > 0) { @@ -942,15 +976,14 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } lbValue g = {}; - g.value = array_data; + g.value = LLVMConstPointerCast(array_data, LLVMPointerType(lb_type(m, t), 0)); g.type = t; lb_add_entity(m, e, g); lb_add_member(m, name, g); { - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef ptr = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2); + LLVMValueRef ptr = g.value; LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); LLVMValueRef values[2] = {ptr, len}; @@ -1272,7 +1305,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { aos_values[value_index++] = val; } @@ -1287,7 +1320,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; aos_values[value_index++] = val; found = true; break; @@ -1340,7 +1373,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - aos_values[i] = lb_const_value(m, elem_type, tav.value, cc).value; + aos_values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = elem_count; i < type->Struct.soa_count; i++) { aos_values[i] = nullptr; @@ -1407,7 +1440,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -1422,7 +1455,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -1437,12 +1470,12 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); return res; - } else if (value.value_compound->tav.type == elem_type) { + } else if (are_types_identical(value.value_compound->tav.type, elem_type)) { // Compound is of array item type; expand its value to all items in array. LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); for (isize i = 0; i < type->Array.count; i++) { - values[i] = lb_const_value(m, elem_type, value, cc).value; + values[i] = lb_const_value(m, elem_type, value, cc, elem_type).value; } res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); @@ -1456,7 +1489,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, cc).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = elem_count; i < type->Array.count; i++) { values[i] = LLVMConstNull(lb_type(m, elem_type)); @@ -1502,7 +1535,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -1517,7 +1550,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -1540,7 +1573,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, cc).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = elem_count; i < type->EnumeratedArray.count; i++) { values[i] = LLVMConstNull(lb_type(m, elem_type)); @@ -1585,7 +1618,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -1600,7 +1633,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -1619,7 +1652,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, cc).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } LLVMTypeRef et = lb_type(m, elem_type); @@ -1668,7 +1701,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i32 index = field_remapping[f->Variable.field_index]; if (elem_type_can_be_constant(f->type)) { if (sel.index.count == 1) { - values[index] = lb_const_value(m, f->type, tav.value, cc).value; + values[index] = lb_const_value(m, f->type, tav.value, cc, tav.type).value; visited[index] = true; } else { if (!visited[index]) { @@ -1714,7 +1747,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } } if (is_constant) { - LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc).value; + LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc, tav.type).value; if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) { values[index] = llvm_const_insert_value(m, values[index], elem_value, idx_list, idx_list_len); } else if (is_local) { @@ -1768,7 +1801,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i32 index = field_remapping[f->Variable.field_index]; if (elem_type_can_be_constant(f->type)) { - values[index] = lb_const_value(m, f->type, val, cc).value; + values[index] = lb_const_value(m, f->type, val, cc, tav.type).value; visited[index] = true; } } @@ -1902,7 +1935,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { i64 offset = matrix_row_major_index_to_offset(type, k); GB_ASSERT(values[offset] == nullptr); @@ -1914,7 +1947,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb i64 index = exact_value_to_i64(index_tav.value); GB_ASSERT(index < max_count); TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; i64 offset = matrix_row_major_index_to_offset(type, index); GB_ASSERT(values[offset] == nullptr); values[offset] = val; @@ -1938,7 +1971,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb GB_ASSERT(tav.mode != Addressing_Invalid); i64 offset = 0; offset = matrix_row_major_index_to_offset(type, i); - values[offset] = lb_const_value(m, elem_type, tav.value, cc).value; + values[offset] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = 0; i < total_count; i++) { if (values[i] == nullptr) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 80cab9722..0e8562194 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3947,6 +3947,20 @@ gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) { return res; } +gb_internal Type *lb_build_expr_original_const_type(Ast *expr) { + expr = unparen_expr(expr); + Type *type = type_of_expr(expr); + if (is_type_union(type)) { + if (expr->kind == Ast_CallExpr) { + if (expr->CallExpr.proc->tav.mode == Addressing_Type) { + Type *res = lb_build_expr_original_const_type(expr->CallExpr.args[0]); + return res; + } + } + } + return type_of_expr(expr); +} + gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { lbModule *m = p->module; @@ -3958,9 +3972,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); + if (tv.value.kind != ExactValue_Invalid) { + Type *original_type = lb_build_expr_original_const_type(expr); // NOTE(bill): Short on constant values - return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL); + return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, original_type); } else if (tv.mode == Addressing_Type) { // NOTE(bill, 2023-01-16): is this correct? I hope so at least return lb_typeid(m, tv.type); @@ -4041,7 +4057,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { TypeAndValue tav = type_and_value_of_expr(expr); GB_ASSERT(tav.mode == Addressing_Constant); - return lb_const_value(p->module, type, tv.value); + return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, tv.type); case_end; case_ast_node(se, SelectorCallExpr, expr); @@ -4322,7 +4338,7 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp GB_ASSERT(e != nullptr); if (e->kind == Entity_Constant) { Type *t = default_type(type_of_expr(expr)); - lbValue v = lb_const_value(p->module, t, e->Constant.value); + lbValue v = lb_const_value(p->module, t, e->Constant.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL, e->type); if (LLVMIsConstant(v.value)) { lbAddr g = lb_add_global_generated_from_procedure(p, t, v); return g; -- cgit v1.2.3 From cbab97fbd74834ef4b06126b8a6787479e177b24 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 28 Sep 2025 22:50:36 +0100 Subject: Use `memcpy` for local constant slice arrays from a global constant --- src/llvm_backend_const.cpp | 202 ++++++------------------------------------- src/llvm_backend_expr.cpp | 18 ---- src/llvm_backend_general.cpp | 5 +- 3 files changed, 30 insertions(+), 195 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 66e2e50aa..dc555a7bd 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -641,161 +641,6 @@ gb_internal Slice lb_construct_const_union_flatten_values(lbModule return {}; } -gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef variant_value, Type *variant_type, Type *union_type) { -#if 1 - return nullptr; -#else - Type *bt = base_type(union_type); - GB_ASSERT(bt->kind == Type_Union); - GB_ASSERT(lb_type(m, variant_type) == LLVMTypeOf(variant_value)); - - LLVMTypeRef llvm_type = lb_type(m, union_type); - - if (LLVMIsNull(variant_value)) { - return LLVMConstNull(llvm_type); - } - - if (bt->Union.variants.count == 0) { - GB_ASSERT(LLVMIsNull(variant_value)); - return variant_value; - } - - i64 block_size = bt->Union.variant_block_size; - i64 variant_size = type_size_of(variant_type); - - LLVMTypeRef llvm_variant_type = lb_type(m, variant_type); - - if (is_type_union_maybe_pointer(bt)) { - GB_ASSERT(lb_sizeof(LLVMTypeOf(variant_value)) == lb_sizeof(llvm_type)); - return LLVMConstBitCast(variant_value, llvm_type); - } - - if (bt->Union.variants.count == 1) { - unsigned long long the_tag = cast(unsigned long long)union_variant_index(union_type, variant_type); - LLVMTypeRef tag_type = lb_type(m, union_tag_type(bt)); - - LLVMValueRef values[3] = {}; - unsigned i = 0; - values[i++] = variant_value; - values[i++] = LLVMConstInt(tag_type, the_tag, false); - - i64 used_size = block_size + lb_sizeof(tag_type); - i64 padding = type_size_of(union_type) - used_size; - i64 align = type_align_of(union_type); - if (padding > 0) { - LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align); - values[i++] = LLVMConstNull(padding_type); - } - - return LLVMConstNamedStruct(llvm_type, values, i); - } else if (true) { - // TODO(bill): ignore this for the time being - return nullptr; - } - - LLVMTypeRef block_type = LLVMStructGetTypeAtIndex(llvm_type, 0); - - LLVMTypeRef tag_type = lb_type(m, union_tag_type(bt)); - - i64 used_size = block_size + lb_sizeof(tag_type); - i64 padding = type_size_of(union_type) - used_size; - i64 align = type_align_of(union_type); - LLVMTypeRef padding_type = nullptr; - if (padding > 0) { - padding_type = lb_type_padding_filler(m, padding, align); - } - - - unsigned i = 0; - LLVMValueRef values[3] = {}; - - LLVMValueRef block_value = variant_value; - - if (block_size == 0) { - block_value = LLVMConstNull(block_type); - } else if (lb_sizeof(llvm_variant_type) == 0) { - block_value = LLVMConstNull(block_type); - } else if (block_type != llvm_variant_type) { - - LLVMTypeKind block_kind = LLVMGetTypeKind(block_type); - LLVMTypeKind variant_kind = LLVMGetTypeKind(llvm_variant_type); - - - if (block_kind == LLVMArrayTypeKind) { - LLVMTypeRef elem = LLVMGetElementType(block_type); - unsigned count = LLVMGetArrayLength(block_type); - - Slice partial_elems = lb_construct_const_union_flatten_values(m, variant_value, variant_type, elem); - if (partial_elems.count == count) { - block_value = LLVMConstArray(elem, partial_elems.data, count); - goto assign_value_wrapped; - } - - Slice full_elems = temporary_slice_make(count); - slice_copy(&full_elems, partial_elems); - for (isize j = partial_elems.count; j < count; j++) { - full_elems[j] = LLVMConstNull(elem); - } - block_value = LLVMConstArray(elem, full_elems.data, count); - goto assign_value_wrapped; - - } else if (block_size != variant_size) { - if (block_kind == LLVMIntegerTypeKind && !is_type_different_to_arch_endianness(variant_type)) { - Slice partial_elems = lb_construct_const_union_flatten_values(m, variant_value, variant_type, block_type); - if (partial_elems.count == 1) { - block_value = partial_elems[0]; - goto assign_value_wrapped; - } - } - - return nullptr; - } - if (block_kind == LLVMIntegerTypeKind) { - GB_ASSERT(block_size == variant_size); - - switch (variant_kind) { - case LLVMHalfTypeKind: - case LLVMFloatTypeKind: - case LLVMDoubleTypeKind: - block_value = LLVMConstBitCast(block_value, block_type); - goto assign_value_wrapped; - case LLVMPointerTypeKind: - block_value = LLVMConstPtrToInt(block_value, block_type); - goto assign_value_wrapped; - } - } - - return nullptr; - } else { - // TODO(bill): ignore this for the time being - return nullptr; - } - -assign_value_wrapped:; - values[i++] = block_value; - - unsigned long long the_tag = cast(unsigned long long)union_variant_index(union_type, variant_type); - values[i++] = LLVMConstInt(tag_type, the_tag, false); - if (padding > 0) { - values[i++] = LLVMConstNull(padding_type); - } - return LLVMConstNamedStruct(llvm_type, values, i); -#endif -} - -gb_internal bool lb_try_construct_const_union(lbModule *m, lbValue *value, Type *variant_type, Type *union_type) { - if (lb_is_const(*value)) { - LLVMValueRef res = lb_construct_const_union(m, value->value, variant_type, union_type); - if (res != nullptr) { - *value = {res, union_type}; - return true; - } - // gb_printf_err("%s -> %s\n", LLVMPrintValueToString(value->value), LLVMPrintTypeToString(lb_type(m, union_type))); - } - return false; -} - - gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc, Type *value_type) { if (cc.allow_local) { cc.is_rodata = false; @@ -888,6 +733,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb Type *tag_type = union_tag_type(bt); LLVMTypeRef llvm_tag_type = lb_type(m, tag_type); i64 tag_index = union_variant_index(bt, variant_type); + GB_ASSERT(tag_index >= 0); values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false); i64 used_size = block_size + type_size_of(tag_type); i64 union_size = type_size_of(bt); @@ -946,27 +792,42 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb count = gb_max(cast(isize)cl->max_count, count); Type *elem = base_type(type)->Slice.elem; Type *t = alloc_type_array(elem, count); - lbValue backing_array = lb_const_value(m, t, value, cc); + lbValue backing_array = lb_const_value(m, t, value, cc, nullptr); LLVMValueRef array_data = nullptr; + u32 id = m->global_array_index.fetch_add(1); + gbString str = gb_string_make(temporary_allocator(), "csba$"); + str = gb_string_appendc(str, m->module_name); + str = gb_string_append_fmt(str, "$%x", id); + + String name = make_string(cast(u8 const *)str, gb_string_length(str)); + + Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value); + array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str); + LLVMSetInitializer(array_data, backing_array.value); + + + if (is_local) { + LLVMSetGlobalConstant(array_data, true); + // NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs // its backing data on the stack lbProcedure *p = m->curr_procedure; - LLVMTypeRef llvm_type = lb_type(m, t); - array_data = llvm_alloca(p, llvm_type, 16); - - { - LLVMValueRef ptr = array_data; - ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(LLVMTypeOf(backing_array.value), 0), ""); - LLVMBuildStore(p->builder, backing_array.value, ptr); - } + // NOTE(bill, 2025-09-28): make the array data global BUT memcpy it + // to make a local copy + LLVMTypeRef llvm_type = lb_type(m, t); + LLVMValueRef local_copy = llvm_alloca(p, llvm_type, 16); + LLVMBuildMemCpy(p->builder, + local_copy, 16, + array_data, 1, + LLVMConstInt(lb_type(m, t_int), type_size_of(t), false)); { LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, array_data, indices, 2, ""); + LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, local_copy, indices, 2, ""); LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); lbAddr slice = lb_add_local_generated(p, original_type, false); @@ -976,17 +837,6 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb return lb_addr_load(p, slice); } } else { - u32 id = m->global_array_index.fetch_add(1); - gbString str = gb_string_make(temporary_allocator(), "csba$"); - str = gb_string_appendc(str, m->module_name); - str = gb_string_append_fmt(str, "$%x", id); - - String name = make_string(cast(u8 const *)str, gb_string_length(str)); - - Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value); - array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str); - LLVMSetInitializer(array_data, backing_array.value); - if (cc.link_section.len > 0) { LLVMSetSection(array_data, alloc_cstring(permanent_allocator(), cc.link_section)); } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0e8562194..187c34595 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2495,13 +2495,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { Type *vt = dst->Union.variants[0]; if (internal_check_is_assignable_to(src_type, vt)) { value = lb_emit_conv(p, value, vt); - if (lb_is_const(value)) { - LLVMValueRef res = lb_construct_const_union(m, value.value, vt, t); - if (res != nullptr) { - return {res, t}; - } - } - lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); @@ -2509,19 +2502,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } for (Type *vt : dst->Union.variants) { if (src_type == t_llvm_bool && is_type_boolean(vt)) { - value = lb_emit_conv(p, value, vt); - if (lb_try_construct_const_union(m, &value, vt, t)) { - return value; - } - lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); } if (are_types_identical(src_type, vt)) { - if (lb_try_construct_const_union(m, &value, vt, t)) { - return value; - } lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); @@ -2559,9 +2544,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { if (valid_count == 1) { Type *vt = dst->Union.variants[first_success_index]; value = lb_emit_conv(p, value, vt); - if (lb_try_construct_const_union(m, &value, vt, t)) { - return value; - } lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b181788b9..123af51f5 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1493,8 +1493,11 @@ gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { unsigned element_count = LLVMCountStructElementTypes(uvt); GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); + LLVMValueRef ptr = u.value; + ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(uvt, 0), ""); + lbValue tag_ptr = {}; - tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, ""); + tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 1, ""); tag_ptr.type = alloc_type_pointer(tag_type); return tag_ptr; } -- cgit v1.2.3 From 4db4841413095645e2319afcafc1db7276259f9d Mon Sep 17 00:00:00 2001 From: laytan Date: Sat, 29 Nov 2025 12:14:06 +0100 Subject: fix matrix transpose with different result type Fixes #5623 --- src/llvm_backend_expr.cpp | 4 ++-- src/llvm_backend_proc.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 187c34595..40b749e1b 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -634,7 +634,7 @@ gb_internal LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) } -gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) { +gb_internal lbValue lb_emit_matrix_transpose(lbProcedure *p, lbValue m, Type *type) { if (is_type_array(m.type)) { i32 rank = type_math_rank(m.type); if (rank == 2) { @@ -664,7 +664,7 @@ gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *typ Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - if (lb_is_matrix_simdable(mt)) { + if (lb_is_matrix_simdable(mt) && lb_is_matrix_simdable(type)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; unsigned column_count = cast(unsigned)mt->Matrix.column_count; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 890556a61..10e10564e 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2681,7 +2681,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_transpose: { lbValue m = lb_build_expr(p, ce->args[0]); - return lb_emit_matrix_tranpose(p, m, tv.type); + return lb_emit_matrix_transpose(p, m, tv.type); } case BuiltinProc_outer_product: -- cgit v1.2.3 From 679d306d0ff0ff9ac451a23ee50d7e44807d5aa6 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 29 Nov 2025 20:06:43 +0100 Subject: panic on transpose with result type in diff layout Partially reverts 4db4841, it should behave the same as cast (which does an implicit transpose). --- src/llvm_backend_expr.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 40b749e1b..d5658b9d5 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -664,6 +664,11 @@ gb_internal lbValue lb_emit_matrix_transpose(lbProcedure *p, lbValue m, Type *ty Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); + Type *rt = base_type(type); + if (rt->kind == Type_Matrix && rt->Matrix.is_row_major != mt->Matrix.is_row_major) { + GB_PANIC("TODO: transpose with changing layout"); + } + if (lb_is_matrix_simdable(mt) && lb_is_matrix_simdable(type)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; -- cgit v1.2.3 From 0f0c40b96dc5d5b6e585c935186b342180747d06 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Dec 2025 13:11:32 +0000 Subject: Fix `-integer-division-by-zero` modes and document `all-bits` --- src/llvm_backend_expr.cpp | 19 ++++++++++--------- src/llvm_backend_proc.cpp | 2 +- src/main.cpp | 6 ++++-- 3 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index d5658b9d5..9b8df5a37 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1161,8 +1161,7 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L case IntegerDivisionByZero_Zero: return zero; case IntegerDivisionByZero_AllBits: - // return all_bits; - break; + return all_bits; } } else { if (!is_signed && lb_sizeof(type) <= 8) { @@ -1198,7 +1197,6 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L lb_start_block(p, edge_case_block); - switch (behaviour) { case IntegerDivisionByZero_Trap: lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); @@ -1214,17 +1212,17 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L incoming_values[1] = all_bits; break; } + LLVMValueRef res = nullptr; lb_emit_jump(p, done_block); lb_start_block(p, done_block); - LLVMValueRef res = incoming_values[0]; switch (behaviour) { case IntegerDivisionByZero_Trap: - case IntegerDivisionByZero_Self: res = incoming_values[0]; break; + case IntegerDivisionByZero_Self: case IntegerDivisionByZero_Zero: case IntegerDivisionByZero_AllBits: res = LLVMBuildPhi(p->builder, type, ""); @@ -1233,6 +1231,9 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L incoming_blocks[0] = p->curr_block->preds[0]->block; incoming_blocks[1] = p->curr_block->preds[1]->block; + GB_ASSERT(incoming_blocks[0] == safe_block->block); + GB_ASSERT(incoming_blocks[1] == edge_case_block->block); + LLVMAddIncoming(res, incoming_values, incoming_blocks, 2); break; } @@ -1240,7 +1241,7 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L return res; } -gb_internal LLVMValueRef lb_integer_division_intrinsics(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, LLVMValueRef scale, Type *platform_type, char const *name) { +gb_internal LLVMValueRef lb_integer_division_fixed_point_intrinsics(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, LLVMValueRef scale, Type *platform_type, char const *name) { LLVMTypeRef type = LLVMTypeOf(rhs); GB_ASSERT(LLVMTypeOf(lhs) == type); @@ -1310,13 +1311,13 @@ gb_internal LLVMValueRef lb_integer_division_intrinsics(lbProcedure *p, LLVMValu lb_emit_jump(p, done_block); lb_start_block(p, done_block); - LLVMValueRef res = incoming_values[0]; + LLVMValueRef res = nullptr; switch (behaviour) { case IntegerDivisionByZero_Trap: - case IntegerDivisionByZero_Self: res = incoming_values[0]; break; + case IntegerDivisionByZero_Self: case IntegerDivisionByZero_Zero: case IntegerDivisionByZero_AllBits: res = LLVMBuildPhi(p->builder, type, ""); @@ -1423,9 +1424,9 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV switch (behaviour) { case IntegerDivisionByZero_Trap: - case IntegerDivisionByZero_Self: res = incoming_values[0]; break; + case IntegerDivisionByZero_Self: case IntegerDivisionByZero_Zero: case IntegerDivisionByZero_AllBits: res = LLVMBuildPhi(p->builder, type, ""); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 10e10564e..27167aefd 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3305,7 +3305,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu if (id == BuiltinProc_fixed_point_div || id == BuiltinProc_fixed_point_div_sat) { - res.value = lb_integer_division_intrinsics(p, x.value, y.value, scale.value, platform_type, name); + res.value = lb_integer_division_fixed_point_intrinsics(p, x.value, y.value, scale.value, platform_type, name); } else { LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; diff --git a/src/main.cpp b/src/main.cpp index 544cd54bb..ca05bb177 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1570,8 +1570,10 @@ gb_internal bool parse_build_flags(Array args) { build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Zero; } else if (str_eq_ignore_case(value.value_string, "self")) { build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Self; - }else { - gb_printf_err("-integer-division-by-zero options are 'trap', 'zero', and 'self'.\n"); + } else if (str_eq_ignore_case(value.value_string, "all-bits")) { + build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_AllBits; + } else { + gb_printf_err("-integer-division-by-zero options are 'trap', 'zero', 'self', and 'all-bits'.\n"); bad_flags = true; } break; -- cgit v1.2.3 From 29019d7138629af4a66c3e8faf064d9d29b5ee62 Mon Sep 17 00:00:00 2001 From: miere43 Date: Wed, 3 Dec 2025 21:16:18 +0300 Subject: Fix duplicate code emission in type assertions. --- src/llvm_backend_expr.cpp | 4 ++-- tests/issues/run.bat | 1 + tests/issues/run.sh | 1 + tests/issues/test_issue_5699.odin | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 tests/issues/test_issue_5699.odin (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 9b8df5a37..dba61df44 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -5785,11 +5785,11 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { if (is_type_union(t)) { Type *type = type_of_expr(expr); lbAddr v = lb_add_local_generated(p, type, false); - lb_addr_store(p, v, lb_emit_union_cast(p, lb_build_expr(p, ta->expr), type, pos)); + lb_addr_store(p, v, lb_emit_union_cast(p, e, type, pos)); return v; } else if (is_type_any(t)) { Type *type = type_of_expr(expr); - return lb_emit_any_cast_addr(p, lb_build_expr(p, ta->expr), type, pos); + return lb_emit_any_cast_addr(p, e, type, pos); } else { GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); } diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 4a1072e12..eeaf8e002 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -25,6 +25,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style ..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5097-2.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5265.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_5699.odin %COMMON% || exit /b @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 03d84425a..86e6ce17f 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -32,6 +32,7 @@ $ODIN build ../test_issue_5043.odin $COMMON $ODIN build ../test_issue_5097.odin $COMMON $ODIN build ../test_issue_5097-2.odin $COMMON $ODIN build ../test_issue_5265.odin $COMMON +$ODIN test ../test_issue_5699.odin $COMMON set +x diff --git a/tests/issues/test_issue_5699.odin b/tests/issues/test_issue_5699.odin new file mode 100644 index 000000000..cc91799e1 --- /dev/null +++ b/tests/issues/test_issue_5699.odin @@ -0,0 +1,36 @@ +// Tests issue #5699 https://github.com/odin-lang/Odin/issues/5699 +package test_issues + +import "core:testing" + +Issue5699_Value :: struct { + value: i32, +} + +Issue5699_Result :: union { + Issue5699_Value, +} + +test_issue_5699_increment_union :: proc(counter: ^i32) -> Issue5699_Result { + counter^ += 1 + return Issue5699_Value{0} +} + +@test +test_issue_5699_union :: proc(t: ^testing.T) { + counter: i32 = 0 + _ = test_issue_5699_increment_union(&counter).(Issue5699_Value).value + testing.expectf(t, counter == 1, "\n\texpected: 1\n\tgot: %d", counter) +} + +test_issue_5699_increment_any :: proc(counter: ^i32) -> any { + counter^ += 1 + return Issue5699_Value{0} +} + +@test +test_issue_5699_any :: proc(t: ^testing.T) { + counter: i32 = 0 + _ = test_issue_5699_increment_any(&counter).(Issue5699_Value).value + testing.expectf(t, counter == 1, "\n\texpected: 1\n\tgot: %d", counter) +} -- cgit v1.2.3