diff --git a/releasenotes.md b/releasenotes.md index 0be39d9b4..f9b4c6457 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -14,6 +14,7 @@ - Remove division-by-zero checks for floating point in safe mode #2556. - Fix division-by-zero checks on `a /= 0` and `b /= 0f` #2558. - Fix fmod `a %= 0f`. +- Regression vector ABI: initializing a struct containing a NPOT vector with a constant value would crash LLVM. #2559 ### Stdlib changes diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index fe014c4aa..079483c9f 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -143,6 +143,7 @@ typedef struct struct ConstInitializer_ { ConstInitType kind; + bool is_simd; // Type, should always be flattened Type *type; union @@ -4550,6 +4551,12 @@ INLINE bool check_module_name(Path *path) return true; } +INLINE void const_init_set_type(ConstInitializer *init, Type *type) +{ + init->is_simd = type_is_simd(type); + init->type = type_flatten(type); +} + INLINE bool expr_is_valid_index(Expr *expr) { ASSERT_SPAN(expr, expr_is_const_int(expr)); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index d479b6c8a..69ae73373 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -229,7 +229,7 @@ static LLVMValueRef llvm_emit_const_array_padding(LLVMTypeRef element_type, Inde return llvm_get_zero_raw(LLVMArrayType(element_type, (unsigned)diff)); } -LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init) +LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init, bool in_aggregate) { ASSERT(const_init->type == type_flatten(const_init->type)); switch (const_init->kind) @@ -252,11 +252,11 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ LLVMValueRef *parts = VECNEW(LLVMValueRef, size); for (ArrayIndex i = 0; i < (ArrayIndex)size; i++) { - LLVMValueRef element = llvm_emit_const_initializer(c, elements[i]); + LLVMValueRef element = llvm_emit_const_initializer(c, elements[i], true); if (element_type_llvm != LLVMTypeOf(element)) was_modified = true; vec_add(parts, element); } - if (array_type->type_kind == TYPE_VECTOR) + if ((!in_aggregate && array_type->type_kind == TYPE_VECTOR) || const_init->is_simd) { return LLVMConstVector(parts, vec_size(parts)); } @@ -282,7 +282,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ unsigned alignment = 0; LLVMValueRef *parts = NULL; bool pack = false; - bool is_vec = type_flat_is_vector(array_type); + bool is_vec = const_init->is_simd || (!in_aggregate && array_type->type_kind == TYPE_VECTOR); FOREACH(ConstInitializer *, element, elements) { ASSERT(element->kind == CONST_INIT_ARRAY_VALUE); @@ -308,7 +308,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ vec_add(parts, llvm_emit_const_array_padding(element_type_llvm, diff, &was_modified)); } } - LLVMValueRef value = llvm_emit_const_initializer(c, element->init_array_value.element); + LLVMValueRef value = llvm_emit_const_initializer(c, element->init_array_value.element, true); if (LLVMTypeOf(value) != element_type_llvm) was_modified = true; vec_add(parts, value); current_index = element_index + 1; @@ -334,7 +334,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ Decl *decl = const_init->type->decl; // Emit our value. - LLVMValueRef result = llvm_emit_const_initializer(c, const_init->init_union.element); + LLVMValueRef result = llvm_emit_const_initializer(c, const_init->init_union.element, true); LLVMTypeRef result_type = LLVMTypeOf(result); // Get the union value @@ -388,7 +388,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ { vec_add(entries, llvm_emit_const_padding(c, member->padding)); } - LLVMValueRef element = llvm_emit_const_initializer(c, const_init->init_struct[i]); + LLVMValueRef element = llvm_emit_const_initializer(c, const_init->init_struct[i], true); LLVMTypeRef element_type = LLVMTypeOf(element); //ASSERT(LLVMIsConstant(element)); if (llvm_get_type(c, member->type) != element_type) @@ -573,7 +573,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) { ASSERT(type_flatten(init_expr->type)->type_kind != TYPE_SLICE); ConstInitializer *list = init_expr->const_expr.initializer; - init_value = llvm_emit_const_initializer(c, list); + init_value = llvm_emit_const_initializer(c, list, false); } else { diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 5ab3aaf96..c999c75e0 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1419,7 +1419,7 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref, { // First create the constant value. - LLVMValueRef value = llvm_emit_const_initializer(c, initializer); + LLVMValueRef value = llvm_emit_const_initializer(c, initializer, false); // Create a global const. AlignSize alignment = type_alloca_alignment(initializer->type); @@ -1471,7 +1471,7 @@ static void llvm_emit_const_init_ref(GenContext *c, BEValue *ref, ConstInitializ { if (const_init->type->type_kind == TYPE_VECTOR) { - LLVMValueRef val = llvm_emit_const_initializer(c, const_init); + LLVMValueRef val = llvm_emit_const_initializer(c, const_init, !top); llvm_store_raw(c, ref, val); return; } @@ -4746,7 +4746,7 @@ static inline void llvm_emit_const_initializer_list_expr(GenContext *c, BEValue if (llvm_is_global_eval(c) || type_flat_is_vector(expr->type) || type_flatten(expr->type)->type_kind == TYPE_BITSTRUCT) { ASSERT(type_flatten(expr->type)->type_kind != TYPE_SLICE); - llvm_value_set(value, llvm_emit_const_initializer(c, expr->const_expr.initializer), expr->type); + llvm_value_set(value, llvm_emit_const_initializer(c, expr->const_expr.initializer, false), expr->type); return; } llvm_value_set_address_abi_aligned(c, value, llvm_emit_alloca_aligned(c, expr->type, "literal"), expr->type); @@ -4803,7 +4803,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) ConstInitializer *init = expr->const_expr.slice_init; if (llvm_is_global_eval(c) || type_flat_is_vector(expr->type) || type_flatten(expr->type)->type_kind == TYPE_BITSTRUCT) { - LLVMValueRef value = llvm_emit_const_initializer(c, init); + LLVMValueRef value = llvm_emit_const_initializer(c, init, false); AlignSize alignment = type_alloca_alignment(init->type); LLVMTypeRef val_type = llvm_get_type(c, init->type); LLVMValueRef global_copy = llvm_add_global_raw(c, ".__const_slice", val_type, alignment); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index a036afb4b..12f20b9df 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -400,7 +400,7 @@ INLINE void llvm_value_ext_trunc(GenContext *c, BEValue *value, Type *type); // -- Constants -- void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type); -LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init); +LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init, bool in_aggregate); LLVMValueRef llvm_emit_const_padding(GenContext *c, AlignSize size); LLVMValueRef llvm_emit_string_const(GenContext *c, const char *str, const char *extname); LLVMValueRef llvm_emit_empty_string_const(GenContext *c); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index d2a3a4174..d5de694fe 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1766,7 +1766,7 @@ static void vector_const_initializer_convert_to_type(ConstInitializer *initializ vector_const_initializer_convert_to_type(initializer->init_array_value.element, to_type); break; } - initializer->type = type_flatten(to_type); + const_init_set_type(initializer, to_type); } /** @@ -1987,7 +1987,7 @@ static void cast_vec_to_arr(Expr *expr, Type *to_type) ASSERT(expr->const_expr.const_kind == CONST_INITIALIZER); ConstInitializer *list = expr->const_expr.initializer; - list->type = type_flatten(to_type); + const_init_set_type(list, to_type); expr->type = to_type; } @@ -2398,6 +2398,7 @@ static void cast_arr_to_vec(Expr *expr, Type *to_type) ASSERT(expr->const_expr.const_kind == CONST_INITIALIZER); ConstInitializer *list = expr->const_expr.initializer; list->type = type_flatten(to_temp); + list->is_simd = type_is_simd(to_temp); expr->type = to_temp; } else diff --git a/src/compiler/sema_const.c b/src/compiler/sema_const.c index 8a2a8865a..340123906 100644 --- a/src/compiler/sema_const.c +++ b/src/compiler/sema_const.c @@ -248,7 +248,7 @@ static bool sema_append_const_array_one(SemaContext *context, Expr *expr, Expr * case CONST_INIT_ZERO: { init->kind = CONST_INIT_ARRAY; - init->type = new_inner_type; + const_init_set_type(init, new_inner_type); ConstInitializer **inits = NULL; vec_add(inits, const_init_new_array_value(element, len - 1)); init->init_array.elements = inits; @@ -257,13 +257,13 @@ static bool sema_append_const_array_one(SemaContext *context, Expr *expr, Expr * break; } case CONST_INIT_ARRAY: - init->type = new_inner_type; + const_init_set_type(init, new_inner_type); vec_add(init->init_array.elements, const_init_new_array_value(element, len - 1)); expr_replace(expr, list); expr->type = new_outer_type; break; case CONST_INIT_ARRAY_FULL: - init->type = new_inner_type; + const_init_set_type(init, new_inner_type); vec_add(init->init_array_full, const_init_new_value(element)); expr_replace(expr, list); expr->type = new_outer_type; @@ -544,7 +544,7 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr * ASSERT_SPAN(right, element->kind == CONST_INIT_ARRAY_VALUE); element->init_array_value.index += (ArrayIndex)len_lhs; } - rhs_init->type = type; + const_init_set_type(rhs_init, type); expr_rewrite_const_initializer(concat_expr, type, rhs_init); return true; } @@ -629,7 +629,7 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr * case CONST_INIT_ZERO: { // { 1 => 3 } + { 0, 0, 0 } - lhs_init->type = type; + const_init_set_type(lhs_init, type); expr_rewrite_const_initializer(concat_expr, type, lhs_init); return true; } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 0901e1c26..c5becd00d 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -4481,7 +4481,7 @@ static inline bool sema_slice_initializer(SemaContext *context, Expr *expr, Expr Type *inner_type = is_vec ? type_get_vector(new_type->array.base, range->len_index) : type_get_array(new_type->array.base, range->len_index); - initializer->type = inner_type; + const_init_set_type(initializer, inner_type); switch (initializer->kind) { case CONST_INIT_ZERO: diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index c71bb1182..6f7d27211 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -80,14 +80,14 @@ bool const_init_local_init_may_be_global_inner(ConstInitializer *init, bool top) void const_init_rewrite_to_zero(ConstInitializer *init, Type *type) { init->kind = CONST_INIT_ZERO; - init->type = type_flatten(type); + const_init_set_type(init, type); } ConstInitializer *const_init_new_array(Type *type, ConstInitializer **elements) { ConstInitializer *init = CALLOCS(ConstInitializer); init->kind = CONST_INIT_ARRAY; - init->type = type_flatten(type); + const_init_set_type(init, type); init->init_array.elements = elements; return init; } @@ -96,7 +96,7 @@ ConstInitializer *const_init_new_array_full(Type *type, ConstInitializer **eleme { ConstInitializer *init = CALLOCS(ConstInitializer); init->kind = CONST_INIT_ARRAY_FULL; - init->type = type_flatten(type); + const_init_set_type(init, type); init->init_array_full = elements; return init; } @@ -105,7 +105,7 @@ ConstInitializer *const_init_new_struct(Type *type, Expr **elements) { ConstInitializer *init = CALLOCS(ConstInitializer); init->kind = CONST_INIT_STRUCT; - init->type = type_flatten(type); + const_init_set_type(init, type); ConstInitializer **values = NULL; FOREACH(Expr *, expr, elements) { @@ -123,7 +123,7 @@ ConstInitializer *const_init_new_struct(Type *type, Expr **elements) ConstInitializer *const_init_new_union(Type *type, ArrayIndex index, Expr *value) { ConstInitializer *init = CALLOCS(ConstInitializer); - init->type = type_flatten(type); + const_init_set_type(init, type); init->kind = CONST_INIT_UNION; init->init_union.index = index; if (expr_is_const_initializer(value)) @@ -140,7 +140,7 @@ ConstInitializer *const_init_new_union(Type *type, ArrayIndex index, Expr *value ConstInitializer *const_init_new_array_value(Expr *expr, ArrayIndex index) { ConstInitializer *init = CALLOCS(ConstInitializer); - init->type = type_flatten(expr->type); + const_init_set_type(init, expr->type); init->kind = CONST_INIT_ARRAY_VALUE; init->init_array_value.index = index; init->init_array_value.element = const_init_new_value(expr); @@ -150,7 +150,7 @@ ConstInitializer *const_init_new_array_value(Expr *expr, ArrayIndex index) ConstInitializer *const_init_new_zero_array_value(Type *type, ArrayIndex index) { ConstInitializer *init = CALLOCS(ConstInitializer); - init->type = type_flatten(type); + const_init_set_type(init, type); init->kind = CONST_INIT_ARRAY_VALUE; init->init_array_value.index = index; init->init_array_value.element = const_init_new_zero(type); @@ -160,7 +160,7 @@ ConstInitializer *const_init_new_zero(Type *type) { ConstInitializer *init = CALLOCS(ConstInitializer); init->kind = CONST_INIT_ZERO; - init->type = type_flatten(type); + const_init_set_type(init, type); return init; } bool const_init_local_init_may_be_global(ConstInitializer *init) @@ -463,7 +463,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex } vec_add(inits, const_init_new_value(expr)); } - ConstInitializer *const_init = const_init_new_array_full(type_flatten(initializer->type), inits); + ConstInitializer *const_init = const_init_new_array_full(initializer->type, inits); expr_rewrite_const_initializer(initializer, initializer->type, const_init); } @@ -960,7 +960,7 @@ void const_init_rewrite_to_value(ConstInitializer *const_init, Expr *value) return; } const_init->init_value = value; - const_init->type = type_flatten(value->type); + const_init_set_type(const_init, value->type); const_init->kind = CONST_INIT_VALUE; } @@ -1106,7 +1106,7 @@ static inline void sema_update_const_initializer_with_designator_union(ConstInit } // Update of the sub element. - sub_element->type = type_flatten(const_init->type->decl->strukt.members[element->index]->type); + const_init_set_type(sub_element, const_init->type->decl->strukt.members[element->index]->type); // And the index const_init->init_union.index = element->index; diff --git a/src/compiler/types.c b/src/compiler/types.c index 30e0be4e4..0e6dfc29b 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -524,8 +524,12 @@ bool type_is_abi_aggregate(Type *type) bool type_is_simd(Type *type) { type = type->canonical; - if (type->type_kind != TYPE_TYPEDEF) return false; - return type->decl->attr_simd; + while (type->type_kind == TYPE_TYPEDEF) + { + if (type->decl->attr_simd) return true; + type = type->decl->distinct->type; + } + return false; } bool type_is_aggregate(Type *type) diff --git a/test/test_suite/struct/struct_vector_const_init.c3t b/test/test_suite/struct/struct_vector_const_init.c3t new file mode 100644 index 000000000..d31614262 --- /dev/null +++ b/test/test_suite/struct/struct_vector_const_init.c3t @@ -0,0 +1,36 @@ +// #target: macos-x64 +module test; +typedef Int4s = int[<4>] @simd; +typedef Int3 = int[<3>]; +struct Foo1 +{ + Int3 bar; +} +struct Foo2 +{ + Int4s bar; +} + +fn int main() +{ + Foo1 f1 = {{1,2,3}}; + Foo2 f2 = {{1,2,3,4}}; + return 0; +} + +/* #expect: test.ll + +%Foo2 = type { <4 x i32> } +%Foo1 = type { [3 x i32] } + +@.__const = private unnamed_addr constant { [3 x i32] } { [3 x i32] [i32 1, i32 2, i32 3] }, align 4 +@.__const.1 = private unnamed_addr constant %Foo2 { <4 x i32> }, align 16 + +define i32 @main() #0 { +entry: + %f1 = alloca %Foo1, align 4 + %f2 = alloca %Foo2, align 16 + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %f1, ptr align 4 @.__const, i32 12, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 16 %f2, ptr align 16 @.__const.1, i32 16, i1 false) + ret i32 0 +}