Discussion:
[9fans] emulated fp on arm
(too old to reply)
erik quanstrom
2013-01-28 17:10:35 UTC
Permalink
here's a fix for the first issue. it is sufficient to catch the case above.
; diffy -c fpi.h
/n/dump/2013/0125/sys/src/9/omap/fpi.h:37,43 - fpi.h:37,43
#define SetQNaN(n) ((n)->s = 0, (n)->e = ExpInfinity, \
(n)->h = HiddenBit|(LsBit<<1), (n)->l = 0)
#define IsZero(n) ((n)->e == 1 && (n)->h == 0 && (n)->l == 0)
- #define SetZero(n) ((n)->e = 1, (n)->h = 0, (n)->l = 0)
+ #define SetZero(n) ((n)->s = 0, (n)->e = 1, (n)->h = 0, (n)->l = 0)
i was looking for a little input before submitting.
does anyone see an issue with this?

- erik
Richard Miller
2013-01-29 22:10:55 UTC
Permalink
i'm not a fp expert, but i think there are two problems here. first
it is bad form to generate -0 in the emulator, even if it is technically
correct, and second, -0 is defined to be equal to 0 by the spec, so
-0 == 0 should always be true.
I think you're right on the second point (I haven't read the IEEE spec
lately, just looked at wikipedia), and wrong on the first. IEEE fp
definitely allows for positive and negative zero, so the emulator should
be generating them when the spec calls for them to do so.

I hope we will soon be emulating vfp floating point instead of the old
arm7500 architecture.
erik quanstrom
2013-01-29 22:44:16 UTC
Permalink
Post by Richard Miller
i'm not a fp expert, but i think there are two problems here. first
it is bad form to generate -0 in the emulator, even if it is technically
correct, and second, -0 is defined to be equal to 0 by the spec, so
-0 == 0 should always be true.
I think you're right on the second point (I haven't read the IEEE spec
lately, just looked at wikipedia), and wrong on the first. IEEE fp
definitely allows for positive and negative zero, so the emulator should
be generating them when the spec calls for them to do so.
you might be right about the first point, but i'm really having a hard
time sorting this out. i don't have the standard, and it's $85.
this wiki page says there are some rules funny rules for addition/subtraction:
http://en.wikipedia.org/wiki/Signed_zero#Arithmetic

here's what i have with the as-is fpi

; for(i in ocilla ladd kw)cpu -h $i -c /tmp/awktest
Xeon -1 + 1 = 0 cmp 0 ok; cmp -0 ok
1 + -1 = 0 cmp 0 ok; cmp -0 ok
Atom -1 + 1 = 0 cmp 0 ok; cmp -0 ok
1 + -1 = 0 cmp 0 ok; cmp -0 ok
ARM -1 + 1 = -0 cmp 0 fail; cmp -0 fail
1 + -1 = 0 cmp 0 ok; cmp -0 ok
; and gcc/amd64 + gawk
-1 + 1 = 0 cmp 0 ok; cmp -0 ok

if you tell gawk you've got -0, it ignores the sign.
in the c world, i couldn't get the same behavior
no matter what i set the rounding mode to.
(the instruction used is ADDSD.)
Post by Richard Miller
I hope we will soon be emulating vfp floating point instead of the old
arm7500 architecture.
yes!

the fpi guts are independent of the emulation on top, aren't they?
i haven't looked too carefully at the inteface.

- erik

---
; gcc -c -ggdb -Iplan9/include wierd.c # no optimization
; 9l wierd.o
; ./a.out
0000 0 0.000000
0800 0 0.000000
0400 0 0.000000
0c00 0 0.000000
; cat wierd.c
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include <fenv.h>

int tab[] = {
FE_TONEAREST,
FE_DOWNWARD,
FE_UPWARD,
FE_TOWARDZERO,
};

