diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 5bb0f18de..13191e07c 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -672,3 +672,88 @@ gnu_f2h_ieee :: proc "c" (value: f32) -> u16 { extendhfsf2 :: proc "c" (value: u16) -> f32 { return gnu_h2f_ieee(value); } + + + +@(link_name="__floattidf") +floattidf :: proc(a: i128) -> f64 { + DBL_MANT_DIG :: 53; + if a == 0 { + return 0.0; + } + a := a; + N :: size_of(i128) * 8; + s := a >> (N-1); + a = (a ~ s) - s; + sd: = N - intrinsics.count_leading_zeros(a); // number of significant digits + e := u32(sd - 1); // exponent + if sd > DBL_MANT_DIG { + switch sd { + case DBL_MANT_DIG + 1: + a <<= 1; + case DBL_MANT_DIG + 2: + // okay + case: + a = i128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) | + i128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0); + }; + + a |= i128((a & 4) != 0); + a += 1; + a >>= 2; + + if a & (1 << DBL_MANT_DIG) != 0 { + a >>= 1; + e += 1; + } + } else { + a <<= u128(DBL_MANT_DIG - sd); + } + fb: [2]u32; + fb[1] = (u32(s) & 0x80000000) | // sign + ((e + 1023) << 20) | // exponent + u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high + fb[1] = u32(a); // mantissa-low + return transmute(f64)fb; +} + + +@(link_name="__floattidf_unsigned") +floattidf_unsigned :: proc(a: u128) -> f64 { + DBL_MANT_DIG :: 53; + if a == 0 { + return 0.0; + } + a := a; + N :: size_of(u128) * 8; + sd: = N - intrinsics.count_leading_zeros(a); // number of significant digits + e := u32(sd - 1); // exponent + if sd > DBL_MANT_DIG { + switch sd { + case DBL_MANT_DIG + 1: + a <<= 1; + case DBL_MANT_DIG + 2: + // okay + case: + a = u128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) | + u128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0); + }; + + a |= u128((a & 4) != 0); + a += 1; + a >>= 2; + + if a & (1 << DBL_MANT_DIG) != 0 { + a >>= 1; + e += 1; + } + } else { + a <<= u128(DBL_MANT_DIG - sd); + } + fb: [2]u32; + fb[1] = (0) | // sign + ((e + 1023) << 20) | // exponent + u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high + fb[1] = u32(a); // mantissa-low + return transmute(f64)fb; +} diff --git a/core/runtime/internal_linux.odin b/core/runtime/internal_linux.odin index 19b52a42a..ad46f55e8 100644 --- a/core/runtime/internal_linux.odin +++ b/core/runtime/internal_linux.odin @@ -87,45 +87,3 @@ fixdfti :: proc(a: u64) -> i128 { } } - -@(link_name="__floattidf") -floattidf :: proc(a: i128) -> f64 { - DBL_MANT_DIG :: 53; - if a == 0 { - return 0.0; - } - a := a; - N :: size_of(i128) * 8; - s := a >> (N-1); - a = (a ~ s) - s; - sd: = N - intrinsics.count_leading_zeros(a); // number of significant digits - e := u32(sd - 1); // exponent - if sd > DBL_MANT_DIG { - switch sd { - case DBL_MANT_DIG + 1: - a <<= 1; - case DBL_MANT_DIG + 2: - // okay - case: - a = i128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) | - i128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0); - }; - - a |= i128((a & 4) != 0); - a += 1; - a >>= 2; - - if a & (1 << DBL_MANT_DIG) != 0 { - a >>= 1; - e += 1; - } - } else { - a <<= u128(DBL_MANT_DIG - sd); - } - fb: [2]u32; - fb[1] = (u32(s) & 0x80000000) | // sign - ((e + 1023) << 20) | // exponent - u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high - fb[1] = u32(a); // mantissa-low - return transmute(f64)fb; -} diff --git a/core/runtime/internal_windows.odin b/core/runtime/internal_windows.odin index d7f00d155..2d3009eea 100644 --- a/core/runtime/internal_windows.odin +++ b/core/runtime/internal_windows.odin @@ -87,45 +87,3 @@ fixdfti :: proc(a: u64) -> i128 { } } - -@(link_name="__floattidf") -floattidf :: proc(a: i128) -> f64 { - DBL_MANT_DIG :: 53; - if a == 0 { - return 0.0; - } - a := a; - N :: size_of(i128) * 8; - s := a >> (N-1); - a = (a ~ s) - s; - sd: = N - intrinsics.count_leading_zeros(a); // number of significant digits - e := u32(sd - 1); // exponent - if sd > DBL_MANT_DIG { - switch sd { - case DBL_MANT_DIG + 1: - a <<= 1; - case DBL_MANT_DIG + 2: - // okay - case: - a = i128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) | - i128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0); - }; - - a |= i128((a & 4) != 0); - a += 1; - a >>= 2; - - if a & (1 << DBL_MANT_DIG) != 0 { - a >>= 1; - e += 1; - } - } else { - a <<= u128(DBL_MANT_DIG - sd); - } - fb: [2]u32; - fb[1] = (u32(s) & 0x80000000) | // sign - ((e + 1023) << 20) | // exponent - u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high - fb[1] = u32(a); // mantissa-low - return transmute(f64)fb; -} diff --git a/src/checker.cpp b/src/checker.cpp index 092d7bc31..2792bdece 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1751,6 +1751,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("divti3"), str_lit("fixdfti"), str_lit("floattidf"), + str_lit("floattidf_unsigned"), str_lit("truncsfhf2"), str_lit("truncdfhf2"), str_lit("gnu_h2f_ieee"), diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 505d45b93..a4e6ddbe5 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -7821,6 +7821,17 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return lb_emit_conv(p, res, t); } + if (is_type_integer_128bit(src)) { + auto args = array_make(temporary_allocator(), 1); + args[0] = value; + char const *call = "floattidf"; + if (is_type_unsigned(src)) { + call = "floattidf_unsigned"; + } + lbValue res_f64 = lb_emit_runtime_call(p, call, args); + return lb_emit_conv(p, res_f64, t); + } + lbValue res = {}; res.type = t; if (is_type_unsigned(src)) {