Support ([N]T)([N]U{...})

This commit is contained in:
gingerBill
2026-04-23 10:42:53 +01:00
parent 01734dfa9b
commit a44b8b0af0
2 changed files with 121 additions and 2 deletions

View File

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

View File

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