Browse Source

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

gingerBill 5 years ago
parent
commit
90593fe6ae
9 changed files with 178 additions and 7 deletions
  1. 6 0
      core/fmt/fmt.odin
  2. 5 0
      core/reflect/types.odin
  3. 1 1
      core/runtime/core.odin
  4. 16 0
      core/runtime/internal.odin
  5. 6 0
      src/check_expr.cpp
  6. 3 0
      src/checker.cpp
  7. 83 4
      src/ir.cpp
  8. 36 2
      src/ir_print.cpp
  9. 22 0
      src/types.cpp

+ 6 - 0
core/fmt/fmt.odin

@@ -1802,6 +1802,12 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 	case f32:        fmt_float(fi, f64(a), 32, verb);
 	case f32:        fmt_float(fi, f64(a), 32, verb);
 	case f64:        fmt_float(fi, a,      64, 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 complex64:  fmt_complex(fi, complex128(a), 64, verb);
 	case complex128: fmt_complex(fi, a, 128, verb);
 	case complex128: fmt_complex(fi, a, 128, verb);
 
 

+ 5 - 0
core/reflect/types.odin

@@ -363,6 +363,11 @@ write_type :: proc(buf: ^strings.Builder, ti: ^Type_Info) {
 	case Type_Info_Float:
 	case Type_Info_Float:
 		write_byte(buf, 'f');
 		write_byte(buf, 'f');
 		write_i64(buf, i64(8*ti.size), 10);
 		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:
 	case Type_Info_Complex:
 		write_string(buf, "complex");
 		write_string(buf, "complex");
 		write_i64(buf, i64(8*ti.size), 10);
 		write_i64(buf, i64(8*ti.size), 10);

+ 1 - 1
core/runtime/core.odin

@@ -57,7 +57,7 @@ Type_Info_Struct_Soa_Kind :: enum u8 {
 Type_Info_Named      :: struct {name: string, base: ^Type_Info};
 Type_Info_Named      :: struct {name: string, base: ^Type_Info};
 Type_Info_Integer    :: struct {signed: bool, endianness: Platform_Endianness};
 Type_Info_Integer    :: struct {signed: bool, endianness: Platform_Endianness};
 Type_Info_Rune       :: struct {};
 Type_Info_Rune       :: struct {};
-Type_Info_Float      :: struct {};
+Type_Info_Float      :: struct {endianness: Platform_Endianness};
 Type_Info_Complex    :: struct {};
 Type_Info_Complex    :: struct {};
 Type_Info_Quaternion :: struct {};
 Type_Info_Quaternion :: struct {};
 Type_Info_String     :: struct {is_cstring: bool};
 Type_Info_String     :: struct {is_cstring: bool};

+ 16 - 0
core/runtime/internal.odin

@@ -18,6 +18,22 @@ bswap_128 :: proc "none" (x: u128) -> u128 {
 	return u128(bswap_64(u64(x))) | u128(bswap_64(u64(x>>64)));
 	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 {
 ptr_offset :: inline proc "contextless" (ptr: $P/^$T, n: int) -> P {
 	new := int(uintptr(ptr)) + size_of(T)*n;
 	new := int(uintptr(ptr)) + size_of(T)*n;
 	return P(uintptr(new));
 	return P(uintptr(new));

+ 6 - 0
src/check_expr.cpp

@@ -1455,6 +1455,12 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
 		case Basic_f64:
 		case Basic_f64:
 			return true;
 			return true;
 
 
+		case Basic_f32le:
+		case Basic_f64le:
+		case Basic_f32be:
+		case Basic_f64be:
+			return true;
+
 		case Basic_UntypedFloat:
 		case Basic_UntypedFloat:
 			return true;
 			return true;
 
 

+ 3 - 0
src/checker.cpp

@@ -1708,6 +1708,9 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 		str_lit("bswap_32"),
 		str_lit("bswap_32"),
 		str_lit("bswap_64"),
 		str_lit("bswap_64"),
 		str_lit("bswap_128"),
 		str_lit("bswap_128"),
+
+		str_lit("bswap_f32"),
+		str_lit("bswap_f64"),
 	};
 	};
 	for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
 	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]));
 		add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));

