On OpenBSD/luna88k 8.0-beta, the following test checks
an unordered comparison with a quiet NaN:

```
#include <stdio.h>
#include <ieeefp.h>

attribute((noinline)) int
is_unordered(double a, double b)
{
        return __builtin_isunordered(a, b);
}

int
main(void)
{
        volatile double q = __builtin_nan("");
        volatile double one = 1.0;
        int v;
        fp_except f;

        fpsetsticky(0);
        v = is_unordered(q, one);
        f = fpgetsticky();
        printf("unordered value=%d sticky=0x%x\n", v, (unsigned)f);
        return 0;
}
```

    gcc -O0 fp01-qnan.c -o fp01-qnan
    ./fp01-qnan

FCMP should report unordered without raising IEEE invalid for a quiet NaN.
The MC88100 User's Manual, second edition, section 2.4.5.1,
distinguishes software completion from IEEE exceptions.
The MC88110 User's Manual, section 4.3.2.4, item 2 on page 4-20,
explicitly specifies quiet NaN FCMP completion without an IEEE exception.

https://www.bitsavers.org/components/motorola/88000/MC88100_RISC_Microprocessor_Users_Manual_2ed_1990.pdf
https://www.bitsavers.org/components/motorola/88000/MC88110UM_88110_Users_Manual_1991.pdf#page=125

The expected output is

    unordered value=1 sticky=0x0

Instead, the unordered check produced

    unordered value=1 sticky=0x10

The comparison result is correct, but the sticky exception flags
contain FP_X_INV (0x10). The generated code uses fcmp.sdd for this
comparison.

This was observed under nono 1.8.3 emulating an MC88100.
The disk image was assembled from official OpenBSD/luna88k 8.0-beta
snapshot binaries with a BUILDINFO build date of 2026-09-15 (UTC).
The compiler was the supplied native gcc 4.2.1 20070719.

The earlier m88100_fp.S sets invalid only for signaling NaNs in its
FCMP path:

```
ASLOCAL(NaN)
        bb0.n   s1nan, %r12, S2sigcheck         /* S1 is not a NaN */
         st     %r1,  %r31,  0                  /* save return address */
        bb1     sigbit, %r5, S2sigcheck         /* S1 is not a signaling NaN */
        set     %r2,  %r2,  1<oper>
        br.n    S1write                         /* FPSR bit already set, S1 is 
*/
                                                /* made quiet, and since we */
                                                /* always write S1 if it is */
                                                /* a NaN, write S1 and skip */
                                                /* rest of routine */
         set    %r5,  %r5,  1<sigbit>           /* make S1 a quiet NaN */

ASLOCAL(S2sigcheck)
        bb0     s2nan, %r12, S1write            /* S2 is not a NaN */
        bb1     sigbit, %r7, S1write            /* S2 is not a signaling NaN */
        set     %r2,  %r2,  1<oper>
        set     %r7,  %r7,  1<sigbit>           /* make S2 a quiet NaN */

```

The 2014-06-09 C replacement m88100_fp.c uses the common fpu_compare()
helper. Its single/double-precision NaN path contains:

```
        case FTYPE_SNG:
                if (float32_is_nan(s1->sng)) {
                        if (!fcmpu || float32_is_signaling_nan(s1->sng))
                            ^^^^^^
                                float_set_invalid();
                        cc = CC_UN;
                        goto done;
                }
                if (float32_is_nan(s2->sng)) {
                        if (!fcmpu || float32_is_signaling_nan(s2->sng))
                            ^^^^^^
                                float_set_invalid();
                        cc = CC_UN;
                        goto done;
                }
                break;
        case FTYPE_DBL:
                if (float64_is_nan(s1->dbl)) {
                        if (!fcmpu || float64_is_signaling_nan(s1->dbl))
                            ^^^^^^
                                float_set_invalid();
                        cc = CC_UN;
                        goto done;
                }
                if (float64_is_nan(s2->dbl)) {
                        if (!fcmpu || float64_is_signaling_nan(s2->dbl))
                            ^^^^^^
                                float_set_invalid();
                        cc = CC_UN;
                        goto done;
                }
                break;
        }
```

MC88100 FCMP passes fcmpu=0, so this condition causes invalid to be
set even for a quiet NaN. The FCMP/FCMPU exception selection for quiet
NaNs appears reversed.

kernel dmesg (on nono emulator emulating LUNA-88K):
----
Copyright (c) 1982, 1986, 1989, 1991, 1993
        The Regents of the University of California.  All rights reserved.
Copyright (c) 1995-2026 OpenBSD. All rights reserved.  https://www.OpenBSD.org
OpenBSD 8.0-beta (GENERIC) #0: Tue Sep 15 18:09:37 JST 2026
    [email protected]:/usr/src/sys/arch/luna88k/compile/GENERIC
real mem = 67104768 (63MB)
avail mem = 60502016 (57MB)
random: boothowto does not indicate good seed
mainbus0 at root: OMRON LUNA-88K, 25MHz
cpu0: M88100 rev 0xb, 2 CMMU
cpu0: M88200 (16K) rev 0x9, full Icache
cpu0: M88200 (16K) rev 0x9, full Dcache
clock0 at mainbus0: MK48T02
lcd0 at mainbus0
le0 at mainbus0: address 02:00:01:83:9a:47
le0: 32 receive buffers, 8 transmit buffers
sio0 at mainbus0: 7201a
siotty0 at sio0 channel 0 (console)
ws0 at sio0 channel 1
wskbd0 at ws0 mux 1
wsmouse0 at ws0 mux 0
xp0 at mainbus0: HD647180X I/O processor
fb0 at mainbus0: 1280x1024, 4bpp
wsdisplay0 at fb0 mux 1
wskbd0: connecting to wsdisplay0
wsdisplay0: screen 0 added (std, vt100 emulation)
spc0 at mainbus0
scsibus0 at spc0: 8 targets, initiator 7
cd0 at scsibus0 targ 5 lun 0: <NONO, SCSICD, > removable
sd0 at scsibus0 targ 6 lun 0: <NONO, SCSIHD, >
sd0: 2048MB, 512 bytes/sector, 4194304 sectors
vscsi0 at root
scsibus1 at vscsi0: 256 targets
softraid0 at root
scsibus2 at softraid0: 256 targets
boot device: sd0
root on sd0a (c71ef0b1c4b73dd3.a) swap on sd0b dump on sd0b
WARNING: clock gained 5 days
WARNING: CHECK AND RESET THE DATE!

Reply via email to