From d8a7c57b567134bdf066c542c719b3011ca3870f Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 30 Dec 2025 23:54:00 +0100 Subject: [PATCH] - Miscompilation: global struct with vector could generate an incorrect initializer. --- releasenotes.md | 1 + src/compiler/llvm_codegen.c | 27 +++++++++---------- .../vector/const_init_struct_with_vector.c3t | 22 +++++++++++++++ 3 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 test/test_suite/vector/const_init_struct_with_vector.c3t diff --git a/releasenotes.md b/releasenotes.md index 18f20f55c..e6003cdb2 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -43,6 +43,7 @@ - Assert when encountering a test function with raw vaarg parameters. - `foo.x` was not always handled correctly when `foo` was optional. - `x'1234' +++ (ichar[1]) { 'A' }` would fail due to missing const folding. +- Miscompilation: global struct with vector could generate an incorrect initializer. ### Stdlib changes - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index fcc067fa7..e93b8a292 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -230,22 +230,22 @@ static LLVMValueRef llvm_emit_const_array_padding(LLVMTypeRef element_type, Inde LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init, bool in_aggregate) { ASSERT(const_init->type == type_flatten(const_init->type)); + Type *type = in_aggregate && const_init->type->type_kind == TYPE_VECTOR ? type_array_from_vector(const_init->type) : const_init->type; switch (const_init->kind) { case CONST_INIT_ZERO: - return llvm_get_zero(c, const_init->type); + return llvm_get_zero(c, type); case CONST_INIT_ARRAY_VALUE: UNREACHABLE case CONST_INIT_ARRAY_FULL: { - ASSERT(const_init->type->type_kind != TYPE_SLICE); + ASSERT(type->type_kind != TYPE_SLICE); bool was_modified = false; - Type *array_type = const_init->type; - Type *element_type = array_type->array.base; + Type *element_type = type->array.base; LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); ConstInitializer **elements = const_init->init_array_full; - ASSERT(type_is_arraylike(array_type)); - ArraySize size = array_type->array.len; + ASSERT(type_is_arraylike(type)); + ArraySize size = type->array.len; ASSERT(size > 0); LLVMValueRef *parts = VECNEW(LLVMValueRef, size); for (ArrayIndex i = 0; i < (ArrayIndex)size; i++) @@ -254,7 +254,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ if (element_type_llvm != LLVMTypeOf(element)) was_modified = true; vec_add(parts, element); } - if ((!in_aggregate && array_type->type_kind == TYPE_VECTOR) || array_type->type_kind == TYPE_SIMD_VECTOR) + if (type->type_kind == TYPE_VECTOR || type->type_kind == TYPE_SIMD_VECTOR) { return LLVMConstVector(parts, vec_size(parts)); } @@ -267,20 +267,19 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ case CONST_INIT_ARRAY: { - ASSERT(const_init->type->type_kind != TYPE_SLICE); + ASSERT(type->type_kind != TYPE_SLICE); bool was_modified = false; - Type *array_type = const_init->type; - Type *element_type = array_type->array.base; + Type *element_type = type->array.base; LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); AlignSize expected_align = llvm_abi_alignment(c, element_type_llvm); ConstInitializer **elements = const_init->init_array.elements; ASSERT(vec_size(elements) > 0 && "Array should always have gotten at least one element."); - if (elements > 0 && array_type->type_kind == TYPE_FLEXIBLE_ARRAY) was_modified = true; + if (elements > 0 && type->type_kind == TYPE_FLEXIBLE_ARRAY) was_modified = true; ArrayIndex current_index = 0; unsigned alignment = 0; LLVMValueRef *parts = NULL; bool pack = false; - bool is_vec = array_type->type_kind == TYPE_SIMD_VECTOR || (!in_aggregate && array_type->type_kind == TYPE_VECTOR); + bool is_vec = type->type_kind == TYPE_SIMD_VECTOR || type->type_kind == TYPE_VECTOR; FOREACH(ConstInitializer *, element, elements) { ASSERT(element->kind == CONST_INIT_ARRAY_VALUE); @@ -312,7 +311,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ current_index = element_index + 1; } - IndexDiff end_diff = (ArrayIndex)array_type->array.len - current_index; + IndexDiff end_diff = (ArrayIndex)type->array.len - current_index; if (end_diff > 0) { vec_add(parts, llvm_emit_const_array_padding(element_type_llvm, end_diff, &was_modified)); @@ -321,7 +320,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ { return llvm_get_unnamed_struct(c, parts, pack); } - if (type_flat_is_vector(array_type)) + if (type_flat_is_vector(type)) { return LLVMConstVector(parts, vec_size(parts)); } diff --git a/test/test_suite/vector/const_init_struct_with_vector.c3t b/test/test_suite/vector/const_init_struct_with_vector.c3t new file mode 100644 index 000000000..95a6e780e --- /dev/null +++ b/test/test_suite/vector/const_init_struct_with_vector.c3t @@ -0,0 +1,22 @@ +// #target: macos-x64 +module test; +struct Struct +{ + float[<3>] foo; + int bar; +} + +Struct my_struct1 = { .foo[1] = 1.0, .bar = 10 }; +Struct my_struct2 = { .bar = 10 }; + +fn int main() +{ + return my_struct1.bar + my_struct2.bar; +} + +/* #expect: test.ll + + + +@test.my_struct1 = local_unnamed_addr global { [3 x float], i32 } { [3 x float] [float 0.000000e+00, float 1.000000e+00, float 0.000000e+00], i32 10 }, align 4 +@test.my_struct2 = local_unnamed_addr global { [3 x float], i32 } { [3 x float] zeroinitializer, i32 10 }, align 4