- Miscompilation: global struct with vector could generate an incorrect initializer.

This commit is contained in:
Christoffer Lerno
2025-12-30 23:54:00 +01:00
parent ad8769580a
commit d8a7c57b56
3 changed files with 36 additions and 14 deletions

View File

@@ -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.

View File

@@ -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));
}

View File

@@ -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