summaryrefslogtreecommitdiff
path: root/sys/src/libc
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2022-12-30 18:36:13 +0000
committercinap_lenrek <cinap_lenrek@felloff.net>2022-12-30 18:36:13 +0000
commitba66d8f69edd895682f2661524a1d07612cb9ba8 (patch)
treed4c3148f88daf09d21eedbd87609b05e0e4777a4 /sys/src/libc
parentb81609d071833c6d950af7a4efac53af86c7c276 (diff)
libc: fix 32-bit arch vlong->double conversion (thans cosa)
Cosa wrote: While trying to run kvik's lu9 on ARM, I found that when converting LLONG_MIN to a double on 32bit systems, the result is wrong (positive instead of negative). Given the following test program: void main() { vlong min = LLONG_MIN; double dmin = min; print("minint %lld\n", min); print("minint as double %f\n", dmin); if (dmin > 0.0) { exits("int min as double turned positive"); } exits(0); } The output on x86_64 will be: minint -9223372036854775808 minint as double -9223372036854776400.000000 But on arm or 386 (and I expect also spim, 68000, mips, 68020, sparc, power, since they all use the same _v2d): minint -9223372036854775808 minint as double 9223372036854776400.000000 And the value turned positive in the conversion. The function used for the cast to double is (in /sys/src/libc/arm/vlrt.c): double _v2d(Vlong x) { if(x.hi & SIGN(32)) { if(x.lo) { x.lo = -x.lo; x.hi = ~x.hi; } else x.hi = -x.hi; return -((long)x.hi*4294967296. + x.lo); } return (long)x.hi*4294967296. + x.lo; } If I understand correctly, the issue is that where it tries to flip the sign for x.hi (x.hi = -x.hi), 0x80000000 has no positive, thus stays the same (it stays negative). Then when we get to the negative return, we get a positive out. What came to my mind then, is that in the case that there is no x.lo, we can keep the x.hi sign and cast directly, thus: double _v2d(Vlong x) {     if(!x.lo) {         return (long)x.hi*4294967296.;     }     if(x.hi & SIGN(32)) {         x.lo = -x.lo;         x.hi = ~x.hi;         return -((long)x.hi*4294967296. + x.lo);     }     return (long)x.hi*4294967296. + x.lo; } This looks correct to me, but I don't trust myself to not make mistakes in such critical code, so I would like some feedback on the change. Happy new year in advance, cosa
Diffstat (limited to 'sys/src/libc')
-rw-r--r--sys/src/libc/386/vlrt.c10
-rw-r--r--sys/src/libc/68000/vlrt.c10
-rw-r--r--sys/src/libc/68020/vlrt.c10
-rw-r--r--sys/src/libc/arm/vlrt.c10
-rw-r--r--sys/src/libc/mips/vlrt.c10
-rw-r--r--sys/src/libc/power/vlrt.c10
-rw-r--r--sys/src/libc/sparc/vlrt.c10
-rw-r--r--sys/src/libc/spim/vlrt.c10
8 files changed, 40 insertions, 40 deletions
diff --git a/sys/src/libc/386/vlrt.c b/sys/src/libc/386/vlrt.c
index 132a04f99..b27705baf 100644
--- a/sys/src/libc/386/vlrt.c
+++ b/sys/src/libc/386/vlrt.c
@@ -95,12 +95,12 @@ _f2v(Vlong *y, float f)
double
_v2d(Vlong x)
{
+ if(!x.lo) {
+ return (long)x.hi*4294967296.;
+ }
if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
return -((long)x.hi*4294967296. + x.lo);
}
return (long)x.hi*4294967296. + x.lo;
diff --git a/sys/src/libc/68000/vlrt.c b/sys/src/libc/68000/vlrt.c
index 646c1796f..12975b656 100644
--- a/sys/src/libc/68000/vlrt.c
+++ b/sys/src/libc/68000/vlrt.c
@@ -120,12 +120,12 @@ _f2v(Vlong *y, float f)
double
_v2d(Vlong x)
{
+ if(!x.lo) {
+ return (long)x.hi*4294967296.;
+ }
if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
return -((long)x.hi*4294967296. + x.lo);
}
return (long)x.hi*4294967296. + x.lo;
diff --git a/sys/src/libc/68020/vlrt.c b/sys/src/libc/68020/vlrt.c
index 629449c24..bbd4179e7 100644
--- a/sys/src/libc/68020/vlrt.c
+++ b/sys/src/libc/68020/vlrt.c
@@ -120,12 +120,12 @@ _f2v(Vlong *y, float f)
double
_v2d(Vlong x)
{
+ if(!x.lo) {
+ return (long)x.hi*4294967296.;
+ }
if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
return -((long)x.hi*4294967296. + x.lo);
}
return (long)x.hi*4294967296. + x.lo;
diff --git a/sys/src/libc/arm/vlrt.c b/sys/src/libc/arm/vlrt.c
index 606d5dfd1..aa0a8874c 100644
--- a/sys/src/libc/arm/vlrt.c
+++ b/sys/src/libc/arm/vlrt.c
@@ -80,12 +80,12 @@ _f2v(Vlong *y, float f)
double
_v2d(Vlong x)
{
+ if(!x.lo) {
+ return (long)x.hi*4294967296.;
+ }
if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
return -((long)x.hi*4294967296. + x.lo);
}
return (long)x.hi*4294967296. + x.lo;
diff --git a/sys/src/libc/mips/vlrt.c b/sys/src/libc/mips/vlrt.c
index 81eaec7c7..a8725d89f 100644
--- a/sys/src/libc/mips/vlrt.c
+++ b/sys/src/libc/mips/vlrt.c
@@ -123,12 +123,12 @@ _f2v(Vlong *y, float f)
double
_v2d(Vlong x)
{
+ if(!x.lo) {
+ return (long)x.hi*4294967296.;
+ }
if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
return -((long)x.hi*4294967296. + x.lo);
}
return (long)x.hi*4294967296. + x.lo;
diff --git a/sys/src/libc/power/vlrt.c b/sys/src/libc/power/vlrt.c
index e9fd3e8bf..9283c8e9c 100644
--- a/sys/src/libc/power/vlrt.c
+++ b/sys/src/libc/power/vlrt.c
@@ -82,12 +82,12 @@ _f2v(Vlong *y, float f)
double
_v2d(Vlong x)
{
+ if(!x.lo) {
+ return (long)x.hi*4294967296.;
+ }
if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
return -((long)x.hi*4294967296. + x.lo);
}
return (long)x.hi*4294967296. + x.lo;
diff --git a/sys/src/libc/sparc/vlrt.c b/sys/src/libc/sparc/vlrt.c
index c1183beb9..2cc9ca500 100644
--- a/sys/src/libc/sparc/vlrt.c
+++ b/sys/src/libc/sparc/vlrt.c
@@ -124,12 +124,12 @@ _f2v(Vlong *y, float f)
double
_v2d(Vlong x)
{
+ if(!x.lo) {
+ return (long)x.hi*4294967296.;
+ }
if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
return -((long)x.hi*4294967296. + x.lo);
}
return (long)x.hi*4294967296. + x.lo;
diff --git a/sys/src/libc/spim/vlrt.c b/sys/src/libc/spim/vlrt.c
index cfa7e4ca7..1f5c629fd 100644
--- a/sys/src/libc/spim/vlrt.c
+++ b/sys/src/libc/spim/vlrt.c
@@ -123,12 +123,12 @@ _f2v(Vlong *y, float f)
double
_v2d(Vlong x)
{
+ if(!x.lo) {
+ return (long)x.hi*4294967296.;
+ }
if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
return -((long)x.hi*4294967296. + x.lo);
}
return (long)x.hi*4294967296. + x.lo;