11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* IEEE754 floating point arithmetic
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * single precision
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MIPS floating point support
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1994-2000 Algorithmics Ltd.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ########################################################################
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is free software; you can distribute it and/or modify it
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  under the terms of the GNU General Public License (Version 2) as
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  published by the Free Software Foundation.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is distributed in the hope it will be useful, but WITHOUT
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  for more details.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  You should have received a copy of the GNU General Public License along
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  with this program; if not, write to the Free Software Foundation, Inc.,
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ########################################################################
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ieee754sp.h"
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	COMPXSP;
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	COMPYSP;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXPLODEXSP;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXPLODEYSP;
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CLEARCX;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FLUSHXSP;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FLUSHYSP;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (CLPAIR(xc, yc)) {
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SETCX(IEEE754_INVALID_OPERATION);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ieee754sp_nanxcpt(ieee754sp_indef(), "mul", x, y);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return y;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return x;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Infinity handling */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SETCX(IEEE754_INVALID_OPERATION);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ieee754sp_inf(xs ^ ys);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ieee754sp_zero(xs ^ ys);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SPDNORMX;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SPDNORMY;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SPDNORMX;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* rm = xm * ym, re = xe+ye basically */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	assert(xm & SP_HIDDEN_BIT);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	assert(ym & SP_HIDDEN_BIT);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int re = xe + ye;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int rs = xs ^ ys;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned rm;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* shunt to top of word */
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xm <<= 32 - (SP_MBITS + 1);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ym <<= 32 - (SP_MBITS + 1);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* multiply 32bits xm,ym to give high 32bits rm with stickness
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned short lxm = xm & 0xffff;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned short hxm = xm >> 16;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned short lym = ym & 0xffff;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned short hym = ym >> 16;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned lrm;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned hrm;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lrm = lxm * lym;	/* 16 * 16 => 32 */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hrm = hxm * hym;	/* 16 * 16 => 32 */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			{
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned t = lxm * hym;	/* 16 * 16 => 32 */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				{
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unsigned at = lrm + (t << 16);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					hrm += at < lrm;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lrm = at;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hrm = hrm + (t >> 16);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			{
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned t = hxm * lym;	/* 16 * 16 => 32 */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				{
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unsigned at = lrm + (t << 16);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					hrm += at < lrm;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lrm = at;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hrm = hrm + (t >> 16);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rm = hrm | (lrm != 0);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * sticky shift down to normal rounding precision
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((int) rm < 0) {
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rm = (rm >> (32 - (SP_MBITS + 1 + 3))) |
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ((rm << (SP_MBITS + 1 + 3)) != 0);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			re++;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) |
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ((rm << (SP_MBITS + 1 + 3 + 1)) != 0);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		assert(rm & (SP_HIDDEN_BIT << 3));
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SPNORMRET2(rs, re, rm, "mul", x, y);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
171