diff options
| author | gingerBill <bill@gingerbill.org> | 2020-04-11 21:51:43 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2020-04-11 21:51:43 +0100 |
| commit | 5157619eb7d0ab40d54cbc0562cc3ce4a5526e81 (patch) | |
| tree | 657678c700e8a934bcb9ae147b148214586ac878 /src/llvm_backend.cpp | |
| parent | 90593fe6ae1a66ea5037140d14c7666fd073894c (diff) | |
Support endian specific float on -llvm-api; fix unary `-` for endian floats
Diffstat (limited to 'src/llvm_backend.cpp')
| -rw-r--r-- | src/llvm_backend.cpp | 128 |
1 files changed, 115 insertions, 13 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 938d09a38..68d288799 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -681,6 +681,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Basic_f32: return LLVMFloatTypeInContext(ctx); case Basic_f64: return LLVMDoubleTypeInContext(ctx); + case Basic_f32le: return LLVMFloatTypeInContext(ctx); + case Basic_f64le: return LLVMDoubleTypeInContext(ctx); + + case Basic_f32be: return LLVMFloatTypeInContext(ctx); + case Basic_f64be: return LLVMDoubleTypeInContext(ctx); + // Basic_complex32, case Basic_complex64: { @@ -4077,7 +4083,11 @@ lbValue lb_const_bool(lbModule *m, Type *type, bool value) { } LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) { + GB_ASSERT(type_size_of(type) == 4); u32 u = bit_cast<u32>(f); + if (is_type_different_to_arch_endianness(type)) { + u = gb_endian_swap32(u); + } LLVMValueRef i = LLVMConstInt(LLVMInt32TypeInContext(m->ctx), u, false); return LLVMConstBitCast(i, lb_type(m, type)); } @@ -4437,7 +4447,13 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) { res.value = lb_const_f32(m, f, type); return res; } - res.value = LLVMConstReal(lb_type(m, original_type), value.value_float); + if (is_type_different_to_arch_endianness(type)) { + u64 u = bit_cast<u64>(value.value_float); + u = gb_endian_swap64(u); + res.value = LLVMConstReal(lb_type(m, original_type), bit_cast<f64>(u)); + } else { + res.value = LLVMConstReal(lb_type(m, original_type), value.value_float); + } return res; case ExactValue_Complex: { @@ -4927,6 +4943,16 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) return lb_emit_byte_swap(p, res, type); } + if (op == Token_Sub && is_type_float(type) && is_type_different_to_arch_endianness(type)) { + Type *platform_type = integer_endian_type_to_platform_type(type); + lbValue v = lb_emit_byte_swap(p, x, platform_type); + + lbValue res = {}; + res.value = LLVMBuildFNeg(p->builder, v.value, ""); + res.type = platform_type; + + return lb_emit_byte_swap(p, res, type); + } lbValue res = {}; @@ -5134,6 +5160,16 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty return lb_emit_byte_swap(p, res, type); } + if (is_type_float(type) && is_type_different_to_arch_endianness(type)) { + Type *platform_type = integer_endian_type_to_platform_type(type); + lbValue x = lb_emit_conv(p, lhs, integer_endian_type_to_platform_type(lhs.type)); + lbValue y = lb_emit_conv(p, rhs, integer_endian_type_to_platform_type(rhs.type)); + + lbValue res = lb_emit_arith(p, op, x, y, platform_type); + + return lb_emit_byte_swap(p, res, type); + } + handle_op: @@ -5563,6 +5599,31 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { i64 sz = type_size_of(src); i64 dz = type_size_of(dst); + + if (dz == sz) { + if (types_have_same_internal_endian(src, dst)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } else { + return lb_emit_byte_swap(p, value, t); + } + } + + 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); + lbValue res = {}; + res = lb_emit_conv(p, value, platform_src_type); + res = lb_emit_conv(p, res, platform_dst_type); + if (is_type_different_to_arch_endianness(dst)) { + res = lb_emit_byte_swap(p, res, t); + } + return lb_emit_conv(p, res, t); + } + + lbValue res = {}; res.type = t; @@ -7803,7 +7864,6 @@ LLVMValueRef lb_lookup_runtime_procedure(lbModule *m, String const &name) { lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type) { Type *vt = core_type(value.type); GB_ASSERT(type_size_of(vt) == type_size_of(platform_type)); - GB_ASSERT(is_type_integer(vt)); // TODO(bill): lb_emit_byte_swap lbValue res = {}; @@ -7812,17 +7872,29 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type) { int sz = cast(int)type_size_of(vt); if (sz > 1) { - String name = {}; - switch (sz) { - case 2: name = str_lit("bswap_16"); break; - case 4: name = str_lit("bswap_32"); break; - case 8: name = str_lit("bswap_64"); break; - case 16: name = str_lit("bswap_128"); break; - default: GB_PANIC("unhandled byteswap size"); break; - } - LLVMValueRef fn = lb_lookup_runtime_procedure(p->module, name); + if (is_type_float(platform_type)) { + String name = {}; + switch (sz) { + case 4: name = str_lit("bswap_f32"); break; + case 8: name = str_lit("bswap_f64"); break; + default: GB_PANIC("unhandled byteswap size"); break; + } + LLVMValueRef fn = lb_lookup_runtime_procedure(p->module, name); + res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, ""); + } else { + GB_ASSERT(is_type_integer(platform_type)); + String name = {}; + switch (sz) { + case 2: name = str_lit("bswap_16"); break; + case 4: name = str_lit("bswap_32"); break; + case 8: name = str_lit("bswap_64"); break; + case 16: name = str_lit("bswap_128"); break; + default: GB_PANIC("unhandled byteswap size"); break; + } + LLVMValueRef fn = lb_lookup_runtime_procedure(p->module, name); - res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, ""); + res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, ""); + } } return res; @@ -8248,6 +8320,12 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri lbValue y = lb_emit_byte_swap(p, right, platform_type); left = x; right = y; + } else if (is_type_float(t) && is_type_different_to_arch_endianness(t)) { + Type *platform_type = integer_endian_type_to_platform_type(t); + lbValue x = lb_emit_conv(p, left, platform_type); + lbValue y = lb_emit_conv(p, right, platform_type); + left = x; + right = y; } } @@ -10433,7 +10511,31 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da // case Basic_f16: case Basic_f32: case Basic_f64: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_float_ptr); + case Basic_f32le: + case Basic_f64le: + case Basic_f32be: + case Basic_f64be: + { + tag = lb_const_ptr_cast(m, 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; + } + lbValue endianness = lb_const_int(m, t_u8, endianness_value); + + LLVMValueRef vals[1] = { + endianness.value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } break; // case Basic_complex32: |