+ 83 - 4
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) {
 void ir_emit_defer_stmts(irProcedure *proc, irDeferExitKind kind, irBlock *block) {
 	isize count = proc->defer_stmts.count;
 	isize count = proc->defer_stmts.count;
 	isize i = count;
 	isize i = count;
@@ -4320,8 +4319,18 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 			goto handle_op;
 			goto handle_op;
 		}
 		}
 		Type *platform_type = integer_endian_type_to_platform_type(type);
 		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);
 		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);
 			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, 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));
 	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;
 		return value;
 	}
 	}
 	GB_ASSERT(type_size_of(vt) == type_size_of(t));
 	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));
 	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
 	// float -> float
 	if (is_type_float(src) && is_type_float(dst)) {
 	if (is_type_float(src) && is_type_float(dst)) {
+		GB_ASSERT(!are_types_identical(src, dst));
 		gbAllocator a = ir_allocator();
 		gbAllocator a = ir_allocator();
 		i64 sz = type_size_of(src);
 		i64 sz = type_size_of(src);
 		i64 dz = type_size_of(dst);
 		i64 dz = type_size_of(dst);
 		irConvKind kind = irConv_fptrunc;
 		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) {
 		if (dz >= sz) {
 			kind = irConv_fpext;
 			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));
 		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);
 		irValue *ptr = ir_emit_uintptr_to_ptr(proc, value, t_rawptr);
 		return ir_emit_bitcast(proc, ptr, dst);
 		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))) {
 	if (is_type_integer(src) && (is_type_pointer(dst) || is_type_cstring(dst))) {
 		Type *vt = core_type(ir_type(value));
 		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_f16:
 			case Basic_f32:
 			case Basic_f32:
 			case Basic_f64:
 			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;
 				break;
 
 
+
 			// case Basic_complex32:
 			// case Basic_complex32:
 			case Basic_complex64:
 			case Basic_complex64:
 			case Basic_complex128:
 			case Basic_complex128:

+ 36 - 2
src/ir_print.cpp

@@ -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_f32:    ir_write_str_lit(f, "float");                   return;
 		case Basic_f64:    ir_write_str_lit(f, "double");                  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_complex32:  ir_write_str_lit(f, "%%..complex32");    return;
 		case Basic_complex64:  ir_write_str_lit(f, "%..complex64");        return;
 		case Basic_complex64:  ir_write_str_lit(f, "%..complex64");        return;
 		case Basic_complex128: ir_write_str_lit(f, "%..complex128");       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);
 		type = core_type(type);
 		u64 u_64 = bit_cast<u64>(value.value_float);
 		u64 u_64 = bit_cast<u64>(value.value_float);
 		u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
 		u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
+
+
 	#if 0
 	#if 0
 		switch (type->Basic.kind) {
 		switch (type->Basic.kind) {
 		case Basic_f32:
 		case Basic_f32:
@@ -861,13 +870,38 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 		}
 		}
 	#else
 	#else
 		switch (type->Basic.kind) {
 		switch (type->Basic.kind) {
-		case Basic_f32: {
+		case Basic_f32:
 			ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
 			ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
 			break;
 			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:
 		case Basic_f64:
 			ir_fprintf(f, "0x%016llx", u_64);
 			ir_fprintf(f, "0x%016llx", u_64);
 			break;
 			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:
 		default:
 			ir_fprintf(f, "0x%016llx", u_64);
 			ir_fprintf(f, "0x%016llx", u_64);
 			break;
 			break;

+ 22 - 0
src/types.cpp

@@ -64,6 +64,12 @@ enum BasicKind {
 	Basic_i128be,
 	Basic_i128be,
 	Basic_u128be,
 	Basic_u128be,
 
 
+	Basic_f32le,
+	Basic_f64le,
+
+	Basic_f32be,
+	Basic_f64be,
+
 	// Untyped types
 	// Untyped types
 	Basic_UntypedBool,
 	Basic_UntypedBool,
 	Basic_UntypedInteger,
 	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_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_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
 	// Untyped types
 	{Type_Basic, {Basic_UntypedBool,       BasicFlag_Boolean    | BasicFlag_Untyped,   0, STR_LIT("untyped bool")}},
 	{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")}},
 	{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);
 	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) {
 bool is_type_dereferenceable(Type *t) {
 	if (is_type_rawptr(t)) {
 	if (is_type_rawptr(t)) {
 		return false;
 		return false;
@@ -1357,6 +1374,11 @@ Type *integer_endian_type_to_platform_type(Type *t) {
 	case Basic_u32be: return t_u32;
 	case Basic_u32be: return t_u32;
 	case Basic_i64be: return t_i64;
 	case Basic_i64be: return t_i64;
 	case Basic_u64be: return t_u64;
 	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;
 	return t;