From 56e0ab7655337b8ce9738d214c21e5f06e91df09 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Mar 2025 13:11:41 +0000 Subject: Fix #4952 --- src/llvm_backend_const.cpp | 49 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index b916c0017..c011e62f4 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1125,10 +1125,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo visited[index] = true; } else { if (!visited[index]) { - values[index] = lb_const_value(m, f->type, {}, false).value; + values[index] = lb_const_value(m, f->type, {}, allow_local, is_rodata).value; visited[index] = true; } + unsigned idx_list_len = cast(unsigned)sel.index.count-1; unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len); @@ -1139,6 +1140,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i32 index = sel.index[j]; Type *cvt = base_type(cv_type); + if (cvt->kind == Type_Struct) { if (cvt->Struct.is_raw_union) { // sanity check which should have been caught by `lb_is_nested_possibly_constant` @@ -1164,9 +1166,38 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (is_constant) { LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local, is_rodata).value; - if (LLVMIsConstant(elem_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 { + } else if (is_local) { + lbProcedure *p = m->curr_procedure; + GB_ASSERT(p != nullptr); + if (LLVMIsConstant(values[index])) { + lbAddr addr = lb_add_local_generated(p, f->type, false); + lb_addr_store(p, addr, lbValue{values[index], f->type}); + values[index] = lb_addr_load(p, addr).value; + } + + GB_ASSERT(LLVMIsALoadInst(values[index])); + + LLVMValueRef ptr = LLVMGetOperand(values[index], 0); + + LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, idx_list_len); + LLVMTypeRef lt_u32 = lb_type(m, t_u32); + for (unsigned i = 0; i < idx_list_len; i++) { + indices[i] = LLVMConstInt(lt_u32, idx_list[i], false); + } + + ptr = LLVMBuildGEP2(p->builder, lb_type(m, f->type), ptr, indices, idx_list_len, ""); + ptr = LLVMBuildPointerCast(p->builder, ptr, lb_type(m, alloc_type_pointer(tav.type)), ""); + + if (LLVMIsALoadInst(elem_value)) { + i64 sz = type_size_of(tav.type); + LLVMValueRef src = LLVMGetOperand(elem_value, 0); + lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false); + } else { + LLVMBuildStore(p->builder, elem_value, ptr); + } + is_constant = false; } } @@ -1205,7 +1236,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef val = values[i]; if (!LLVMIsConstant(val)) { GB_ASSERT(is_local); - GB_ASSERT(LLVMGetInstructionOpcode(val) == LLVMLoad); + GB_ASSERT(LLVMIsALoadInst(val)); is_constant = false; } } @@ -1237,7 +1268,15 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef val = old_values[i]; if (!LLVMIsConstant(val)) { LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, ""); - LLVMBuildStore(p->builder, val, dst); + if (LLVMIsALoadInst(val)) { + Type *ptr_type = v.addr.type; + i64 sz = type_size_of(type_deref(ptr_type)); + + LLVMValueRef src = LLVMGetOperand(val, 0); + lb_mem_copy_non_overlapping(p, {dst, ptr_type}, {src, ptr_type}, lb_const_int(m, t_int, sz), false); + } else { + LLVMBuildStore(p->builder, val, dst); + } } } return lb_addr_load(p, v); -- cgit v1.2.3 From fe6117fc633d59fa3cc7501a9e99590d4f82eca5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Mar 2025 13:14:54 +0000 Subject: Use `store` over `memcpy` --- src/llvm_backend_const.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index c011e62f4..80ba5406a 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1190,13 +1190,13 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ptr = LLVMBuildGEP2(p->builder, lb_type(m, f->type), ptr, indices, idx_list_len, ""); ptr = LLVMBuildPointerCast(p->builder, ptr, lb_type(m, alloc_type_pointer(tav.type)), ""); - if (LLVMIsALoadInst(elem_value)) { - i64 sz = type_size_of(tav.type); - LLVMValueRef src = LLVMGetOperand(elem_value, 0); - lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false); - } else { + // if (LLVMIsALoadInst(elem_value)) { + // i64 sz = type_size_of(tav.type); + // LLVMValueRef src = LLVMGetOperand(elem_value, 0); + // lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false); + // } else { LLVMBuildStore(p->builder, elem_value, ptr); - } + // } is_constant = false; } -- cgit v1.2.3 From 5e89e5ad8b6c8ac6599c6f435ecd66d6812c4dd5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Mar 2025 13:40:24 +0000 Subject: Use `store` --- src/llvm_backend_const.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 80ba5406a..5587a298a 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1125,7 +1125,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo visited[index] = true; } else { if (!visited[index]) { - values[index] = lb_const_value(m, f->type, {}, allow_local, is_rodata).value; + values[index] = lb_const_value(m, f->type, {}, /*allow_local*/false, is_rodata).value; visited[index] = true; } @@ -1169,6 +1169,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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) { + #if 1 lbProcedure *p = m->curr_procedure; GB_ASSERT(p != nullptr); if (LLVMIsConstant(values[index])) { @@ -1190,14 +1191,16 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ptr = LLVMBuildGEP2(p->builder, lb_type(m, f->type), ptr, indices, idx_list_len, ""); ptr = LLVMBuildPointerCast(p->builder, ptr, lb_type(m, alloc_type_pointer(tav.type)), ""); - // if (LLVMIsALoadInst(elem_value)) { - // i64 sz = type_size_of(tav.type); - // LLVMValueRef src = LLVMGetOperand(elem_value, 0); - // lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false); - // } else { + if (LLVMIsALoadInst(elem_value)) { + i64 sz = type_size_of(tav.type); + LLVMValueRef src = LLVMGetOperand(elem_value, 0); + lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false); + } else { LLVMBuildStore(p->builder, elem_value, ptr); - // } - + } + #endif + is_constant = false; + } else { is_constant = false; } } @@ -1268,15 +1271,15 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef val = old_values[i]; if (!LLVMIsConstant(val)) { LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, ""); - if (LLVMIsALoadInst(val)) { - Type *ptr_type = v.addr.type; - i64 sz = type_size_of(type_deref(ptr_type)); - - LLVMValueRef src = LLVMGetOperand(val, 0); - lb_mem_copy_non_overlapping(p, {dst, ptr_type}, {src, ptr_type}, lb_const_int(m, t_int, sz), false); - } else { - LLVMBuildStore(p->builder, val, dst); - } + // if (LLVMIsALoadInst(val)) { + // Type *ptr_type = v.addr.type; + // i64 sz = type_size_of(type_deref(ptr_type)); + + // LLVMValueRef src = LLVMGetOperand(val, 0); + // lb_mem_copy_non_overlapping(p, {dst, ptr_type}, {src, ptr_type}, lb_const_int(m, t_int, sz), false); + // } else { + LLVMBuildStore(p->builder, val, dst); + // } } } return lb_addr_load(p, v); -- cgit v1.2.3 From 10bde208502490371c42b5136d40d7d0cadef3cb Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 2 Apr 2025 14:21:52 +0200 Subject: Fix #4980 Add nullptr check. --- src/llvm_backend_const.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 5587a298a..9401e4d55 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -33,7 +33,7 @@ gb_internal bool lb_is_elem_const(Ast *elem, Type *elem_type) { gb_internal bool lb_is_const_nil(lbValue value) { LLVMValueRef v = value.value; - if (LLVMIsConstant(v)) { + if (v != nullptr && LLVMIsConstant(v)) { if (LLVMIsAConstantAggregateZero(v)) { return true; } else if (LLVMIsAConstantPointerNull(v)) { -- cgit v1.2.3 From fe040d1bbd22c78081ffc1d45b3462f40f8eb17a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Apr 2025 11:36:53 +0100 Subject: Propagate `@(link_section=)` to nested declarations --- src/llvm_backend.cpp | 19 ++++++--- src/llvm_backend.hpp | 14 ++++++- src/llvm_backend_const.cpp | 92 +++++++++++++++++++++++++------------------- src/llvm_backend_expr.cpp | 7 ++-- src/llvm_backend_general.cpp | 23 +++++++---- src/llvm_backend_opt.cpp | 4 +- src/llvm_backend_stmt.cpp | 3 +- 7 files changed, 99 insertions(+), 63 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 396b94f98..ee0ea7567 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2056,8 +2056,8 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star if (testing_proc->pkg != nullptr) { pkg_name = testing_proc->pkg->name; } - lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name); - lbValue v_name = lb_find_or_add_entity_string(m, name); + lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name, false); + lbValue v_name = lb_find_or_add_entity_string(m, name, false); lbValue v_proc = lb_find_procedure_value_from_entity(m, testing_proc); indices[1] = LLVMConstInt(lb_type(m, t_int), testing_proc_index++, false); @@ -2565,12 +2565,16 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (!is_type_any(e->type) && !is_type_union(e->type)) { if (tav.mode != Addressing_Invalid) { if (tav.value.kind != ExactValue_Invalid) { - bool is_rodata = e->kind == Entity_Variable && e->Variable.is_rodata; + auto cc = LB_CONST_CONTEXT_DEFAULT; + cc.is_rodata = e->kind == Entity_Variable && e->Variable.is_rodata; + cc.allow_local = false; + cc.link_section = e->Variable.link_section; + ExactValue v = tav.value; - lbValue init = lb_const_value(m, tav.type, v, false, is_rodata); + lbValue init = lb_const_value(m, tav.type, v, cc); LLVMSetInitializer(g.value, init.value); var.is_initialized = true; - if (is_rodata) { + if (cc.is_rodata) { LLVMSetGlobalConstant(g.value, true); } } @@ -2585,6 +2589,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } else if (e->kind == Entity_Variable && e->Variable.is_rodata) { LLVMSetGlobalConstant(g.value, true); } + + if (e->flags & EntityFlag_Require) { + lb_append_to_compiler_used(m, g.value); + } + array_add(&global_variables, var); lb_add_entity(m, e, g); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 3e01ada5f..6177fcf6e 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -415,9 +415,19 @@ gb_internal LLVMTypeRef llvm_get_element_type(LLVMTypeRef type); gb_internal lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false); +struct lbConstContext { + bool allow_local; + bool is_rodata; + String link_section; +}; + +static lbConstContext const LB_CONST_CONTEXT_DEFAULT = {true, false, {}}; +static lbConstContext const LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL = {true, false, {}}; +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, bool allow_local=true, bool is_rodata=false); +gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT); gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value); gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value); @@ -514,7 +524,7 @@ gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base gb_internal lbValue lb_type_info(lbProcedure *p, Type *type); -gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str); +gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str, bool custom_link_section); gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr); gb_internal bool lb_is_const(lbValue value); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 9401e4d55..dada2cff5 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -301,10 +301,10 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons } LLVMValueRef fields[4] = {}; - fields[0]/*file*/ = lb_find_or_add_entity_string(m, file).value; + fields[0]/*file*/ = lb_find_or_add_entity_string(m, file, false).value; fields[1]/*line*/ = lb_const_int(m, t_i32, line).value; fields[2]/*column*/ = lb_const_int(m, t_i32, column).value; - fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure).value; + fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure, false).value; lbValue res = {}; res.value = llvm_const_named_struct(m, t_source_code_location, fields, gb_count_of(fields)); @@ -391,12 +391,12 @@ gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, Ast * -gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local, bool is_rodata) { - if (allow_local) { - is_rodata = false; +gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, lbConstContext cc) { + if (cc.allow_local) { + cc.is_rodata = false; } - bool is_local = allow_local && m->curr_procedure != nullptr; + bool is_local = cc.allow_local && m->curr_procedure != nullptr; bool is_const = true; if (is_local) { for (isize i = 0; i < count; i++) { @@ -500,9 +500,9 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, return lb_is_elem_const(elem, ft); } -gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local, bool is_rodata) { - if (allow_local) { - is_rodata = false; +gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) { + if (cc.allow_local) { + cc.is_rodata = false; } LLVMContextRef ctx = m->ctx; @@ -543,7 +543,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo return res; } - bool is_local = allow_local && m->curr_procedure != nullptr; + bool is_local = cc.allow_local && m->curr_procedure != nullptr; // GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type)); @@ -562,7 +562,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata); + lbValue backing_array = lb_const_value(m, t, value, cc); LLVMValueRef array_data = nullptr; @@ -599,7 +599,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str); LLVMSetInitializer(array_data, backing_array.value); - if (is_rodata) { + if (cc.link_section.len > 0) { + LLVMSetSection(array_data, alloc_cstring(permanent_allocator(), cc.link_section)); + } + if (cc.is_rodata) { LLVMSetGlobalConstant(array_data, true); } @@ -650,7 +653,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } // NOTE(bill, 2021-10-07): Allow for array programming value constants Type *core_elem = core_array_type(type); - return lb_const_value(m, core_elem, value, allow_local, is_rodata); + return lb_const_value(m, core_elem, value, cc); } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { GB_ASSERT(type->Array.count == value.value_string.len); LLVMValueRef data = LLVMConstStringInContext(ctx, @@ -668,7 +671,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Type *elem = type->Array.elem; - lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata); + lbValue single_elem = lb_const_value(m, elem, value, cc); LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count); for (i64 i = 0; i < count; i++) { @@ -686,7 +689,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Type *elem = type->Matrix.elem; - lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata); + lbValue single_elem = lb_const_value(m, elem, value, cc); single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem)); i64 total_elem_count = matrix_type_total_internal_elems(type); @@ -708,7 +711,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i64 count = type->SimdVector.count; Type *elem = type->SimdVector.elem; - lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata); + lbValue single_elem = lb_const_value(m, elem, value, cc); single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem)); LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count); @@ -729,9 +732,16 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo return res; case ExactValue_String: { - LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string); + bool custom_link_section = cc.link_section.len > 0; + + LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string, custom_link_section); lbValue res = {}; res.type = default_type(original_type); + + if (custom_link_section) { + LLVMSetSection(ptr, alloc_cstring(permanent_allocator(), cc.link_section)); + } + if (is_type_cstring(res.type)) { res.value = ptr; } else { @@ -837,7 +847,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo case ExactValue_Compound: if (is_type_slice(type)) { - return lb_const_value(m, type, value, allow_local, is_rodata); + return lb_const_value(m, type, value, cc); } else if (is_type_array(type)) { ast_node(cl, CompoundLit, value.value_compound); Type *elem_type = type->Array.elem; @@ -871,7 +881,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -886,7 +896,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; values[value_index++] = val; found = true; break; @@ -899,7 +909,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); return res; } else { GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); @@ -909,13 +919,13 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc).value; } for (isize i = elem_count; i < type->Array.count; i++) { values[i] = LLVMConstNull(lb_type(m, elem_type)); } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); return res; } } else if (is_type_enumerated_array(type)) { @@ -955,7 +965,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -970,7 +980,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; values[value_index++] = val; found = true; break; @@ -983,7 +993,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, cc); return res; } else { GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count); @@ -993,13 +1003,13 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc).value; } for (isize i = elem_count; i < type->EnumeratedArray.count; i++) { values[i] = LLVMConstNull(lb_type(m, elem_type)); } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, cc); return res; } } else if (is_type_simd_vector(type)) { @@ -1038,7 +1048,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -1053,7 +1063,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; values[value_index++] = val; found = true; break; @@ -1072,7 +1082,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc).value; } LLVMTypeRef et = lb_type(m, elem_type); @@ -1121,11 +1131,13 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + values[index] = lb_const_value(m, f->type, tav.value, cc).value; visited[index] = true; } else { if (!visited[index]) { - values[index] = lb_const_value(m, f->type, {}, /*allow_local*/false, is_rodata).value; + auto new_cc = cc; + new_cc.allow_local = false; + values[index] = lb_const_value(m, f->type, {}, new_cc).value; visited[index] = true; } @@ -1165,7 +1177,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } if (is_constant) { - LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local, is_rodata).value; + LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc).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) { @@ -1219,7 +1231,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + values[index] = lb_const_value(m, f->type, val, cc).value; visited[index] = true; } } @@ -1353,7 +1365,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; for (i64 k = lo; k < hi; k++) { i64 offset = matrix_row_major_index_to_offset(type, k); GB_ASSERT(values[offset] == nullptr); @@ -1365,7 +1377,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; i64 offset = matrix_row_major_index_to_offset(type, index); GB_ASSERT(values[offset] == nullptr); values[offset] = val; @@ -1378,7 +1390,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, cc); return res; } else { GB_ASSERT_MSG(elem_count == max_count, "%td != %td", elem_count, max_count); @@ -1389,7 +1401,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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, allow_local, is_rodata).value; + values[offset] = lb_const_value(m, elem_type, tav.value, cc).value; } for (isize i = 0; i < total_count; i++) { if (values[i] == nullptr) { @@ -1397,7 +1409,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, cc); return res; } } else { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0c82180ec..20b8d3cf8 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2352,7 +2352,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { Type *elem = base_array_type(dst); lbValue e = lb_emit_conv(p, value, elem); lbAddr v = lb_add_local_generated(p, t, false); - lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), true); + lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL); for (i64 j = 0; j < dst->Matrix.column_count; j++) { for (i64 i = 0; i < dst->Matrix.row_count; i++) { lbValue ptr = lb_emit_matrix_epi(p, v.addr, i, j); @@ -2389,7 +2389,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { lb_emit_store(p, d, s); } else if (i == j) { lbValue d = lb_emit_matrix_epi(p, v.addr, i, j); - lbValue s = lb_const_value(p->module, dst->Matrix.elem, exact_value_i64(1), true); + lbValue s = lb_const_value(p->module, dst->Matrix.elem, exact_value_i64(1), LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL); lb_emit_store(p, d, s); } } @@ -3493,8 +3493,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Short on constant values - bool allow_local = true; - return lb_const_value(p->module, type, tv.value, allow_local); + return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL); } 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); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index ce2c70661..421720c4c 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -356,7 +356,7 @@ gb_internal LLVMValueRef llvm_const_insert_value(lbModule *m, LLVMValueRef agg, gb_internal LLVMValueRef llvm_cstring(lbModule *m, String const &str) { - lbValue v = lb_find_or_add_entity_string(m, str); + lbValue v = lb_find_or_add_entity_string(m, str, false); unsigned indices[1] = {0}; return llvm_const_extract_value(m, v.value, indices, gb_count_of(indices)); } @@ -568,7 +568,7 @@ gb_internal void lb_set_file_line_col(lbProcedure *p, Array arr, TokenP col = obfuscate_i32(col); } - arr[0] = lb_find_or_add_entity_string(p->module, file); + arr[0] = lb_find_or_add_entity_string(p->module, file, false); arr[1] = lb_const_int(p->module, t_i32, line); arr[2] = lb_const_int(p->module, t_i32, col); } @@ -2543,9 +2543,14 @@ general_end:; -gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { - StringHashKey key = string_hash_string(str); - LLVMValueRef *found = string_map_get(&m->const_strings, key); +gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str, bool custom_link_section) { + StringHashKey key = {}; + LLVMValueRef *found = nullptr; + + if (!custom_link_section) { + key = string_hash_string(str); + found = string_map_get(&m->const_strings, key); + } if (found != nullptr) { return *found; } else { @@ -2568,15 +2573,17 @@ gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String co LLVMSetAlignment(global_data, 1); LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); - string_map_set(&m->const_strings, key, ptr); + if (!custom_link_section) { + string_map_set(&m->const_strings, key, ptr); + } return ptr; } } -gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) { +gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str, bool custom_link_section) { LLVMValueRef ptr = nullptr; if (str.len != 0) { - ptr = lb_find_or_add_entity_string_ptr(m, str); + ptr = lb_find_or_add_entity_string_ptr(m, str, custom_link_section); } else { ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); } diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 7fe1359b4..8d5cfcb70 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -516,7 +516,7 @@ gb_internal void llvm_delete_function(LLVMValueRef func) { LLVMDeleteFunction(func); } -gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) { +gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef value) { LLVMValueRef global = LLVMGetNamedGlobal(m->mod, "llvm.compiler.used"); LLVMValueRef *constants; @@ -544,7 +544,7 @@ gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) { LLVMTypeRef Int8PtrTy = LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0); LLVMTypeRef ATy = llvm_array_type(Int8PtrTy, operands); - constants[operands - 1] = LLVMConstBitCast(func, Int8PtrTy); + constants[operands - 1] = LLVMConstBitCast(value, Int8PtrTy); LLVMValueRef initializer = LLVMConstArray(Int8PtrTy, constants, operands); global = LLVMAddGlobal(m->mod, ATy, "llvm.compiler.used"); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 1f783b1be..a0b7e8340 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1963,8 +1963,7 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { GB_ASSERT(ast_value->tav.mode == Addressing_Constant || ast_value->tav.mode == Addressing_Invalid); - bool allow_local = false; - value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, allow_local); + value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL); } Ast *ident = vd->names[i]; -- cgit v1.2.3 From ee8aeea38163c18a9b3513717bd09d3765c0d6d8 Mon Sep 17 00:00:00 2001 From: bogwi Date: Mon, 5 May 2025 14:18:11 +0900 Subject: CHECK 1 done Fix panic in LLVM backend when using generic procedure with default arguments - Fixed panic in `llvm_backend_proc.cpp` when using unspecialized polymorphic procedures as defaults. - Ensured correct type inference when generic procedures are used as default parameters. --- src/llvm_backend_const.cpp | 5 ++++- src/llvm_backend_general.cpp | 12 ++++++++++-- src/llvm_backend_proc.cpp | 12 ++++++++++++ 3 files changed, 26 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 dada2cff5..51c8a4449 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -533,7 +533,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb Entity *e = entity_from_expr(expr); res = lb_find_procedure_value_from_entity(m, e); } - GB_ASSERT(res.value != nullptr); + if (res.value == nullptr) { + // This is an unspecialized polymorphic procedure, return nil or dummy value + return lb_const_nil(m, original_type); + } GB_ASSERT(LLVMGetValueKind(res.value) == LLVMFunctionValueKind); if (LLVMGetIntrinsicID(res.value) == 0) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 421720c4c..41a6fb34a 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -885,8 +885,8 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { Type *t = base_type(type_deref(addr.addr.type)); GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); lbValue len = lb_soa_struct_len(p, addr.addr); - if (addr.soa.index_expr != nullptr) { - lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), index, len); + if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { + lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); } } @@ -2728,6 +2728,14 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) ignore_body = other_module != m; lbProcedure *missing_proc = lb_create_procedure(m, e, ignore_body); + if (missing_proc == nullptr) { + // This is an unspecialized polymorphic procedure, which should not be codegen'd + lbValue dummy = {}; + dummy.value = nullptr; + dummy.type = nullptr; + return dummy; + } + if (ignore_body) { mutex_lock(&gen->anonymous_proc_lits_mutex); defer (mutex_unlock(&gen->anonymous_proc_lits_mutex)); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index be51f529d..519ab3e9d 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -67,6 +67,14 @@ gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValu gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) { GB_ASSERT(entity != nullptr); GB_ASSERT(entity->kind == Entity_Procedure); + // Skip codegen for unspecialized polymorphic procedures + if (is_type_polymorphic(entity->type) && !entity->Procedure.is_foreign) { + Type *bt = base_type(entity->type); + if (bt->kind == Type_Proc && bt->Proc.is_polymorphic && !bt->Proc.is_poly_specialized) { + // Do not generate code for unspecialized polymorphic procedures + return nullptr; + } + } if (!entity->Procedure.is_foreign) { if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) { GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false)); @@ -815,6 +823,10 @@ gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) e->Procedure.link_name = name; lbProcedure *nested_proc = lb_create_procedure(p->module, e); + if (nested_proc == nullptr) { + // This is an unspecialized polymorphic procedure, skip codegen + return; + } e->code_gen_procedure = nested_proc; lbValue value = {}; -- cgit v1.2.3 From 6804f4c4716c65f2729945de3e7b7413fb061ee1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 4 Jun 2025 13:56:46 +0100 Subject: Add support for `#soa[N]T` compound literals --- src/check_expr.cpp | 184 ++++++++++++++++++++++++++------------------- src/llvm_backend_const.cpp | 142 ++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 77 deletions(-) (limited to 'src/llvm_backend_const.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 99d464da5..9308eab8e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9464,6 +9464,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } bool is_to_be_determined_array_count = false; bool is_constant = true; + bool is_soa = false; Ast *type_expr = cl->type; @@ -9496,8 +9497,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * GB_ASSERT(tag->kind == Ast_BasicDirective); String name = tag->BasicDirective.name.string; if (name == "soa") { - error(node, "#soa arrays are not supported for compound literals"); - return kind; + is_soa = true; + if (count == nullptr) { + error(node, "#soa slices are not supported for compound literals"); + return kind; + } else if (count->kind == Ast_UnaryExpr && + count->UnaryExpr.op.kind == Token_Question) { + error(node, "#soa fixed length arrays must specify their length and cannot use ?"); + } } } } @@ -9507,7 +9514,8 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * GB_ASSERT(tag->kind == Ast_BasicDirective); String name = tag->BasicDirective.name.string; if (name == "soa") { - error(node, "#soa arrays are not supported for compound literals"); + is_soa = true; + error(node, "#soa dynamic arrays are not supported for compound literals"); return kind; } } @@ -9536,101 +9544,101 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * switch (t->kind) { - case Type_Struct: { + case Type_Struct: if (cl->elems.count == 0) { break; // NOTE(bill): No need to init } - if (t->Struct.soa_kind != StructSoa_None) { - error(node, "#soa arrays are not supported for compound literals"); - break; - } - - if (t->Struct.is_raw_union) { - if (cl->elems.count > 0) { - // NOTE: unions cannot be constant - is_constant = false; + if (t->Struct.soa_kind == StructSoa_None) { + if (t->Struct.is_raw_union) { + if (cl->elems.count > 0) { + // NOTE: unions cannot be constant + is_constant = false; - if (cl->elems[0]->kind != Ast_FieldValue) { - gbString type_str = type_to_string(type); - error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str); - gb_string_free(type_str); - } else { - if (cl->elems.count != 1) { + if (cl->elems[0]->kind != Ast_FieldValue) { gbString type_str = type_to_string(type); - error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count); + error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str); gb_string_free(type_str); } else { - check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + if (cl->elems.count != 1) { + gbString type_str = type_to_string(type); + error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count); + gb_string_free(type_str); + } else { + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + } } } - } - break; - } - - wait_signal_until_available(&t->Struct.fields_wait_signal); - isize field_count = t->Struct.fields.count; - isize min_field_count = t->Struct.fields.count; - for (isize i = min_field_count-1; i >= 0; i--) { - Entity *e = t->Struct.fields[i]; - GB_ASSERT(e->kind == Entity_Variable); - if (e->Variable.param_value.kind != ParameterValue_Invalid) { - min_field_count--; - } else { break; } - } - if (cl->elems[0]->kind == Ast_FieldValue) { - check_compound_literal_field_values(c, cl->elems, o, type, is_constant); - } else { - bool seen_field_value = false; - - for_array(index, cl->elems) { - Entity *field = nullptr; - Ast *elem = cl->elems[index]; - if (elem->kind == Ast_FieldValue) { - seen_field_value = true; - error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } else if (seen_field_value) { - error(elem, "Value elements cannot be used after a 'field = value'"); - continue; - } - if (index >= field_count) { - error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count); + wait_signal_until_available(&t->Struct.fields_wait_signal); + isize field_count = t->Struct.fields.count; + isize min_field_count = t->Struct.fields.count; + for (isize i = min_field_count-1; i >= 0; i--) { + Entity *e = t->Struct.fields[i]; + GB_ASSERT(e->kind == Entity_Variable); + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + min_field_count--; + } else { break; } + } - if (field == nullptr) { - field = t->Struct.fields[index]; - } + if (cl->elems[0]->kind == Ast_FieldValue) { + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + } else { + bool seen_field_value = false; - Operand o = {}; - check_expr_or_type(c, &o, elem, field->type); + for_array(index, cl->elems) { + Entity *field = nullptr; + Ast *elem = cl->elems[index]; + if (elem->kind == Ast_FieldValue) { + seen_field_value = true; + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } else if (seen_field_value) { + error(elem, "Value elements cannot be used after a 'field = value'"); + continue; + } + if (index >= field_count) { + error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count); + break; + } - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { - is_constant = false; - } - if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); - } + if (field == nullptr) { + field = t->Struct.fields[index]; + } - check_assignment(c, &o, field->type, str_lit("structure literal")); - } - if (cl->elems.count < field_count) { - if (min_field_count < field_count) { - if (cl->elems.count < min_field_count) { - error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count); - } - } else { - error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count); + Operand o = {}; + check_expr_or_type(c, &o, elem, field->type); + + if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { + is_constant = false; + } + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &o); + } + + check_assignment(c, &o, field->type, str_lit("structure literal")); + } + if (cl->elems.count < field_count) { + if (min_field_count < field_count) { + if (cl->elems.count < min_field_count) { + error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count); + } + } else { + error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count); + } } } - } - break; - } + break; + } else if (t->Struct.soa_kind != StructSoa_Fixed) { + error(node, "#soa slices and dynamic arrays are not supported for compound literals"); + break; + } + /*fallthrough*/ case Type_Slice: case Type_Array: @@ -9641,7 +9649,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Type *elem_type = nullptr; String context_name = {}; i64 max_type_count = -1; - if (t->kind == Type_Slice) { + if (t->kind == Type_Struct) { + GB_ASSERT(t->Struct.soa_kind == StructSoa_Fixed); + elem_type = t->Struct.soa_elem; + context_name = str_lit("#soa array literal"); + if (!is_to_be_determined_array_count) { + max_type_count = t->Struct.soa_count; + } + } else if (t->kind == Type_Slice) { elem_type = t->Slice.elem; context_name = str_lit("slice literal"); } else if (t->kind == Type_Array) { @@ -9650,6 +9665,12 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (!is_to_be_determined_array_count) { max_type_count = t->Array.count; } + } else if (t->kind == Type_Array) { + elem_type = t->Array.elem; + context_name = str_lit("array literal"); + if (!is_to_be_determined_array_count) { + max_type_count = t->Array.count; + } } else if (t->kind == Type_DynamicArray) { elem_type = t->DynamicArray.elem; context_name = str_lit("dynamic array literal"); @@ -9817,6 +9838,15 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); } } + } else if (t->kind == Type_Struct) { + GB_ASSERT(t->Struct.soa_kind == StructSoa_Fixed); + if (is_to_be_determined_array_count) { + t->Struct.soa_count = cast(i32)max; + } else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < t->Struct.soa_count) { + error(node, "Expected %lld values for this #soa array literal, got %lld", cast(long long)t->Struct.soa_count, cast(long long)max); + } + } } diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 51c8a4449..02bb7473c 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -851,6 +851,148 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb case ExactValue_Compound: if (is_type_slice(type)) { return lb_const_value(m, type, value, cc); + } else if (is_type_soa_struct(type)) { + GB_ASSERT(type->kind == Type_Struct); + GB_ASSERT(type->Struct.soa_kind == StructSoa_Fixed); + ast_node(cl, CompoundLit, value.value_compound); + Type *elem_type = type->Struct.soa_elem; + isize elem_count = cl->elems.count; + if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) { + return lb_const_nil(m, original_type); + } + if (cl->elems[0]->kind == Ast_FieldValue) { + TEMPORARY_ALLOCATOR_GUARD(); + + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + + isize elem_count = cast(isize)type->Struct.soa_count; + + LLVMValueRef *aos_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count); + + isize value_index = 0; + for (i64 i = 0; i < elem_count; i++) { + bool found = false; + + for (isize j = 0; j < elem_count; j++) { + Ast *elem = cl->elems[j]; + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + if (lo == i) { + TypeAndValue tav = fv->value->tav; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value; + for (i64 k = lo; k < hi; k++) { + aos_values[value_index++] = val; + } + + found = true; + i += (hi-lo-1); + break; + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + 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; + aos_values[value_index++] = val; + found = true; + break; + } + } + } + + if (!found) { + aos_values[value_index++] = nullptr; + } + } + + + isize field_count = type->Struct.fields.count; + LLVMValueRef *soa_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, field_count); + + for (isize i = 0; i < field_count; i++) { + TEMPORARY_ALLOCATOR_GUARD(); + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count); + + Entity *f = type->Struct.fields[i]; + Type *array_type = f->type; + GB_ASSERT(array_type->kind == Type_Array); + Type *field_type = array_type->Array.elem; + + for (isize j = 0; j < elem_count; j++) { + LLVMValueRef v = aos_values[j]; + if (v != nullptr) { + values[j] = llvm_const_extract_value(m, v, cast(unsigned)i); + } else { + values[j] = LLVMConstNull(lb_type(m, field_type)); + } + } + + soa_values[i] = lb_build_constant_array_values(m, array_type, field_type, elem_count, values, cc); + } + + res.value = llvm_const_named_struct(m, type, soa_values, field_count); + return res; + } else { + GB_ASSERT_MSG(elem_count == type->Struct.soa_count, "%td != %td", elem_count, type->Struct.soa_count); + + TEMPORARY_ALLOCATOR_GUARD(); + + isize elem_count = cast(isize)type->Struct.soa_count; + + LLVMValueRef *aos_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count); + + 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; + } + for (isize i = elem_count; i < type->Struct.soa_count; i++) { + aos_values[i] = nullptr; + } + + isize field_count = type->Struct.fields.count; + LLVMValueRef *soa_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, field_count); + + for (isize i = 0; i < field_count; i++) { + TEMPORARY_ALLOCATOR_GUARD(); + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count); + + Entity *f = type->Struct.fields[i]; + Type *array_type = f->type; + GB_ASSERT(array_type->kind == Type_Array); + Type *field_type = array_type->Array.elem; + + for (isize j = 0; j < elem_count; j++) { + LLVMValueRef v = aos_values[j]; + if (v != nullptr) { + values[j] = llvm_const_extract_value(m, v, cast(unsigned)i); + } else { + values[j] = LLVMConstNull(lb_type(m, field_type)); + } + } + + soa_values[i] = lb_build_constant_array_values(m, array_type, field_type, elem_count, values, cc); + } + + res.value = llvm_const_named_struct(m, type, soa_values, field_count); + return res; + } } else if (is_type_array(type)) { ast_node(cl, CompoundLit, value.value_compound); Type *elem_type = type->Array.elem; -- cgit v1.2.3 From 36b41ce163843c9524d789e6edbc171c1d723e85 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 5 Jun 2025 07:31:03 -0400 Subject: Let compound literal array be broadcast to a struct field of arrays Fixes #4364 Patch courtesy of @cribalik --- src/llvm_backend_const.cpp | 11 +++++++++++ tests/issues/run.bat | 1 + tests/issues/run.sh | 1 + tests/issues/test_issue_4364.odin | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 tests/issues/test_issue_4364.odin (limited to 'src/llvm_backend_const.cpp') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 02bb7473c..e897ae282 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1054,9 +1054,20 @@ 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) { + // 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; + } + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); return res; } else { + // Assume that compound value is an array literal GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); diff --git a/tests/issues/run.bat b/tests/issues/run.bat index bbe9b7ca6..8e71c3f3d 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -17,6 +17,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style ..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_4364.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5043.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 228efce7f..fc8ab513f 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -18,6 +18,7 @@ $ODIN test ../test_issue_2615.odin $COMMON $ODIN test ../test_issue_2637.odin $COMMON $ODIN test ../test_issue_2666.odin $COMMON $ODIN test ../test_issue_4210.odin $COMMON +$ODIN test ../test_issue_4364.odin $COMMON $ODIN test ../test_issue_4584.odin $COMMON if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then echo "SUCCESSFUL 1/1" diff --git a/tests/issues/test_issue_4364.odin b/tests/issues/test_issue_4364.odin new file mode 100644 index 000000000..817a1a26b --- /dev/null +++ b/tests/issues/test_issue_4364.odin @@ -0,0 +1,18 @@ +// Tests issue #4364 https://github.com/odin-lang/Odin/issues/4364 +package test_issues + +import "core:testing" + +@test +test_const_array_fill_assignment :: proc(t: ^testing.T) { + MAGIC :: 12345 + Struct :: struct {x: int} + CONST_ARR : [4]Struct : Struct{MAGIC} + arr := CONST_ARR + + testing.expect_value(t, len(arr), 4) + testing.expect_value(t, arr[0], Struct{MAGIC}) + testing.expect_value(t, arr[1], Struct{MAGIC}) + testing.expect_value(t, arr[2], Struct{MAGIC}) + testing.expect_value(t, arr[3], Struct{MAGIC}) +} -- cgit v1.2.3