From 6338e0a8a3db948624817c99c431e5889afc636a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 19 Sep 2025 11:56:44 +0100 Subject: Allow unions with one variant to be constant --- src/llvm_backend_const.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index e64be49f2..98e50dd78 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -168,7 +168,7 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue return llvm_const_named_struct_internal(struct_type, values, value_count_); } Type *bt = base_type(t); - GB_ASSERT(bt->kind == Type_Struct); + GB_ASSERT(bt->kind == Type_Struct || bt->kind == Type_Union); GB_ASSERT(value_count_ == bt->Struct.fields.count); @@ -585,6 +585,47 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb bool is_local = cc.allow_local && m->curr_procedure != nullptr; + 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) { + Type *t = bt->Union.variants[0]; + lbValue cv = lb_const_value(m, t, value, cc); + GB_ASSERT(LLVMIsConstant(cv.value)); + + LLVMTypeRef llvm_type = lb_type(m, original_type); + + if (is_type_union_maybe_pointer(type)) { + LLVMValueRef values[1] = {cv.value}; + res.value = llvm_const_named_struct_internal(llvm_type, values, 1); + res.type = original_type; + return res; + } else { + + unsigned tag_value = 1; + if (bt->Union.kind == UnionType_no_nil) { + tag_value = 0; + } + LLVMValueRef tag = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false); + LLVMValueRef padding = nullptr; + LLVMValueRef values[3] = {cv.value, tag, padding}; + + isize value_count = 2; + if (LLVMCountStructElementTypes(llvm_type) > 2) { + value_count = 3; + padding = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2)); + } + res.value = llvm_const_named_struct_internal(llvm_type, values, value_count); + res.type = original_type; + return res; + } + } + + } + // GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type)); if (is_type_slice(type)) { -- 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_const.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 bad495519b604081e34e69bbafd33c81f4d3fc1e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Sep 2025 10:08:25 +0100 Subject: Improve const union attemps --- src/llvm_backend_const.cpp | 26 +++++++++++++++++++++++--- src/llvm_backend_general.cpp | 22 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 781cc52b8..9069f3bdf 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -547,6 +547,9 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari return variant_value; } + i64 block_size = bt->Union.variant_block_size; + i64 variant_size = type_size_of(variant_type); + LLVMTypeRef llvm_type = lb_type(m, union_type); LLVMTypeRef llvm_variant_type = lb_type(m, variant_type); @@ -564,7 +567,7 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari 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 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) { @@ -578,7 +581,7 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari 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); + i64 block_padding_size = block_size - variant_size; if (block_padding_size > 0) { block_padding = lb_type_padding_filler(m, block_padding_size, type_align_of(variant_type)); return nullptr; @@ -586,7 +589,7 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari LLVMTypeRef tag_type = lb_type(m, union_tag_type(bt)); - i64 used_size = bt->Union.variant_block_size + lb_sizeof(tag_type); + 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; @@ -603,9 +606,26 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari if (lb_sizeof(llvm_variant_type) == 0) { variant_value_wrapped = LLVMConstNull(block_type); } else if (block_type != llvm_variant_type) { + if (block_size != variant_size) { + return nullptr; + } + if (LLVMGetTypeKind(block_type) == LLVMIntegerTypeKind) { + switch (LLVMGetTypeKind(llvm_variant_type)) { + case LLVMHalfTypeKind: + case LLVMFloatTypeKind: + case LLVMDoubleTypeKind: + variant_value_wrapped = LLVMConstBitCast(variant_value_wrapped, block_type); + goto assign_value_wrapped; + case LLVMPointerTypeKind: + variant_value_wrapped = LLVMConstPtrToInt(variant_value_wrapped, block_type); + goto assign_value_wrapped; + } + } + return nullptr; } +assign_value_wrapped:; values[i++] = variant_value_wrapped; if (block_padding_size > 0) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index fc770102c..4c60d9f4c 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1778,6 +1778,28 @@ gb_internal LLVMTypeRef lb_type_internal_union_block_type(lbModule *m, Type *typ } } end_rest_zero_except_one:; + // { + // LLVMTypeRef 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 = lb_type(m, base_type(t)); + // } else { + // LLVMTypeRef llvm_t = lb_type(m, base_type(t)); + // if (llvm_t != first_different) { + // goto end_rest_zero_except_one_llvm_like; + // } + // } + // } + // if (first_different != nullptr) { + // return first_different; + // } + // } end_rest_zero_except_one_llvm_like:; + + return lb_type_padding_filler(m, block_size, align); } -- cgit v1.2.3 From ad85ec765bcf3b3e501f445ab4e35169bc7576d7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Sep 2025 10:21:38 +0100 Subject: More const union improvements --- src/llvm_backend_const.cpp | 71 ++++++++++++++++++++++++++++++++++---------- src/llvm_backend_general.cpp | 5 ++-- 2 files changed, 58 insertions(+), 18 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 9069f3bdf..219700ffd 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -542,6 +542,12 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari 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; @@ -550,7 +556,6 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari i64 block_size = bt->Union.variant_block_size; i64 variant_size = type_size_of(variant_type); - LLVMTypeRef llvm_type = lb_type(m, union_type); LLVMTypeRef llvm_variant_type = lb_type(m, variant_type); if (is_type_union_maybe_pointer(bt)) { @@ -580,13 +585,6 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari LLVMTypeRef block_type = LLVMStructGetTypeAtIndex(llvm_type, 0); - LLVMTypeRef block_padding = nullptr; - i64 block_padding_size = block_size - variant_size; - 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 = block_size + lb_sizeof(tag_type); @@ -601,12 +599,55 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari unsigned i = 0; LLVMValueRef values[3] = {}; - LLVMValueRef variant_value_wrapped = variant_value; + LLVMValueRef block_value = variant_value; if (lb_sizeof(llvm_variant_type) == 0) { - variant_value_wrapped = LLVMConstNull(block_type); + block_value = LLVMConstNull(block_type); } else if (block_type != llvm_variant_type) { if (block_size != variant_size) { + + if (LLVMGetTypeKind(block_type) == LLVMArrayTypeKind && + LLVMGetTypeKind(llvm_variant_type) == LLVMIntegerTypeKind) { + LLVMTypeRef elem = LLVMGetElementType(block_type); + unsigned count = LLVMGetArrayLength(block_type); + if (elem == llvm_variant_type) { + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = variant_value; + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + + goto assign_value_wrapped; + } else if (!is_type_different_to_arch_endianness(variant_type)) { + i64 elem_size = lb_sizeof(elem); + i64 variant_size = lb_sizeof(llvm_variant_type); + if (elem_size > variant_size) { + u64 val = LLVMConstIntGetZExtValue(variant_value); + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + + goto assign_value_wrapped; + } + } + } else if (LLVMGetTypeKind(block_type) == LLVMIntegerTypeKind && + LLVMGetTypeKind(llvm_variant_type) == LLVMIntegerTypeKind) { + if (!is_type_different_to_arch_endianness(variant_type)) { + i64 variant_size = lb_sizeof(llvm_variant_type); + if (block_size > variant_size) { + u64 val = LLVMConstIntGetZExtValue(variant_value); + block_value = LLVMConstInt(block_type, val, false); + + goto assign_value_wrapped; + } + } + } + return nullptr; } if (LLVMGetTypeKind(block_type) == LLVMIntegerTypeKind) { @@ -614,10 +655,10 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari case LLVMHalfTypeKind: case LLVMFloatTypeKind: case LLVMDoubleTypeKind: - variant_value_wrapped = LLVMConstBitCast(variant_value_wrapped, block_type); + block_value = LLVMConstBitCast(block_value, block_type); goto assign_value_wrapped; case LLVMPointerTypeKind: - variant_value_wrapped = LLVMConstPtrToInt(variant_value_wrapped, block_type); + block_value = LLVMConstPtrToInt(block_value, block_type); goto assign_value_wrapped; } } @@ -626,11 +667,8 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari } assign_value_wrapped:; - values[i++] = variant_value_wrapped; + values[i++] = block_value; - 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) { @@ -646,6 +684,7 @@ gb_internal bool lb_try_construct_const_union(lbModule *m, lbValue *value, Type *value = {res, union_type}; return true; } + // gb_printf_err("%s -> %s\n", LLVMPrintValueToString(value->value), LLVMPrintTypeToString(lb_type(m, union_type))); } return false; } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 4c60d9f4c..6e513a075 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1733,10 +1733,11 @@ gb_internal LLVMTypeRef lb_type_internal_union_block_type(lbModule *m, Type *typ } 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; + if (block_size == 0) { + return lb_type_padding_filler(m, block_size, align); + } bool all_pointers = align == build_context.ptr_size; for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) { -- cgit v1.2.3 From 43e0d6966ec4943750684c851bd6ca2ec6c0b3bb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Sep 2025 14:07:09 +0100 Subject: More improves for const union stuff! --- src/llvm_backend_const.cpp | 218 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 193 insertions(+), 25 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 219700ffd..39a223027 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -537,6 +537,84 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, return lb_is_elem_const(elem, ft); } +gb_internal Slice lb_construct_const_union_flatten_values(lbModule *m, LLVMValueRef variant_value, Type *variant_type, LLVMTypeRef elem) { + LLVMTypeRef llvm_variant_type = lb_type(m, variant_type); + LLVMTypeKind variant_kind = LLVMGetTypeKind(llvm_variant_type); + + if (are_types_identical(base_type(variant_type), t_string)) { + LLVMValueRef *elems = temporary_alloc_array(2); + elems[0] = llvm_const_extract_value(m, variant_value, 0); + elems[0] = LLVMConstPtrToInt(elems[0], elem); + + elems[1] = llvm_const_extract_value(m, variant_value, 1); + + return {elems, 2}; + } + + if (is_type_struct(variant_type)) { + // Type *st = base_type(variant_type); + // if (st->Struct.fields.count == 1) { + // return lb_construct_const_union_flatten_values(m, llvm_const_extract_value(m, variant_value, 0), st->Struct.fields[0]->type, elem); + // } + } else if (variant_kind == LLVMIntegerTypeKind) { + if (elem == llvm_variant_type) { + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = variant_value; + return {elems, 1}; + } else if (!is_type_different_to_arch_endianness(variant_type)) { + i64 elem_size = lb_sizeof(elem); + i64 variant_size = lb_sizeof(llvm_variant_type); + if (elem_size > variant_size) { + u64 val = LLVMConstIntGetZExtValue(variant_value); + + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = LLVMConstInt(elem, val, false); + return {elems, 1}; + } + } + } else if (!is_type_different_to_arch_endianness(variant_type)) { + switch (variant_kind) { + case LLVMHalfTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + u16 val = f32_to_f16(cast(f32)res); + + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = LLVMConstInt(elem, val, false); + return {elems, 1}; + } + break; + case LLVMFloatTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f32 f; u32 i; } val = {}; + val.f = cast(f32)res; + + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = LLVMConstInt(elem, val.i, false); + return {elems, 1}; + } + break; + case LLVMDoubleTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f64 f; u64 i; } val = {}; + val.f = res; + + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = LLVMConstInt(elem, val.i, false); + return {elems, 1}; + } + break; + } + } + + return {}; +} + 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); @@ -601,43 +679,98 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari LLVMValueRef block_value = variant_value; - if (lb_sizeof(llvm_variant_type) == 0) { + 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) { - if (block_size != variant_size) { + LLVMTypeKind block_kind = LLVMGetTypeKind(block_type); + LLVMTypeKind variant_kind = LLVMGetTypeKind(llvm_variant_type); - if (LLVMGetTypeKind(block_type) == LLVMArrayTypeKind && - LLVMGetTypeKind(llvm_variant_type) == LLVMIntegerTypeKind) { + if (block_size != variant_size) { + if (block_kind == LLVMArrayTypeKind) { LLVMTypeRef elem = LLVMGetElementType(block_type); unsigned count = LLVMGetArrayLength(block_type); - if (elem == llvm_variant_type) { - LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = variant_value; - for (unsigned j = 1; j < count; j++) { - elems[j] = LLVMConstNull(elem); - } - block_value = LLVMConstArray(elem, elems, count); - - goto assign_value_wrapped; - } else if (!is_type_different_to_arch_endianness(variant_type)) { - i64 elem_size = lb_sizeof(elem); - i64 variant_size = lb_sizeof(llvm_variant_type); - if (elem_size > variant_size) { - u64 val = LLVMConstIntGetZExtValue(variant_value); + if (variant_kind == LLVMIntegerTypeKind) { + if (elem == llvm_variant_type) { LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = LLVMConstInt(elem, val, false); + elems[0] = variant_value; for (unsigned j = 1; j < count; j++) { elems[j] = LLVMConstNull(elem); } block_value = LLVMConstArray(elem, elems, count); - goto assign_value_wrapped; + } else if (!is_type_different_to_arch_endianness(variant_type)) { + i64 elem_size = lb_sizeof(elem); + i64 variant_size = lb_sizeof(llvm_variant_type); + if (elem_size > variant_size) { + u64 val = LLVMConstIntGetZExtValue(variant_value); + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + goto assign_value_wrapped; + } + } + } else if (!is_type_different_to_arch_endianness(variant_type)) { + switch (variant_kind) { + case LLVMHalfTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + u16 val = f32_to_f16(cast(f32)res); + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + goto assign_value_wrapped; + } + break; + case LLVMFloatTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f32 f; u32 i; } val = {}; + val.f = cast(f32)res; + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val.i, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + goto assign_value_wrapped; + } + break; + case LLVMDoubleTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f64 f; u64 i; } val = {}; + val.f = res; + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val.i, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + goto assign_value_wrapped; + } + break; } } - } else if (LLVMGetTypeKind(block_type) == LLVMIntegerTypeKind && - LLVMGetTypeKind(llvm_variant_type) == LLVMIntegerTypeKind) { - if (!is_type_different_to_arch_endianness(variant_type)) { + + + } else if (block_kind == LLVMIntegerTypeKind && !is_type_different_to_arch_endianness(variant_type)) { + if (variant_kind == LLVMIntegerTypeKind) { i64 variant_size = lb_sizeof(llvm_variant_type); if (block_size > variant_size) { u64 val = LLVMConstIntGetZExtValue(variant_value); @@ -645,13 +778,48 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari goto assign_value_wrapped; } + } else { + switch (variant_kind) { + case LLVMHalfTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + u16 val = f32_to_f16(cast(f32)res); + + block_value = LLVMConstInt(block_type, val, false); + goto assign_value_wrapped; + } + break; + case LLVMFloatTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f32 f; u32 i; } val = {}; + val.f = cast(f32)res; + + block_value = LLVMConstInt(block_type, val.i, false); + goto assign_value_wrapped; + } + break; + case LLVMDoubleTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f64 f; u64 i; } val = {}; + val.f = res; + + block_value = LLVMConstInt(block_type, val.i, false); + goto assign_value_wrapped; + } + break; + } } } return nullptr; } - if (LLVMGetTypeKind(block_type) == LLVMIntegerTypeKind) { - switch (LLVMGetTypeKind(llvm_variant_type)) { + if (block_kind == LLVMIntegerTypeKind) { + switch (variant_kind) { case LLVMHalfTypeKind: case LLVMFloatTypeKind: case LLVMDoubleTypeKind: -- cgit v1.2.3 From 5d3092bf2d00a46311a5f785658f04c823a9f3fa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Sep 2025 14:27:44 +0100 Subject: Again, better const union stuff --- src/llvm_abi.cpp | 34 ++++---- src/llvm_backend_const.cpp | 192 +++++++++++++-------------------------------- 2 files changed, 72 insertions(+), 154 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 8dbb8fa76..9f2faaa08 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -522,6 +522,23 @@ namespace lbAbiAmd64Win64 { } }; + +gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) { + if (!lb_is_type_kind(type, LLVMStructTypeKind)) { + return false; + } + if (LLVMCountStructElementTypes(type) != 2) { + return false; + } + LLVMTypeRef fields[2] = {}; + LLVMGetStructElementTypes(type, fields); + if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) { + return false; + } + return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8; + +} + // NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything namespace lbAbiAmd64SysV { enum RegClass { @@ -652,23 +669,6 @@ namespace lbAbiAmd64SysV { return false; } - gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) { - if (!lb_is_type_kind(type, LLVMStructTypeKind)) { - return false; - } - if (LLVMCountStructElementTypes(type) != 2) { - return false; - } - LLVMTypeRef fields[2] = {}; - LLVMGetStructElementTypes(type, fields); - if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) { - return false; - } - return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8; - - } - - gb_internal bool is_aggregate(LLVMTypeRef type) { LLVMTypeKind kind = LLVMGetTypeKind(type); switch (kind) { diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 39a223027..edcc241dc 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -540,22 +540,38 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, gb_internal Slice lb_construct_const_union_flatten_values(lbModule *m, LLVMValueRef variant_value, Type *variant_type, LLVMTypeRef elem) { LLVMTypeRef llvm_variant_type = lb_type(m, variant_type); LLVMTypeKind variant_kind = LLVMGetTypeKind(llvm_variant_type); + LLVMTypeKind elem_kind = LLVMGetTypeKind(elem); - if (are_types_identical(base_type(variant_type), t_string)) { - LLVMValueRef *elems = temporary_alloc_array(2); - elems[0] = llvm_const_extract_value(m, variant_value, 0); - elems[0] = LLVMConstPtrToInt(elems[0], elem); - - elems[1] = llvm_const_extract_value(m, variant_value, 1); + if (is_type_struct(variant_type)) { + Type *st = base_type(variant_type); + GB_ASSERT(st->kind == Type_Struct); + if (st->Struct.fields.count == 1) { + LLVMValueRef f = llvm_const_extract_value(m, variant_value, 0); + return lb_construct_const_union_flatten_values(m, f, st->Struct.fields[0]->type, elem); + } + } else if (is_llvm_type_slice_like(llvm_variant_type)) { + if (lb_sizeof(elem) == build_context.ptr_size) { + LLVMValueRef *elems = temporary_alloc_array(2); + elems[0] = llvm_const_extract_value(m, variant_value, 0); + elems[0] = LLVMConstPtrToInt(elems[0], elem); - return {elems, 2}; - } + elems[1] = llvm_const_extract_value(m, variant_value, 1); - if (is_type_struct(variant_type)) { - // Type *st = base_type(variant_type); - // if (st->Struct.fields.count == 1) { - // return lb_construct_const_union_flatten_values(m, llvm_const_extract_value(m, variant_value, 0), st->Struct.fields[0]->type, elem); - // } + return {elems, 2}; + } + } else if (is_type_array_like(variant_type)) { + Type *array_elem = base_array_type(variant_type); + isize array_count = get_array_type_count(variant_type); + Slice array = temporary_slice_make(array_count); + for (isize i = 0; i < array_count; i++) { + LLVMValueRef v = llvm_const_extract_value(m, variant_value, 0); + auto res = lb_construct_const_union_flatten_values(m, v, array_elem, elem); + if (res.count != 1) { + return {}; + } + array[i] = res[0]; + } + return array; } else if (variant_kind == LLVMIntegerTypeKind) { if (elem == llvm_variant_type) { LLVMValueRef *elems = temporary_alloc_array(1); @@ -572,7 +588,8 @@ gb_internal Slice lb_construct_const_union_flatten_values(lbModule return {elems, 1}; } } - } else if (!is_type_different_to_arch_endianness(variant_type)) { + } else if (!is_type_different_to_arch_endianness(variant_type) && + elem_kind == LLVMIntegerTypeKind) { switch (variant_kind) { case LLVMHalfTypeKind: { @@ -687,138 +704,39 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari LLVMTypeKind block_kind = LLVMGetTypeKind(block_type); LLVMTypeKind variant_kind = LLVMGetTypeKind(llvm_variant_type); - if (block_size != variant_size) { - if (block_kind == LLVMArrayTypeKind) { - LLVMTypeRef elem = LLVMGetElementType(block_type); - unsigned count = LLVMGetArrayLength(block_type); - - if (variant_kind == LLVMIntegerTypeKind) { - if (elem == llvm_variant_type) { - LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = variant_value; - for (unsigned j = 1; j < count; j++) { - elems[j] = LLVMConstNull(elem); - } - block_value = LLVMConstArray(elem, elems, count); - goto assign_value_wrapped; - } else if (!is_type_different_to_arch_endianness(variant_type)) { - i64 elem_size = lb_sizeof(elem); - i64 variant_size = lb_sizeof(llvm_variant_type); - if (elem_size > variant_size) { - u64 val = LLVMConstIntGetZExtValue(variant_value); - - LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = LLVMConstInt(elem, val, false); - for (unsigned j = 1; j < count; j++) { - elems[j] = LLVMConstNull(elem); - } - block_value = LLVMConstArray(elem, elems, count); - goto assign_value_wrapped; - } - } - } else if (!is_type_different_to_arch_endianness(variant_type)) { - switch (variant_kind) { - case LLVMHalfTypeKind: - { - LLVMBool loses = false; - f64 res = LLVMConstRealGetDouble(variant_value, &loses); - u16 val = f32_to_f16(cast(f32)res); - - LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = LLVMConstInt(elem, val, false); - for (unsigned j = 1; j < count; j++) { - elems[j] = LLVMConstNull(elem); - } - block_value = LLVMConstArray(elem, elems, count); - goto assign_value_wrapped; - } - break; - case LLVMFloatTypeKind: - { - LLVMBool loses = false; - f64 res = LLVMConstRealGetDouble(variant_value, &loses); - union { f32 f; u32 i; } val = {}; - val.f = cast(f32)res; - - LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = LLVMConstInt(elem, val.i, false); - for (unsigned j = 1; j < count; j++) { - elems[j] = LLVMConstNull(elem); - } - block_value = LLVMConstArray(elem, elems, count); - goto assign_value_wrapped; - } - break; - case LLVMDoubleTypeKind: - { - LLVMBool loses = false; - f64 res = LLVMConstRealGetDouble(variant_value, &loses); - union { f64 f; u64 i; } val = {}; - val.f = res; - - LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = LLVMConstInt(elem, val.i, false); - for (unsigned j = 1; j < count; j++) { - elems[j] = LLVMConstNull(elem); - } - block_value = LLVMConstArray(elem, elems, count); - goto assign_value_wrapped; - } - break; - } - } + if (block_kind == LLVMArrayTypeKind) { + LLVMTypeRef elem = LLVMGetElementType(block_type); + unsigned count = LLVMGetArrayLength(block_type); - } else if (block_kind == LLVMIntegerTypeKind && !is_type_different_to_arch_endianness(variant_type)) { - if (variant_kind == LLVMIntegerTypeKind) { - i64 variant_size = lb_sizeof(llvm_variant_type); - if (block_size > variant_size) { - u64 val = LLVMConstIntGetZExtValue(variant_value); - block_value = LLVMConstInt(block_type, val, false); + 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; + } - goto assign_value_wrapped; - } - } else { - switch (variant_kind) { - case LLVMHalfTypeKind: - { - LLVMBool loses = false; - f64 res = LLVMConstRealGetDouble(variant_value, &loses); - u16 val = f32_to_f16(cast(f32)res); - - block_value = LLVMConstInt(block_type, val, false); - goto assign_value_wrapped; - } - break; - case LLVMFloatTypeKind: - { - LLVMBool loses = false; - f64 res = LLVMConstRealGetDouble(variant_value, &loses); - union { f32 f; u32 i; } val = {}; - val.f = cast(f32)res; - - block_value = LLVMConstInt(block_type, val.i, false); - goto assign_value_wrapped; - } - break; - case LLVMDoubleTypeKind: - { - LLVMBool loses = false; - f64 res = LLVMConstRealGetDouble(variant_value, &loses); - union { f64 f; u64 i; } val = {}; - val.f = res; - - block_value = LLVMConstInt(block_type, val.i, false); - goto assign_value_wrapped; - } - break; - } + 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: -- cgit v1.2.3