Skip to content

Commit 3393fcc

Browse files
committed
libgcc/m68k: Fixes for soft float
Check for non-zero denorm in __adddf3. Need to check both the upper and lower 32-bit chunks of a 64-bit float for a non-zero value when checking to see if the value is -0. Fix __addsf3 when the sum exponent is exactly 0xff to ensure that produces infinity and not nan. Handle converting NaN/inf values between formats. Handle underflow and overflow when truncating. Write a replacement for __fixxfsi so that it does not raise extra exceptions during an extra conversion from long double to double. Return correctly signed zero on float and double divide underflow Return positive qNaN instead of negative. Signed-off-by: Keith Packard <[email protected]>
1 parent d18296e commit 3393fcc

File tree

2 files changed

+143
-39
lines changed

2 files changed

+143
-39
lines changed

libgcc/config/m68k/fpgnulib.c

+130-32
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#define SIGNBIT 0x80000000L
5555
#define HIDDEN (1L << 23L)
5656
#define SIGN(fp) ((fp) & SIGNBIT)
57+
#define EXPMASK 0xFFL
5758
#define EXP(fp) (((fp) >> 23L) & 0xFF)
5859
#define MANT(fp) (((fp) & 0x7FFFFFL) | HIDDEN)
5960
#define PACK(s,e,m) ((s) | ((e) << 23L) | (m))
@@ -262,6 +263,9 @@ __extendsfdf2 (float a1)
262263
mant &= ~HIDDEN;
263264
}
264265
exp = exp - EXCESS + EXCESSD;
266+
/* Handle inf and NaN */
267+
if (exp == EXPMASK - EXCESS + EXCESSD)
268+
exp = EXPDMASK;
265269
dl.l.upper |= exp << 20;
266270
dl.l.upper |= mant >> 3;
267271
dl.l.lower = mant << 29;
@@ -295,40 +299,52 @@ __truncdfsf2 (double a1)
295299
/* shift double mantissa 6 bits so we can round */
296300
sticky |= mant & ((1 << 6) - 1);
297301
mant >>= 6;
298-
299-
/* Check for underflow and denormals. */
300-
if (exp <= 0)
302+
if (exp == EXPDMASK - EXCESSD + EXCESS)
303+
{
304+
exp = EXPMASK;
305+
mant = mant >> 1 | (mant & 1) | !!sticky;
306+
}
307+
else
301308
{
302-
if (exp < -24)
309+
/* Check for underflow and denormals. */
310+
if (exp <= 0)
303311
{
304-
sticky |= mant;
305-
mant = 0;
312+
if (exp < -24)
313+
{
314+
sticky |= mant;
315+
mant = 0;
316+
}
317+
else
318+
{
319+
sticky |= mant & ((1 << (1 - exp)) - 1);
320+
mant >>= 1 - exp;
321+
}
322+
exp = 0;
306323
}
307-
else
324+
325+
/* now round */
326+
shift = 1;
327+
if ((mant & 1) && (sticky || (mant & 2)))
308328
{
309-
sticky |= mant & ((1 << (1 - exp)) - 1);
310-
mant >>= 1 - exp;
311-
}
312-
exp = 0;
313-
}
314-
315-
/* now round */
316-
shift = 1;
317-
if ((mant & 1) && (sticky || (mant & 2)))
318-
{
319-
int rounding = exp ? 2 : 1;
329+
int rounding = exp ? 2 : 1;
320330

321-
mant += 1;
331+
mant += 1;
322332

323-
/* did the round overflow? */
324-
if (mant >= (HIDDEN << rounding))
333+
/* did the round overflow? */
334+
if (mant >= (HIDDEN << rounding))
335+
{
336+
exp++;
337+
shift = rounding;
338+
}
339+
}
340+
/* shift down */
341+
mant >>= shift;
342+
if (exp >= EXPMASK)
325343
{
326-
exp++;
327-
shift = rounding;
344+
exp = EXPMASK;
345+
mant = 0;
328346
}
329347
}
330-
/* shift down */
331-
mant >>= shift;
332348

333349
mant &= ~HIDDEN;
334350

@@ -432,8 +448,31 @@ __extenddfxf2 (double d)
432448
}
433449

434450
exp = EXPD (dl) - EXCESSD + EXCESSX;
435-
ldl.l.upper |= exp << 16;
451+
dl.l.upper &= MANTDMASK;
436452
ldl.l.middle = HIDDENX;
453+
454+
/* Recover from a denorm. */
455+
if (exp == -EXCESSD + EXCESSX)
456+
{
457+
exp++;
458+
while ((dl.l.upper & HIDDEND) == 0)
459+
{
460+
exp--;
461+
dl.l.upper = (dl.l.upper << 1) | (dl.l.lower >> 31);
462+
dl.l.lower = dl.l.lower << 1;
463+
}
464+
}
465+
466+
/* Handle inf and NaN */
467+
else if (exp == EXPDMASK - EXCESSD + EXCESSX)
468+
{
469+
exp = EXPXMASK;
470+
/* No hidden one bit for INF */
471+
if (dl.l.upper == 0 && dl.l.lower == 0)
472+
ldl.l.middle = 0;
473+
}
474+
475+
ldl.l.upper |= exp << 16;
437476
/* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */
438477
ldl.l.middle |= (dl.l.upper & MANTDMASK) << (31 - 20);
439478
/* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */
@@ -464,9 +503,38 @@ __truncxfdf2 (long double ld)
464503
}
465504

466505
exp = EXPX (ldl) - EXCESSX + EXCESSD;
467-
/* ??? quick and dirty: keep `exp' sane */
468-
if (exp >= EXPDMASK)
469-
exp = EXPDMASK - 1;
506+
/* Check for underflow and denormals. */
507+
if (exp <= 0)
508+
{
509+
if (exp < -53)
510+
{
511+
ldl.l.middle = 0;
512+
ldl.l.lower = 0;
513+
}
514+
else if (exp < -30)
515+
{
516+
ldl.l.lower = (ldl.l.middle & MANTXMASK) >> ((1 - exp) - 32);
517+
ldl.l.middle &= ~MANTXMASK;
518+
}
519+
else
520+
{
521+
ldl.l.lower >>= 1 - exp;
522+
ldl.l.lower |= (ldl.l.middle & MANTXMASK) << (32 - (1 - exp));
523+
ldl.l.middle = (ldl.l.middle & ~MANTXMASK) | (ldl.l.middle & MANTXMASK >> (1 - exp));
524+
}
525+
exp = 0;
526+
}
527+
else if (exp == EXPXMASK - EXCESSX + EXCESSD)
528+
{
529+
exp = EXPDMASK;
530+
ldl.l.middle |= ldl.l.lower;
531+
}
532+
else if (exp >= EXPDMASK)
533+
{
534+
exp = EXPDMASK;
535+
ldl.l.middle = 0;
536+
ldl.l.lower = 0;
537+
}
470538
dl.l.upper |= exp << (32 - (EXPDBITS + 1));
471539
/* +1-1: add one for sign bit, but take one off for explicit-integer-bit */
472540
dl.l.upper |= (ldl.l.middle & MANTXMASK) >> (EXPDBITS + 1 - 1);
@@ -511,10 +579,40 @@ __floatunsixf (unsigned long l)
511579

512580
/* convert a long double to an int */
513581
long
514-
__fixxfsi (long double ld)
582+
__fixxfsi (long double a)
515583
{
516-
long foo = __fixdfsi ((double) ld);
517-
return foo;
584+
union long_double_long ldl;
585+
long exp;
586+
long l;
587+
588+
ldl.ld = a;
589+
590+
exp = EXPX(ldl);
591+
if (exp == 0 && ldl.l.middle == 0 && ldl.l.lower == 0)
592+
return 0;
593+
594+
exp = exp - EXCESSX - 64;
595+
596+
if (exp > 0)
597+
{
598+
/* Return largest integer. */
599+
return SIGNX (ldl) ? 0x80000000L : 0x7fffffffL;
600+
}
601+
602+
if (exp <= -64)
603+
return 0;
604+
605+
if (exp <= -32)
606+
{
607+
ldl.l.lower = ldl.l.middle >> (-exp - 32);
608+
}
609+
else if (exp < 0)
610+
{
611+
ldl.l.lower = ldl.l.lower >> -exp;
612+
ldl.l.lower |= ldl.l.middle << (32 + exp);
613+
}
614+
615+
return SIGNX(ldl) ? -ldl.l.lower : ldl.l.lower;
518616
}
519617

520618
/* The remaining provide crude math support by working in double precision. */

libgcc/config/m68k/lb1sf68.S

+13-7
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ SYM (__modsi3):
635635
.globl SYM (_fpCCR)
636636
.globl $_exception_handler
637637

638-
QUIET_NaN = 0xffffffff
638+
QUIET_NaN = 0x7fffffff
639639

640640
D_MAX_EXP = 0x07ff
641641
D_BIAS = 1022
@@ -700,9 +700,10 @@ Ld$overflow:
700700
PICJUMP $_exception_handler
701701

702702
Ld$underflow:
703-
| Return 0 and set the exception flags
703+
| Return a properly signed 0 and set the exception flags
704704
movel IMM (0),d0
705705
movel d0,d1
706+
orl d7,d0
706707
movew IMM (INEXACT_RESULT+UNDERFLOW),d7
707708
moveq IMM (DOUBLE_FLOAT),d6
708709
PICJUMP $_exception_handler
@@ -711,6 +712,7 @@ Ld$inop:
711712
| Return a quiet NaN and set the exception flags
712713
movel IMM (QUIET_NaN),d0
713714
movel d0,d1
715+
bset IMM (31),d1
714716
movew IMM (INEXACT_RESULT+INVALID_OPERATION),d7
715717
moveq IMM (DOUBLE_FLOAT),d6
716718
PICJUMP $_exception_handler
@@ -1383,6 +1385,8 @@ Ladddf$a:
13831385
bge 2f |
13841386
movel d0,d0 | check for zero, since we don't '
13851387
bne Ladddf$ret | want to return -0 by mistake
1388+
movel d1,d1 |
1389+
bne Ladddf$ret |
13861390
bclr IMM (31),d7 |
13871391
bra Ladddf$ret |
13881392
2:
@@ -2080,6 +2084,7 @@ Ldivdf$b$nf:
20802084
| If d2 == 0x7ff00000 we have to check d3.
20812085
tstl d3 |
20822086
bne Ld$inop | if d3 <> 0, b is NaN
2087+
movel a0,d7 | put a's sign
20832088
bra Ld$underflow | else b is +/-INFINITY, so signal underflow
20842089

20852090
Ldivdf$a$nf:
@@ -2090,8 +2095,7 @@ Ldivdf$a$nf:
20902095
| If a is INFINITY we have to check b
20912096
cmpl d7,d2 | compare b with INFINITY
20922097
bge Ld$inop | if b is NaN or INFINITY return NaN
2093-
tstl d3 |
2094-
bne Ld$inop |
2098+
movl a0,d7 | restore sign bit to d7
20952099
bra Ld$overflow | else return overflow
20962100

20972101
| If a number is denormalized we put an exponent of 1 but do not put the
@@ -2186,6 +2190,7 @@ Lround$exit:
21862190
#endif
21872191
beq 2f | if not loop back
21882192
bra 1b |
2193+
movel a0,d7
21892194
bra Ld$underflow | safety check, shouldn't execute '
21902195
2: orl d6,d2 | this is a trick so we don't lose '
21912196
orl d7,d3 | the bits which were flushed right
@@ -2548,7 +2553,7 @@ Lround$to$minus:
25482553
.globl SYM (_fpCCR)
25492554
.globl $_exception_handler
25502555

2551-
QUIET_NaN = 0xffffffff
2556+
QUIET_NaN = 0x7fffffff
25522557
SIGNL_NaN = 0x7f800001
25532558
INFINITY = 0x7f800000
25542559

@@ -2614,8 +2619,9 @@ Lf$overflow:
26142619
PICJUMP $_exception_handler
26152620

26162621
Lf$underflow:
2617-
| Return 0 and set the exception flags
2622+
| Return a properly signed 0 and set the exception flags
26182623
moveq IMM (0),d0
2624+
orl d7,d0
26192625
moveq IMM (INEXACT_RESULT+UNDERFLOW),d7
26202626
moveq IMM (SINGLE_FLOAT),d6
26212627
PICJUMP $_exception_handler
@@ -2936,7 +2942,7 @@ Laddsf$4:
29362942
#else
29372943
cmpl IMM (0xff),d2
29382944
#endif
2939-
bhi 1f
2945+
bge 1f
29402946
bclr IMM (FLT_MANT_DIG-1),d0
29412947
#ifndef __mcoldfire__
29422948
lslw IMM (7),d2

0 commit comments

Comments
 (0)