MIPS: math-emu: Add support for the MIPS R6 MAX{, A} FPU instruction
authorMarkos Chandras <markos.chandras@imgtec.com>
Thu, 13 Aug 2015 07:56:36 +0000 (09:56 +0200)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 3 Sep 2015 10:08:14 +0000 (12:08 +0200)
MIPS R6 introduced the following instruction:
Scalar Floating-Point Maximum and
Scalar Floating-Point argument with Maximum Absolute Value
MAX.fmt writes the maximum value of the inputs fs and ft to the
destination fd.
MAXA.fmt takes input arguments fs and ft and writes the argument with
the maximum absolute value to the destination fd.

Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/10961/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/math-emu/Makefile
arch/mips/math-emu/cp1emu.c
arch/mips/math-emu/dp_fmax.c [new file with mode: 0644]
arch/mips/math-emu/ieee754.h
arch/mips/math-emu/sp_fmax.c [new file with mode: 0644]

index b9946322804eb4fdbe86311eb8822cf317782169..a19641d3ac23cacdb327fdfaecd2b40924d0d6f5 100644 (file)
@@ -4,9 +4,9 @@
 
 obj-y  += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \
           dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \
 
 obj-y  += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \
           dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \
-          dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o \
+          dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \
           sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \
           sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \
-          sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o \
+          sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o sp_fmax.o \
           dsemul.o
 
 lib-y  += ieee754d.o \
           dsemul.o
 
 lib-y  += ieee754d.o \
index f397bdfd93fb18c376f7e0f3bfdd84148e63c574..32f0e19a0d7f71fef2bb693e0da7b7bbc6bc9af9 100644 (file)
@@ -1839,6 +1839,30 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        break;
                }
 
                        break;
                }
 
+               case fmax_op: {
+                       union ieee754sp fs, ft;
+
+                       if (!cpu_has_mips_r6)
+                               return SIGILL;
+
+                       SPFROMREG(ft, MIPSInst_FT(ir));
+                       SPFROMREG(fs, MIPSInst_FS(ir));
+                       rv.s = ieee754sp_fmax(fs, ft);
+                       break;
+               }
+
+               case fmaxa_op: {
+                       union ieee754sp fs, ft;
+
+                       if (!cpu_has_mips_r6)
+                               return SIGILL;
+
+                       SPFROMREG(ft, MIPSInst_FT(ir));
+                       SPFROMREG(fs, MIPSInst_FS(ir));
+                       rv.s = ieee754sp_fmaxa(fs, ft);
+                       break;
+               }
+
                case fabs_op:
                        handler.u = ieee754sp_abs;
                        goto scopuop;
                case fabs_op:
                        handler.u = ieee754sp_abs;
                        goto scopuop;
@@ -2133,6 +2157,30 @@ copcsr:
                        break;
                }
 
                        break;
                }
 
+               case fmax_op: {
+                       union ieee754dp fs, ft;
+
+                       if (!cpu_has_mips_r6)
+                               return SIGILL;
+
+                       DPFROMREG(ft, MIPSInst_FT(ir));
+                       DPFROMREG(fs, MIPSInst_FS(ir));
+                       rv.d = ieee754dp_fmax(fs, ft);
+                       break;
+               }
+
+               case fmaxa_op: {
+                       union ieee754dp fs, ft;
+
+                       if (!cpu_has_mips_r6)
+                               return SIGILL;
+
+                       DPFROMREG(ft, MIPSInst_FT(ir));
+                       DPFROMREG(fs, MIPSInst_FS(ir));
+                       rv.d = ieee754dp_fmaxa(fs, ft);
+                       break;
+               }
+
                case fabs_op:
                        handler.u = ieee754dp_abs;
                        goto dcopuop;
                case fabs_op:
                        handler.u = ieee754dp_abs;
                        goto dcopuop;
diff --git a/arch/mips/math-emu/dp_fmax.c b/arch/mips/math-emu/dp_fmax.c
new file mode 100644 (file)
index 0000000..fd71b8d
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * IEEE754 floating point arithmetic
+ * double precision: MIN{,A}.f
+ * MIN : Scalar Floating-Point Minimum
+ * MINA: Scalar Floating-Point argument with Minimum Absolute Value
+ *
+ * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft])
+ * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft])
+ *
+ * MIPS floating point support
+ * Copyright (C) 2015 Imagination Technologies, Ltd.
+ * Author: Markos Chandras <markos.chandras@imgtec.com>
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; version 2 of the License.
+ */
+
+#include "ieee754dp.h"
+
+union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
+{
+       COMPXDP;
+       COMPYDP;
+
+       EXPLODEXDP;
+       EXPLODEYDP;
+
+       FLUSHXDP;
+       FLUSHYDP;
+
+       ieee754_clearcx();
+
+       switch (CLPAIR(xc, yc)) {
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+               return ieee754dp_nanxcpt(y);
+
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+               return ieee754dp_nanxcpt(x);
+
+       /* numbers are preferred to NaNs */
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+               return x;
+
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+               return y;
+
+       /*
+        * Infinity and zero handling
+        */
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+               return xs ? y : x;
+
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+               return ys ? x : y;
+
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+               if (xs == ys)
+                       return x;
+               return ieee754dp_zero(1);
+
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+               DPDNORMX;
+
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+               DPDNORMY;
+               break;
+
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+               DPDNORMX;
+       }
+
+       /* Finally get to do some computation */
+
+       assert(xm & DP_HIDDEN_BIT);
+       assert(ym & DP_HIDDEN_BIT);
+
+       /* Compare signs */
+       if (xs > ys)
+               return y;
+       else if (xs < ys)
+               return x;
+
+       /* Compare exponent */
+       if (xe > ye)
+               return x;
+       else if (xe < ye)
+               return y;
+
+       /* Compare mantissa */
+       if (xm <= ym)
+               return y;
+       return x;
+}
+
+union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
+{
+       COMPXDP;
+       COMPYDP;
+
+       EXPLODEXDP;
+       EXPLODEYDP;
+
+       FLUSHXDP;
+       FLUSHYDP;
+
+       ieee754_clearcx();
+
+       switch (CLPAIR(xc, yc)) {
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+               return ieee754dp_nanxcpt(y);
+
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+               return ieee754dp_nanxcpt(x);
+
+       /* numbers are preferred to NaNs */
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+               return x;
+
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+               return y;
+
+       /*
+        * Infinity and zero handling
+        */
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+               return x;
+
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+               return y;
+
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+               if (xs == ys)
+                       return x;
+               return ieee754dp_zero(1);
+
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+               DPDNORMX;
+
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+               DPDNORMY;
+               break;
+
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+               DPDNORMX;
+       }
+
+       /* Finally get to do some computation */
+
+       assert(xm & DP_HIDDEN_BIT);
+       assert(ym & DP_HIDDEN_BIT);
+
+       /* Compare exponent */
+       if (xe > ye)
+               return x;
+       else if (xe < ye)
+               return y;
+
+       /* Compare mantissa */
+       if (xm <= ym)
+               return y;
+       return x;
+}
index 6a16357a1ddd79c959cd29ae22689cc65ab63f4b..df94720714c73cc95736544f7b05804d607d27ca 100644 (file)
@@ -82,6 +82,8 @@ union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
 int ieee754sp_2008class(union ieee754sp x);
 union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y);
 union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y);
 int ieee754sp_2008class(union ieee754sp x);
 union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y);
 union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y);
