Endian specific floating point types (e.g. f32be)

This commit is contained in:
gingerBill
2020-04-11 21:34:55 +01:00
parent 16b4178b8a
commit 90593fe6ae
9 changed files with 178 additions and 7 deletions

View File

@@ -3297,7 +3297,6 @@ irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char
}
void ir_emit_defer_stmts(irProcedure *proc, irDeferExitKind kind, irBlock *block) {
isize count = proc->defer_stmts.count;
isize i = count;
@@ -4320,8 +4319,18 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
goto handle_op;
}
Type *platform_type = integer_endian_type_to_platform_type(type);
irValue *x = ir_emit_byte_swap(proc, left, integer_endian_type_to_platform_type(t_left));
irValue *y = ir_emit_byte_swap(proc, right, integer_endian_type_to_platform_type(t_right));
irValue *x = ir_emit_conv(proc, left, integer_endian_type_to_platform_type(t_left));
irValue *y = ir_emit_conv(proc, right, integer_endian_type_to_platform_type(t_right));
irValue *res = ir_emit_arith(proc, op, x, y, platform_type);
return ir_emit_byte_swap(proc, res, type);
}
if (is_type_float(type) && is_type_different_to_arch_endianness(type)) {
Type *platform_type = integer_endian_type_to_platform_type(type);
irValue *x = ir_emit_conv(proc, left, integer_endian_type_to_platform_type(t_left));
irValue *y = ir_emit_conv(proc, right, integer_endian_type_to_platform_type(t_right));
irValue *res = ir_emit_arith(proc, op, x, y, platform_type);
@@ -4748,6 +4757,12 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
irValue *y = ir_emit_byte_swap(proc, right, platform_type);
return ir_emit(proc, ir_instr_binary_op(proc, op_kind, x, y, t_llvm_bool));
}
if (is_type_float(t) && is_type_different_to_arch_endianness(t)) {
Type *platform_type = integer_endian_type_to_platform_type(t);
irValue *x = ir_emit_byte_swap(proc, left, platform_type);
irValue *y = ir_emit_byte_swap(proc, right, platform_type);
return ir_emit(proc, ir_instr_binary_op(proc, op_kind, x, y, t_llvm_bool));
}
}
return ir_emit(proc, ir_instr_binary_op(proc, op_kind, left, right, t_llvm_bool));
@@ -5269,6 +5284,29 @@ irValue *ir_emit_byte_swap(irProcedure *proc, irValue *value, Type *t) {
return value;
}
GB_ASSERT(type_size_of(vt) == type_size_of(t));
if (is_type_float(t)) {
i64 sz = type_size_of(t);
auto args = array_make<irValue *>(ir_allocator(), 1);
args[0] = value;
char const *proc_name = nullptr;
switch (sz*8) {
case 32: proc_name = "bswap_f32"; break;
case 64: proc_name = "bswap_f64"; break;
}
GB_ASSERT(proc_name != nullptr);
String name = make_string_c(proc_name);
AstPackage *p = proc->module->info->runtime_package;
Entity *e = scope_lookup_current(p->scope, name);
irValue **found = map_get(&proc->module->values, hash_entity(e));
GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name));
irValue *gp = *found;
return ir_emit(proc, ir_instr_call(proc, gp, nullptr, args, t, nullptr, ProcInlining_none));
}
return ir_emit(proc, ir_instr_conv(proc, irConv_byteswap, value, vt, t));
}
@@ -5423,13 +5461,34 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
// float -> float
if (is_type_float(src) && is_type_float(dst)) {
GB_ASSERT(!are_types_identical(src, dst));
gbAllocator a = ir_allocator();
i64 sz = type_size_of(src);
i64 dz = type_size_of(dst);
irConvKind kind = irConv_fptrunc;
if (dz == sz) {
if (types_have_same_internal_endian(src, dst)) {
return ir_emit_transmute(proc, value, t);
} else {
return ir_emit_byte_swap(proc, value, t);
}
}
if (dz >= sz) {
kind = irConv_fpext;
}
if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) {
Type *platform_src_type = integer_endian_type_to_platform_type(src);
Type *platform_dst_type = integer_endian_type_to_platform_type(dst);
irValue *res = nullptr;
res = ir_emit_conv(proc, value, platform_src_type);
res = ir_emit_conv(proc, res, platform_dst_type);
if (is_type_different_to_arch_endianness(dst)) {
res = ir_emit_byte_swap(proc, res, t);
}
return ir_emit_conv(proc, res, t);
}
return ir_emit(proc, ir_instr_conv(proc, kind, value, src_type, t));
}
@@ -5738,6 +5797,9 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) {
irValue *ptr = ir_emit_uintptr_to_ptr(proc, value, t_rawptr);
return ir_emit_bitcast(proc, ptr, dst);
}
if (is_type_float(src) && is_type_float(dst)) {
return ir_emit_bitcast(proc, value, t);
}
if (is_type_integer(src) && (is_type_pointer(dst) || is_type_cstring(dst))) {
Type *vt = core_type(ir_type(value));
@@ -11441,9 +11503,26 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
// case Basic_f16:
case Basic_f32:
case Basic_f64:
tag = ir_emit_conv(proc, variant_ptr, t_type_info_float_ptr);
case Basic_f32le:
case Basic_f64le:
case Basic_f32be:
case Basic_f64be:
{
tag = ir_emit_conv(proc, variant_ptr, t_type_info_float_ptr);
// NOTE(bill): This is matches the runtime layout
u8 endianness_value = 0;
if (t->Basic.flags & BasicFlag_EndianLittle) {
endianness_value = 1;
} else if (t->Basic.flags & BasicFlag_EndianBig) {
endianness_value = 2;
}
irValue *endianness = ir_const_u8(endianness_value);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), endianness);
}
break;
// case Basic_complex32:
case Basic_complex64:
case Basic_complex128: