Skip to content

Commit

Permalink
Fix displaying negative numbers in emacs
Browse files Browse the repository at this point in the history
It tests for whether a number is NaN by testing whether !(x * 0 >= 0),
and this was passing for all negative numbers because -0 was considered
less than and equal to 0.

Also fix some UBsan things

Fixed #749
  • Loading branch information
tbodt committed May 31, 2020
1 parent 52ebee6 commit 1946585
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 18 deletions.
16 changes: 10 additions & 6 deletions emu/float80-test.c
Expand Up @@ -11,6 +11,8 @@
int deconst_dummy;
#define deconst(x) (deconst_dummy? 0 : x)

#define neg(x) (x == 0 ? -1e-200/1e200 : -x)

union f80 {
float80 f;
long double ld;
Expand Down Expand Up @@ -156,9 +158,9 @@ void test_math() {
assertf(bitwise_eq(u.ld, expected) || (isnan(u.ld) && isnan(expected)) || (ua.ld == 0 && ub.ld == 0 && u.ld == 0 && expected == 0), "f80_"#op"(%.20Le, %.20Le) = %.20Le (%.20Le)", ua.ld, ub.ld, u.ld, expected)
#define test(op, a, b) \
_test(op, a, b); \
_test(op, -a, b); \
_test(op, a, -b); \
_test(op, -a, -b)
_test(op, neg(a), b); \
_test(op, a, neg(b)); \
_test(op, neg(a), neg(b))

test(add, 1, 1);
test(add, 123, 123);
Expand Down Expand Up @@ -226,20 +228,22 @@ void test_compare() {
assertf(actual == expected, "f80_"#op"(%Le, %Le) = %s", ua.ld, ub.ld, actual ? "true" : "false")
#define test(op, a, b) \
_test(op, a, b); \
_test(op, -a, b); \
_test(op, a, -b); \
_test(op, -a, -b)
_test(op, neg(a), b); \
_test(op, a, neg(b)); \
_test(op, neg(a), neg(b))

test(eq, 0, 0);
test(eq, 1, 1);
test(eq, 0, 1);
test(eq, 1, 0);
test(eq, INFINITY, INFINITY);
test(eq, 1, INFINITY);
test(eq, NAN, 123);
test(eq, NAN, NAN);
test(lt, 0, 0);
test(lt, 1, 1);
test(lt, 0, 1);
test(lt, 1, 0);
test(lt, INFINITY, INFINITY);
test(lt, 1, INFINITY);
test(lt, NAN, 123);
Expand Down
29 changes: 18 additions & 11 deletions emu/float80.c
Expand Up @@ -123,8 +123,10 @@ static float80 f80_normalize(float80 f) {
return f;
// shift left as many times as possible without overflow
// number of leading zeroes = how many times we can shift out a leading digit before overflow
int shift = __builtin_clzl(f.signif);
if (f.signif == 0)
int shift;
if (f.signif != 0)
shift = __builtin_clzl(f.signif);
else
shift = 64; // __builtin_clzl has undefined result with zero
if (f.exp - shift < EXP_MIN) {
// if we shifted this much, exponent would go below its minimum
Expand All @@ -138,10 +140,12 @@ static float80 f80_normalize(float80 f) {

static int u128_clz(uint128_t x) {
// correctly counting leading zeros on a 128-bit int is interesting
int zeros = __builtin_clzl((uint64_t) (x >> 64));
if (x >> 64 == 0)
int zeros;
if (x >> 64 != 0)
zeros = __builtin_clzl((uint64_t) (x >> 64));
else if (x != 0)
zeros = 64 + __builtin_clzl((uint64_t) x);
if (x == 0)
else
zeros = 128;
return zeros;
}
Expand Down Expand Up @@ -198,7 +202,7 @@ float80 f80_from_int(int64_t i) {
f.exp = 0;
if (i < 0) {
f.sign = 1;
f.signif = -i;
f.signif = -(uint64_t) i;
}
return f80_normalize(f);
}
Expand Down Expand Up @@ -460,9 +464,12 @@ float80 f80_div(float80 a, float80 b) {
uint128_t signif = ((uint128_t) a.signif << 64) / b.signif;
uint128_t remainder = ((uint128_t) a.signif << 64) % b.signif;
// extend this to 128 bit precision because hell yeah
int extra_bits = u128_clz(signif);
signif <<= extra_bits;
signif |= (remainder << extra_bits) / b.signif;
int extra_bits = 0;
if (signif != 0) {
extra_bits = u128_clz(signif);
signif <<= extra_bits;
signif |= (remainder << extra_bits) / b.signif;
}
int exp = unbias_denormal(a.exp) - unbias_denormal(b.exp) + 63 - b_trailing - extra_bits;
f = u128_normalize_round(signif, exp, a.sign ^ b.sign);
}
Expand Down Expand Up @@ -495,8 +502,8 @@ bool f80_lt(float80 a, float80 b) {
if (f80_isinf(a) && f80_isinf(b) && a.sign == b.sign)
return false;
// zeroes are always equal
if (f80_iszero(a) && f80_iszero(b) && a.sign != b.sign)
return true;
if (f80_iszero(a) && f80_iszero(b))
return false;
// if a < b then a - b < 0
float80 diff = f80_sub(a, b);
return diff.sign == 1 && !f80_iszero(diff);
Expand Down
2 changes: 1 addition & 1 deletion fs/poll.h
Expand Up @@ -65,7 +65,7 @@ struct poll_fd {
#define POLL_HUP 16
#define POLL_NVAL 32
#define POLL_ONESHOT (1 << 30)
#define POLL_EDGETRIGGERED (1 << 31)
#define POLL_EDGETRIGGERED (1ul << 31)
struct poll_event {
struct fd *fd;
int types;
Expand Down

0 comments on commit 1946585

Please sign in to comment.