+union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y);
+union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y);
 
 /*
  * double precision (often aka double)
 
 /*
  * double precision (often aka double)
@@ -114,6 +116,8 @@ union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
 int ieee754dp_2008class(union ieee754dp x);
 union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y);
 union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y);
 int ieee754dp_2008class(union ieee754dp x);
 union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y);
 union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y);
+union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y);
+union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y);
 
 
 /* 5 types of floating point number
 
 
 /* 5 types of floating point number
diff --git a/arch/mips/math-emu/sp_fmax.c b/arch/mips/math-emu/sp_fmax.c
new file mode 100644 (file)
index 0000000..4d00084
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * IEEE754 floating point arithmetic
+ * single precision: MAX{,A}.f
+ * MAX : Scalar Floating-Point Maximum
+ * MAXA: Scalar Floating-Point argument with Maximum Absolute Value
+ *
+ * MAX.S : FPR[fd] = maxNum(FPR[fs],FPR[ft])
+ * MAXA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft])
+ *
+ * MIPS floating point support
+ * Copyright (C) 2015 Imagination Technologies, Ltd.
+ * Author: Markos Chandras <markos.chandras@imgtec.com>
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; version 2 of the License.
+ */
+
+#include "ieee754sp.h"
+
+union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
+{
+       COMPXSP;
+       COMPYSP;
+
+       EXPLODEXSP;
+       EXPLODEYSP;
+
+       FLUSHXSP;
+       FLUSHYSP;
+
+       ieee754_clearcx();
+
+       switch (CLPAIR(xc, yc)) {
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+               return ieee754sp_nanxcpt(y);
+
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+               return ieee754sp_nanxcpt(x);
+
+       /* numbers are preferred to NaNs */
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+               return x;
+
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+               return y;
+
+       /*
+        * Infinity and zero handling
+        */
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+               return xs ? y : x;
+
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+               return ys ? x : y;
+
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+               if (xs == ys)
+                       return x;
+               return ieee754sp_zero(1);
+
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+               SPDNORMX;
+
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+               SPDNORMY;
+               break;
+
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+               SPDNORMX;
+       }
+
+       /* Finally get to do some computation */
+
+       assert(xm & SP_HIDDEN_BIT);
+       assert(ym & SP_HIDDEN_BIT);
+
+       /* Compare signs */
+       if (xs > ys)
+               return y;
+       else if (xs < ys)
+               return x;
+
+       /* Compare exponent */
+       if (xe > ye)
+               return x;
+       else if (xe < ye)
+               return y;
+
+       /* Compare mantissa */
+       if (xm <= ym)
+               return y;
+       return x;
+}
+
+union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
+{
+       COMPXSP;
+       COMPYSP;
+
+       EXPLODEXSP;
+       EXPLODEYSP;
+
+       FLUSHXSP;
+       FLUSHYSP;
+
+       ieee754_clearcx();
+
+       switch (CLPAIR(xc, yc)) {
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+               return ieee754sp_nanxcpt(y);
+
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+               return ieee754sp_nanxcpt(x);
+
+       /* numbers are preferred to NaNs */
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+               return x;
+
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+               return y;
+
+       /*
+        * Infinity and zero handling
+        */
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+               return x;
+
+       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+               return y;
+
+       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+               if (xs == ys)
+                       return x;
+               return ieee754sp_zero(1);
+
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+               SPDNORMX;
+
+       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+               SPDNORMY;
+               break;
+
+       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+               SPDNORMX;
+       }
+
+       /* Finally get to do some computation */
+
+       assert(xm & SP_HIDDEN_BIT);
+       assert(ym & SP_HIDDEN_BIT);
+
+       /* Compare exponent */
+       if (xe > ye)
+               return x;
+       else if (xe < ye)
+               return y;
+
+       /* Compare mantissa */
+       if (xm <= ym)
+               return y;
+       return x;
+}