aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-06-06 12:35:38 +0100
committergingerBill <bill@gingerbill.org>2021-06-06 12:35:38 +0100
commit785c27daa7a84734c29dbbbb35d084dcdd8752f2 (patch)
treef558557d79a59d1ad012d6226df7d62fcf52862b
parent795a5910cf237b5ba6c5adcb33109b1e40a17976 (diff)
Fix 128-bit integer to float cast by explicitly calling the procedure direct; Fix #781
-rw-r--r--core/runtime/internal.odin85
-rw-r--r--core/runtime/internal_linux.odin42
-rw-r--r--core/runtime/internal_windows.odin42
-rw-r--r--src/checker.cpp1
-rw-r--r--src/llvm_backend.cpp11
5 files changed, 97 insertions, 84 deletions
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<lbValue>(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)) {