mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-13 06:43:35 +00:00
Endian specific floating point types (e.g. f32be)
This commit is contained in:
@@ -1802,6 +1802,12 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
case f32: fmt_float(fi, f64(a), 32, verb);
|
||||
case f64: fmt_float(fi, a, 64, verb);
|
||||
|
||||
case f32le: fmt_float(fi, f64(a), 32, verb);
|
||||
case f64le: fmt_float(fi, f64(a), 64, verb);
|
||||
|
||||
case f32be: fmt_float(fi, f64(a), 32, verb);
|
||||
case f64be: fmt_float(fi, f64(a), 64, verb);
|
||||
|
||||
case complex64: fmt_complex(fi, complex128(a), 64, verb);
|
||||
case complex128: fmt_complex(fi, a, 128, verb);
|
||||
|
||||
|
||||
@@ -363,6 +363,11 @@ write_type :: proc(buf: ^strings.Builder, ti: ^Type_Info) {
|
||||
case Type_Info_Float:
|
||||
write_byte(buf, 'f');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
switch info.endianness {
|
||||
case .Platform: // Okay
|
||||
case .Little: write_string(buf, "le");
|
||||
case .Big: write_string(buf, "be");
|
||||
}
|
||||
case Type_Info_Complex:
|
||||
write_string(buf, "complex");
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
|
||||
@@ -57,7 +57,7 @@ Type_Info_Struct_Soa_Kind :: enum u8 {
|
||||
Type_Info_Named :: struct {name: string, base: ^Type_Info};
|
||||
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness};
|
||||
Type_Info_Rune :: struct {};
|
||||
Type_Info_Float :: struct {};
|
||||
Type_Info_Float :: struct {endianness: Platform_Endianness};
|
||||
Type_Info_Complex :: struct {};
|
||||
Type_Info_Quaternion :: struct {};
|
||||
Type_Info_String :: struct {is_cstring: bool};
|
||||
|
||||
@@ -18,6 +18,22 @@ bswap_128 :: proc "none" (x: u128) -> u128 {
|
||||
return u128(bswap_64(u64(x))) | u128(bswap_64(u64(x>>64)));
|
||||
}
|
||||
|
||||
|
||||
bswap_f32 :: proc "none" (f: f32) -> f32 {
|
||||
x := transmute(u32)f;
|
||||
z := x>>24 | (x>>8)&0xff00 | (x<<8)&0xff0000 | x<<24;
|
||||
return transmute(f32)z;
|
||||
|
||||
}
|
||||
|
||||
bswap_f64 :: proc "none" (f: f64) -> f64 {
|
||||
x := transmute(u64)f;
|
||||
z := u64(bswap_32(u32(x))) | u64(bswap_32(u32(x>>32)));
|
||||
return transmute(f64)z;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ptr_offset :: inline proc "contextless" (ptr: $P/^$T, n: int) -> P {
|
||||
new := int(uintptr(ptr)) + size_of(T)*n;
|
||||
return P(uintptr(new));
|
||||
|
||||
@@ -1455,6 +1455,12 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
|
||||
case Basic_f64:
|
||||
return true;
|
||||
|
||||
case Basic_f32le:
|
||||
case Basic_f64le:
|
||||
case Basic_f32be:
|
||||
case Basic_f64be:
|
||||
return true;
|
||||
|
||||
case Basic_UntypedFloat:
|
||||
return true;
|
||||
|
||||
|
||||
@@ -1708,6 +1708,9 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
str_lit("bswap_32"),
|
||||
str_lit("bswap_64"),
|
||||
str_lit("bswap_128"),
|
||||
|
||||
str_lit("bswap_f32"),
|
||||
str_lit("bswap_f64"),
|
||||
};
|
||||
for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
|
||||
add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));
|
||||
|
||||
87
src/ir.cpp
87
src/ir.cpp
@@ -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:
|
||||
|
||||
@@ -449,6 +449,13 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
|
||||
case Basic_f32: ir_write_str_lit(f, "float"); return;
|
||||
case Basic_f64: ir_write_str_lit(f, "double"); return;
|
||||
|
||||
|
||||
case Basic_f32le: ir_write_str_lit(f, "float"); return;
|
||||
case Basic_f64le: ir_write_str_lit(f, "double"); return;
|
||||
|
||||
case Basic_f32be: ir_write_str_lit(f, "float"); return;
|
||||
case Basic_f64be: ir_write_str_lit(f, "double"); return;
|
||||
|
||||
// case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
|
||||
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
|
||||
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
|
||||
@@ -834,6 +841,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
type = core_type(type);
|
||||
u64 u_64 = bit_cast<u64>(value.value_float);
|
||||
u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
|
||||
|
||||
|
||||
#if 0
|
||||
switch (type->Basic.kind) {
|
||||
case Basic_f32:
|
||||
@@ -861,13 +870,38 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
}
|
||||
#else
|
||||
switch (type->Basic.kind) {
|
||||
case Basic_f32: {
|
||||
case Basic_f32:
|
||||
ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
|
||||
break;
|
||||
}
|
||||
case Basic_f32le:
|
||||
if (build_context.endian_kind != TargetEndian_Little) {
|
||||
u_32 = gb_endian_swap32(u_32);
|
||||
}
|
||||
ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
|
||||
break;
|
||||
case Basic_f32be:
|
||||
if (build_context.endian_kind != TargetEndian_Big) {
|
||||
u_32 = gb_endian_swap32(u_32);
|
||||
}
|
||||
ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
|
||||
break;
|
||||
|
||||
case Basic_f64:
|
||||
ir_fprintf(f, "0x%016llx", u_64);
|
||||
break;
|
||||
case Basic_f64le:
|
||||
if (build_context.endian_kind != TargetEndian_Little) {
|
||||
u_64 = gb_endian_swap64(u_64);
|
||||
}
|
||||
ir_fprintf(f, "0x%016llx", u_64);
|
||||
break;
|
||||
case Basic_f64be:
|
||||
if (build_context.endian_kind != TargetEndian_Big) {
|
||||
u_64 = gb_endian_swap64(u_64);
|
||||
}
|
||||
ir_fprintf(f, "0x%016llx", u_64);
|
||||
break;
|
||||
|
||||
default:
|
||||
ir_fprintf(f, "0x%016llx", u_64);
|
||||
break;
|
||||
|
||||
@@ -64,6 +64,12 @@ enum BasicKind {
|
||||
Basic_i128be,
|
||||
Basic_u128be,
|
||||
|
||||
Basic_f32le,
|
||||
Basic_f64le,
|
||||
|
||||
Basic_f32be,
|
||||
Basic_f64be,
|
||||
|
||||
// Untyped types
|
||||
Basic_UntypedBool,
|
||||
Basic_UntypedInteger,
|
||||
@@ -449,6 +455,12 @@ gb_global Type basic_types[] = {
|
||||
{Type_Basic, {Basic_i128be, BasicFlag_Integer | BasicFlag_EndianBig, 16, STR_LIT("i128be")}},
|
||||
{Type_Basic, {Basic_u128be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 16, STR_LIT("u128be")}},
|
||||
|
||||
{Type_Basic, {Basic_f32le, BasicFlag_Float | BasicFlag_EndianLittle, 4, STR_LIT("f32le")}},
|
||||
{Type_Basic, {Basic_f64le, BasicFlag_Float | BasicFlag_EndianLittle, 8, STR_LIT("f64le")}},
|
||||
|
||||
{Type_Basic, {Basic_f32be, BasicFlag_Float | BasicFlag_EndianBig, 4, STR_LIT("f32be")}},
|
||||
{Type_Basic, {Basic_f64be, BasicFlag_Float | BasicFlag_EndianBig, 8, STR_LIT("f64be")}},
|
||||
|
||||
// Untyped types
|
||||
{Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, 0, STR_LIT("untyped bool")}},
|
||||
{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}},
|
||||
@@ -1316,6 +1328,11 @@ bool is_type_endian_little(Type *t) {
|
||||
return is_type_integer_endian_little(t);
|
||||
}
|
||||
|
||||
bool types_have_same_internal_endian(Type *a, Type *b) {
|
||||
return is_type_endian_little(a) == is_type_endian_little(b);
|
||||
}
|
||||
|
||||
|
||||
bool is_type_dereferenceable(Type *t) {
|
||||
if (is_type_rawptr(t)) {
|
||||
return false;
|
||||
@@ -1357,6 +1374,11 @@ Type *integer_endian_type_to_platform_type(Type *t) {
|
||||
case Basic_u32be: return t_u32;
|
||||
case Basic_i64be: return t_i64;
|
||||
case Basic_u64be: return t_u64;
|
||||
|
||||
case Basic_f32le: return t_f32;
|
||||
case Basic_f32be: return t_f32;
|
||||
case Basic_f64le: return t_f64;
|
||||
case Basic_f64be: return t_f64;
|
||||
}
|
||||
|
||||
return t;
|
||||
|
||||
Reference in New Issue
Block a user