void
main(void)
{
int i;
double d;

for(i = 0; i < nelem(tab); i++){
if(fesetround(tab[i]) != 0)
print("can't set mode %d\n", i);

d = -1.;
d += 1.;

print("%.4ux %g %f\n", fegetround(), d, d );
}

exits("");
}
Richard Miller
2013-01-30 10:35:56 UTC
Permalink
Post by erik quanstrom
ARM -1 + 1 = -0 cmp 0 fail; cmp -0 fail
1 + -1 = 0 cmp 0 ok; cmp -0 ok
I know floating point add isn't associative, but I thought it was at
least meant to be commutative. The bug may not be where you think.
Post by erik quanstrom
the fpi guts are independent of the emulation on top, aren't they?
More or less. There's the question of how many secret extra bits
of precision to maintain internally, beyond the ones you get when
you store from a register.
Bakul Shah
2013-01-30 22:18:45 UTC
Permalink
Post by erik quanstrom
Post by Richard Miller
i'm not a fp expert, but i think there are two problems here. first
it is bad form to generate -0 in the emulator, even if it is technically
correct, and second, -0 is defined to be equal to 0 by the spec, so
-0 == 0 should always be true.
I think you're right on the second point (I haven't read the IEEE spec
lately, just looked at wikipedia), and wrong on the first. IEEE fp
definitely allows for positive and negative zero, so the emulator should
be generating them when the spec calls for them to do so.
you might be right about the first point, but i'm really having a hard
time sorting this out. i don't have the standard, and it's $85.
this wiki page says there are some rules funny rules for addition/subtraction
http://en.wikipedia.org/wiki/Signed_zero#Arithmetic
here's what i have with the as-is fpi
; for(i in ocilla ladd kw)cpu -h $i -c /tmp/awktest
Xeon -1 + 1 = 0 cmp 0 ok; cmp -0 ok
1 + -1 = 0 cmp 0 ok; cmp -0 ok
Atom -1 + 1 = 0 cmp 0 ok; cmp -0 ok
1 + -1 = 0 cmp 0 ok; cmp -0 ok
ARM -1 + 1 = -0 cmp 0 fail; cmp -0 fail
1 + -1 = 0 cmp 0 ok; cmp -0 ok
; and gcc/amd64 + gawk
-1 + 1 = 0 cmp 0 ok; cmp -0 ok
As ieee754 (1985):

When the sum of two operands with opposite signs (or the
difference of two operands with like signs) is exactly zero,
the sign of that sum (or difference) shall be + in all
rounding modes except round toward -INFINITY, in which mode
that sign shall be -.
erik quanstrom
2013-01-31 03:50:49 UTC
Permalink
Post by Bakul Shah
When the sum of two operands with opposite signs (or the
difference of two operands with like signs) is exactly zero,
the sign of that sum (or difference) shall be + in all
rounding modes except round toward -INFINITY, in which mode
that sign shall be -.
due to the emulator interface, both cases call fpisub.
i've run a number of tests on this with relatively small
numbers that are equal. and this seems to solve the
problems without creating new ones.

- erik

; diff -c fpi.c /sys/src/9/omap
fpi.c:137,143 - /sys/src/9/omap/fpi.c:137,142
void
fpisub(Internal *x, Internal *y, Internal *i)
{
- int exact;
Internal *t;

if(y->e < x->e
fpi.c:158,164 - /sys/src/9/omap/fpi.c:157,162
SetInfinity(i);
return;
}
- exact = x->e == y->e;
matchexponents(x, y);
i->e = y->e;
i->h = y->h - x->h;
fpi.c:167,179 - /sys/src/9/omap/fpi.c:165,172
i->l += CarryBit;
i->h--;
}
- if(i->h == 0 && i->l == 0){
+ if(i->h == 0 && i->l == 0)
SetZero(i);
-
- /* canceling rule */
- if(x->s != y->s && exact)
- i->s = 0; /* 1 in round to -∞ mode */
- }
else while(i->e > 1 && (i->h & HiddenBit) == 0)
shift(i);
}

Loading...