diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 219700ffd..39a223027 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -537,6 +537,84 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, return lb_is_elem_const(elem, ft); } +gb_internal Slice lb_construct_const_union_flatten_values(lbModule *m, LLVMValueRef variant_value, Type *variant_type, LLVMTypeRef elem) { + LLVMTypeRef llvm_variant_type = lb_type(m, variant_type); + LLVMTypeKind variant_kind = LLVMGetTypeKind(llvm_variant_type); + + if (are_types_identical(base_type(variant_type), t_string)) { + LLVMValueRef *elems = temporary_alloc_array(2); + elems[0] = llvm_const_extract_value(m, variant_value, 0); + elems[0] = LLVMConstPtrToInt(elems[0], elem); + + elems[1] = llvm_const_extract_value(m, variant_value, 1); + + return {elems, 2}; + } + + if (is_type_struct(variant_type)) { + // Type *st = base_type(variant_type); + // if (st->Struct.fields.count == 1) { + // return lb_construct_const_union_flatten_values(m, llvm_const_extract_value(m, variant_value, 0), st->Struct.fields[0]->type, elem); + // } + } else if (variant_kind == LLVMIntegerTypeKind) { + if (elem == llvm_variant_type) { + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = variant_value; + return {elems, 1}; + } else if (!is_type_different_to_arch_endianness(variant_type)) { + i64 elem_size = lb_sizeof(elem); + i64 variant_size = lb_sizeof(llvm_variant_type); + if (elem_size > variant_size) { + u64 val = LLVMConstIntGetZExtValue(variant_value); + + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = LLVMConstInt(elem, val, false); + return {elems, 1}; + } + } + } else if (!is_type_different_to_arch_endianness(variant_type)) { + switch (variant_kind) { + case LLVMHalfTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + u16 val = f32_to_f16(cast(f32)res); + + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = LLVMConstInt(elem, val, false); + return {elems, 1}; + } + break; + case LLVMFloatTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f32 f; u32 i; } val = {}; + val.f = cast(f32)res; + + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = LLVMConstInt(elem, val.i, false); + return {elems, 1}; + } + break; + case LLVMDoubleTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f64 f; u64 i; } val = {}; + val.f = res; + + LLVMValueRef *elems = temporary_alloc_array(1); + elems[0] = LLVMConstInt(elem, val.i, false); + return {elems, 1}; + } + break; + } + } + + return {}; +} + gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef variant_value, Type *variant_type, Type *union_type) { Type *bt = base_type(union_type); GB_ASSERT(bt->kind == Type_Union); @@ -601,43 +679,98 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari LLVMValueRef block_value = variant_value; - if (lb_sizeof(llvm_variant_type) == 0) { + if (block_size == 0) { + block_value = LLVMConstNull(block_type); + } else if (lb_sizeof(llvm_variant_type) == 0) { block_value = LLVMConstNull(block_type); } else if (block_type != llvm_variant_type) { - if (block_size != variant_size) { + LLVMTypeKind block_kind = LLVMGetTypeKind(block_type); + LLVMTypeKind variant_kind = LLVMGetTypeKind(llvm_variant_type); - if (LLVMGetTypeKind(block_type) == LLVMArrayTypeKind && - LLVMGetTypeKind(llvm_variant_type) == LLVMIntegerTypeKind) { + if (block_size != variant_size) { + if (block_kind == LLVMArrayTypeKind) { LLVMTypeRef elem = LLVMGetElementType(block_type); unsigned count = LLVMGetArrayLength(block_type); - if (elem == llvm_variant_type) { - LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = variant_value; - for (unsigned j = 1; j < count; j++) { - elems[j] = LLVMConstNull(elem); - } - block_value = LLVMConstArray(elem, elems, count); - - goto assign_value_wrapped; - } else if (!is_type_different_to_arch_endianness(variant_type)) { - i64 elem_size = lb_sizeof(elem); - i64 variant_size = lb_sizeof(llvm_variant_type); - if (elem_size > variant_size) { - u64 val = LLVMConstIntGetZExtValue(variant_value); + if (variant_kind == LLVMIntegerTypeKind) { + if (elem == llvm_variant_type) { LLVMValueRef *elems = temporary_alloc_array(count); - elems[0] = LLVMConstInt(elem, val, false); + elems[0] = variant_value; for (unsigned j = 1; j < count; j++) { elems[j] = LLVMConstNull(elem); } block_value = LLVMConstArray(elem, elems, count); - goto assign_value_wrapped; + } else if (!is_type_different_to_arch_endianness(variant_type)) { + i64 elem_size = lb_sizeof(elem); + i64 variant_size = lb_sizeof(llvm_variant_type); + if (elem_size > variant_size) { + u64 val = LLVMConstIntGetZExtValue(variant_value); + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + goto assign_value_wrapped; + } + } + } else if (!is_type_different_to_arch_endianness(variant_type)) { + switch (variant_kind) { + case LLVMHalfTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + u16 val = f32_to_f16(cast(f32)res); + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + goto assign_value_wrapped; + } + break; + case LLVMFloatTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f32 f; u32 i; } val = {}; + val.f = cast(f32)res; + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val.i, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + goto assign_value_wrapped; + } + break; + case LLVMDoubleTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f64 f; u64 i; } val = {}; + val.f = res; + + LLVMValueRef *elems = temporary_alloc_array(count); + elems[0] = LLVMConstInt(elem, val.i, false); + for (unsigned j = 1; j < count; j++) { + elems[j] = LLVMConstNull(elem); + } + block_value = LLVMConstArray(elem, elems, count); + goto assign_value_wrapped; + } + break; } } - } else if (LLVMGetTypeKind(block_type) == LLVMIntegerTypeKind && - LLVMGetTypeKind(llvm_variant_type) == LLVMIntegerTypeKind) { - if (!is_type_different_to_arch_endianness(variant_type)) { + + + } else if (block_kind == LLVMIntegerTypeKind && !is_type_different_to_arch_endianness(variant_type)) { + if (variant_kind == LLVMIntegerTypeKind) { i64 variant_size = lb_sizeof(llvm_variant_type); if (block_size > variant_size) { u64 val = LLVMConstIntGetZExtValue(variant_value); @@ -645,13 +778,48 @@ gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef vari goto assign_value_wrapped; } + } else { + switch (variant_kind) { + case LLVMHalfTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + u16 val = f32_to_f16(cast(f32)res); + + block_value = LLVMConstInt(block_type, val, false); + goto assign_value_wrapped; + } + break; + case LLVMFloatTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f32 f; u32 i; } val = {}; + val.f = cast(f32)res; + + block_value = LLVMConstInt(block_type, val.i, false); + goto assign_value_wrapped; + } + break; + case LLVMDoubleTypeKind: + { + LLVMBool loses = false; + f64 res = LLVMConstRealGetDouble(variant_value, &loses); + union { f64 f; u64 i; } val = {}; + val.f = res; + + block_value = LLVMConstInt(block_type, val.i, false); + goto assign_value_wrapped; + } + break; + } } } return nullptr; } - if (LLVMGetTypeKind(block_type) == LLVMIntegerTypeKind) { - switch (LLVMGetTypeKind(llvm_variant_type)) { + if (block_kind == LLVMIntegerTypeKind) { + switch (variant_kind) { case LLVMHalfTypeKind: case LLVMFloatTypeKind: case LLVMDoubleTypeKind: