Skip to content

Commit c1ea994

Browse files
committed
libgcc/m68k: Fixes for soft float
Fix __extenddfxf2: * Remove bogus denorm handling block which would never execute -- the converted exp value is always positive as EXCESSX > EXCESSD. * Compute the whole significand in dl instead of doing part of it in ldl. * Mask off exponent from dl.l.upper so the denorm shift test works. * Insert the hidden one bit into dl.l.upper as needed. Fix __truncxfdf2 denorm handling. All that is required is to shift the significand right by the correct amount; it already has all of the necessary bits set including the explicit one. Compute the shift amount, then perform the wide shift across both elements of the significand. Fix __fixxfsi: * The value was off by a factor of two as the significand contains 32 bits, not 31 so we need to shift by one more than the equivalent code in __fixdfsi. * Simplify the code having realized that the lower 32 bits of the significand can never appear in the results. Return positive qNaN instead of negative. For floats, qNaN is 0x7fff_ffff. For doubles, qNaN is 0x7fff_ffff_ffff_ffff. Return correctly signed zero on float and double divide underflow. This means that Ld$underflow now expects d7 to contain the sign bit, just like the other return paths. Signed-off-by: Keith Packard <[email protected]>
1 parent 862467c commit c1ea994

File tree

2 files changed

+45
-46
lines changed

2 files changed

+45
-46
lines changed

Diff for: libgcc/config/m68k/fpgnulib.c

+36-42
Original file line numberDiff line numberDiff line change
@@ -449,34 +449,37 @@ __extenddfxf2 (double d)
449449
}
450450

451451
exp = EXPD (dl) - EXCESSD + EXCESSX;
452-
/* Check for underflow and denormals. */
453-
if (exp < 0)
452+
453+
dl.l.upper &= MANTDMASK;
454+
455+
/* Recover from a denorm. */
456+
if (exp == -EXCESSD + EXCESSX)
454457
{
455-
if (exp < -53)
456-
{
457-
ldl.l.middle = 0;
458-
ldl.l.lower = 0;
459-
}
460-
else if (exp < -30)
461-
{
462-
ldl.l.lower = (ldl.l.middle & MANTXMASK) >> ((1 - exp) - 32);
463-
ldl.l.middle &= ~MANTXMASK;
464-
}
465-
else
458+
exp++;
459+
while ((dl.l.upper & HIDDEND) == 0)
466460
{
467-
ldl.l.lower >>= 1 - exp;
468-
ldl.l.lower |= (ldl.l.middle & MANTXMASK) << (32 - (1 - exp));
469-
ldl.l.middle = (ldl.l.middle & ~MANTXMASK) | (ldl.l.middle & MANTXMASK >> (1 - exp));
461+
exp--;
462+
dl.l.upper = (dl.l.upper << 1) | (dl.l.lower >> 31);
463+
dl.l.lower = dl.l.lower << 1;
470464
}
471-
exp = 0;
472465
}
466+
473467
/* Handle inf and NaN */
474-
if (exp == EXPDMASK - EXCESSD + EXCESSX)
475-
exp = EXPXMASK;
468+
else if (exp == EXPDMASK - EXCESSD + EXCESSX)
469+
{
470+
exp = EXPXMASK;
471+
/* Add hidden one bit for NaN */
472+
if (dl.l.upper != 0 || dl.l.lower != 0)
473+
dl.l.upper |= HIDDEND;
474+
}
475+
else
476+
{
477+
dl.l.upper |= HIDDEND;
478+
}
479+
476480
ldl.l.upper |= exp << 16;
477-
ldl.l.middle = HIDDENX;
478481
/* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */
479-
ldl.l.middle |= (dl.l.upper & MANTDMASK) << (31 - 20);
482+
ldl.l.middle = dl.l.upper << (31 - 20);
480483
/* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */
481484
ldl.l.middle |= dl.l.lower >> (1 + 20);
482485
/* 32 - 21: # bits of dl.l.lower in ldl.l.middle */
@@ -508,21 +511,21 @@ __truncxfdf2 (long double ld)
508511
/* Check for underflow and denormals. */
509512
if (exp <= 0)
510513
{
511-
if (exp < -53)
514+
long shift = 1 - exp;
515+
if (shift > 52)
512516
{
513517
ldl.l.middle = 0;
514518
ldl.l.lower = 0;
515519
}
516-
else if (exp < -30)
520+
else if (shift >= 32)
517521
{
518-
ldl.l.lower = (ldl.l.middle & MANTXMASK) >> ((1 - exp) - 32);
519-
ldl.l.middle &= ~MANTXMASK;
522+
ldl.l.lower = (ldl.l.middle) >> (shift - 32);
523+
ldl.l.middle = 0;
520524
}
521525
else
522526
{
523-
ldl.l.lower >>= 1 - exp;
524-
ldl.l.lower |= (ldl.l.middle & MANTXMASK) << (32 - (1 - exp));
525-
ldl.l.middle = (ldl.l.middle & ~MANTXMASK) | (ldl.l.middle & MANTXMASK >> (1 - exp));
527+
ldl.l.lower = (ldl.l.middle << (32 - shift)) | (ldl.l.lower >> shift);
528+
ldl.l.middle = ldl.l.middle >> shift;
526529
}
527530
exp = 0;
528531
}
@@ -585,36 +588,27 @@ __fixxfsi (long double a)
585588
{
586589
union long_double_long ldl;
587590
long exp;
588-
long l;
589591

590592
ldl.ld = a;
591593

592594
exp = EXPX (ldl);
593595
if (exp == 0 && ldl.l.middle == 0 && ldl.l.lower == 0)
594596
return 0;
595597

596-
exp = exp - EXCESSX - 63;
598+
exp = exp - EXCESSX - 32;
597599

598-
if (exp > 0)
600+
if (exp >= 0)
599601
{
600602
/* Return largest integer. */
601603
return SIGNX (ldl) ? 0x80000000L : 0x7fffffffL;
602604
}
603605

604-
if (exp <= -64)
606+
if (exp <= -32)
605607
return 0;
606608

607-
if (exp <= -32)
608-
{
609-
ldl.l.lower = ldl.l.middle >> (-exp - 32);
610-
}
611-
else if (exp < 0)
612-
{
613-
ldl.l.lower = ldl.l.lower >> -exp;
614-
ldl.l.lower |= ldl.l.middle << (32 + exp);
615-
}
609+
ldl.l.middle >>= -exp;
616610

617-
return SIGNX (ldl) ? -ldl.l.lower : ldl.l.lower;
611+
return SIGNX (ldl) ? -ldl.l.middle : ldl.l.middle;
618612
}
619613

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

Diff for: libgcc/config/m68k/lb1sf68.S

+9-4
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
@@ -2082,6 +2084,7 @@ Ldivdf$b$nf:
20822084
| If d2 == 0x7ff00000 we have to check d3.
20832085
tstl d3 |
20842086
bne Ld$inop | if d3 <> 0, b is NaN
2087+
movel a0,d7 | put a's sign
20852088
bra Ld$underflow | else b is +/-INFINITY, so signal underflow
20862089

20872090
Ldivdf$a$nf:
@@ -2187,6 +2190,7 @@ Lround$exit:
21872190
#endif
21882191
beq 2f | if not loop back
21892192
bra 1b |
2193+
movel a0,d7 | get back sign bit into d7
21902194
bra Ld$underflow | safety check, shouldn't execute '
21912195
2: orl d6,d2 | this is a trick so we don't lose '
21922196
orl d7,d3 | the bits which were flushed right
@@ -2549,7 +2553,7 @@ Lround$to$minus:
25492553
.globl SYM (_fpCCR)
25502554
.globl $_exception_handler
25512555

2552-
QUIET_NaN = 0xffffffff
2556+
QUIET_NaN = 0x7fffffff
25532557
SIGNL_NaN = 0x7f800001
25542558
INFINITY = 0x7f800000
25552559

@@ -2615,8 +2619,9 @@ Lf$overflow:
26152619
PICJUMP $_exception_handler
26162620

26172621
Lf$underflow:
2618-
| Return 0 and set the exception flags
2622+
| Return a properly signed 0 and set the exception flags
26192623
moveq IMM (0),d0
2624+
orl d7,d0
26202625
moveq IMM (INEXACT_RESULT+UNDERFLOW),d7
26212626
moveq IMM (SINGLE_FLOAT),d6
26222627
PICJUMP $_exception_handler

0 commit comments

Comments
 (0)