aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2020-04-11 21:34:55 +0100
committergingerBill <bill@gingerbill.org>2020-04-11 21:34:55 +0100
commit90593fe6ae1a66ea5037140d14c7666fd073894c (patch)
tree9afa3504eed1addf0e1ef5f8e76dbd7a25dfacdc /src
parent16b4178b8a9bb132e4b2361b95b53f791162a445 (diff)
Endian specific floating point types (e.g. f32be)
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp6
-rw-r--r--src/checker.cpp3
-rw-r--r--src/ir.cpp87
-rw-r--r--src/ir_print.cpp38
-rw-r--r--src/types.cpp22
5 files changed, 150 insertions, 6 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index a9afbf8a4..12712443f 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -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;
diff --git a/src/checker.cpp b/src/checker.cpp
index 678339362..323adac2a 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -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]));
diff --git a/src/ir.cpp b/src/ir.cpp
index ecf911461..31d4036b1 100644
--- a/src/ir.cpp
+++ b/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:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 32cc3809d..ebb729420 100644
--- a/src/ir_print.cpp
+++ b/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_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;
diff --git a/src/types.cpp b/src/types.cpp
index 2ab0897da..52db2ee44 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -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;