From a44b8b0af0c2609192af0216eea3b8eeff571aa0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Apr 2026 10:42:53 +0100 Subject: [PATCH] Support `([N]T)([N]U{...})` --- src/check_expr.cpp | 9 ++- src/llvm_backend_expr.cpp | 114 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 195e0de7a..3bf72204c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3460,8 +3460,13 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type if (dst->kind == Type_Array && src->kind == Type_Array) { - if (are_types_identical(dst->Array.elem, src->Array.elem)) { - return dst->Array.count == src->Array.count; + if (dst->Array.count == src->Array.count) { + if (are_types_identical(dst->Array.elem, src->Array.elem)) { + return true; + } + Operand op = *operand; + op.type = src->Array.elem; + return check_is_castable_to(c, &op, dst->Array.elem); } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index d64a708c5..95f9b735f 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2691,6 +2691,120 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } + if (is_type_array(dst) && is_type_array(src)) { + auto is_simd_able_type = [](Type *t) -> bool { + if (t->kind != Type_Basic) { + return false; + } + + if (t->Basic.flags & (BasicFlag_Boolean|BasicFlag_Integer|BasicFlag_Float|BasicFlag_Rune)) { + TypeEndianKind kind = type_endian_kind_of(t); + switch (kind) { + case TypeEndian_Platform: return true; + case TypeEndian_Little: return build_context.endian_kind == TypeEndian_Little; + case TypeEndian_Big: return build_context.endian_kind == TypeEndian_Big; + } + } + return false; + }; + + + Type *dst_elem = base_array_type(dst); + Type *src_elem = base_array_type(src); + if (dst->Array.count == src->Array.count) { + if (are_types_identical(dst_elem, src_elem)) { + lbValue v = value; + v.type = t; + return v; + } + i64 count = dst->Array.count; + + Type *de = core_type(dst_elem); + Type *se = core_type(src_elem); + if (count <= 64 && // TODO(bill): is this a sensible limit? + is_simd_able_type(de) && is_simd_able_type(se)) { + // NOTE(bill, 2026-04-23): These types are simd-able meaning you can use the direct vector operators + // But we need to be careful when it comes to alignment and tell LLVM that it is only aligned + // to the element type and not the natural vector size + // + // This is to give it a proper hint that this can be done as a vector even when `-o:speed` is not set + + lbAddr v = lb_add_local_generated(p, t, false); // do not zero anything because it will be filled + + lbValue psrc = lb_address_from_load_or_generate_local(p, value); + lbValue pdst = v.addr; + + i64 de_sz = type_size_of(de); + i64 se_sz = type_size_of(se); + + LLVMOpcode op = cast(LLVMOpcode)0; + + if (is_type_float(se)) { + if (is_type_float(de)) { + if (de_sz == se_sz) { op = LLVMBitCast; } + else if (de_sz < se_sz) { op = LLVMFPTrunc; } + else { op = LLVMFPExt; } + } else { + GB_ASSERT(is_type_integer_like(de) || is_type_rune(de)); + if (is_type_unsigned(de) || is_type_boolean(de)) { op = LLVMFPToUI; } + else { op = LLVMFPToSI; } + } + } else { + GB_ASSERT(is_type_integer_like(se) || is_type_rune(se)); + + if (is_type_float(de)) { + if (is_type_unsigned(se) || is_type_boolean(se)) { op = LLVMUIToFP; } + else { op = LLVMSIToFP; } + } else { + if (de_sz == se_sz) { + op = LLVMBitCast; + } else if (de_sz < se_sz) { + op = LLVMTrunc; + } else { + op = (is_type_unsigned(se) || is_type_boolean(se)) ? LLVMZExt : LLVMSExt; // zero extent + } + } + } + + GB_ASSERT(op != 0); + + LLVMTypeRef src_vector_type = LLVMVectorType(lb_type(p->module, se), cast(unsigned)count); + LLVMTypeRef dst_vector_type = LLVMVectorType(lb_type(p->module, de), cast(unsigned)count); + + LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, psrc.value, LLVMPointerType(src_vector_type, 0), ""); + LLVMValueRef dst_ptr = LLVMBuildPointerCast(p->builder, pdst.value, LLVMPointerType(dst_vector_type, 0), ""); + + LLVMValueRef src_vector = LLVMBuildLoad2(p->builder, src_vector_type, src_ptr, ""); + LLVMSetAlignment(src_vector, cast(unsigned)type_align_of(se)); + + LLVMValueRef dst_vector = LLVMBuildCast(p->builder, op, src_vector, dst_vector_type, ""); + + LLVMValueRef store = LLVMBuildStore(p->builder, dst_vector, dst_ptr); + LLVMSetAlignment(store, cast(unsigned)type_align_of(de)); + + return lb_addr_load(p, v); + } else { + lbAddr v = lb_add_local_generated(p, t, true); + + lbValue psrc = lb_address_from_load_or_generate_local(p, value); + lbValue pdst = v.addr; + + for (i64 i = 0; i < count; i++) { + lbValue sp = lb_emit_array_epi(p, psrc, i); + lbValue dp = lb_emit_array_epi(p, pdst, i); + + lbValue s = lb_emit_load(p, sp); + s = lb_emit_conv(p, s, dst_elem); + lb_emit_store(p, dp, s); + } + + return lb_addr_load(p, v); + } + + } + } + + if (is_type_array_like(dst)) { Type *elem = base_array_type(dst); isize index_count = cast(isize)get_array_type_count(dst);