mirror of
https://github.com/odin-lang/Odin.git
synced 2026-05-25 21:28:13 +00:00
Support ([N]T)([N]U{...})
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user