162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* IEEE754 floating point arithmetic
362306a36Sopenharmony_ci * single precision
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * MIPS floating point support
762306a36Sopenharmony_ci * Copyright (C) 1994-2000 Algorithmics Ltd.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "ieee754sp.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciunion ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	int re;
1562306a36Sopenharmony_ci	int rs;
1662306a36Sopenharmony_ci	unsigned int rm;
1762306a36Sopenharmony_ci	unsigned short lxm;
1862306a36Sopenharmony_ci	unsigned short hxm;
1962306a36Sopenharmony_ci	unsigned short lym;
2062306a36Sopenharmony_ci	unsigned short hym;
2162306a36Sopenharmony_ci	unsigned int lrm;
2262306a36Sopenharmony_ci	unsigned int hrm;
2362306a36Sopenharmony_ci	unsigned int t;
2462306a36Sopenharmony_ci	unsigned int at;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	COMPXSP;
2762306a36Sopenharmony_ci	COMPYSP;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	EXPLODEXSP;
3062306a36Sopenharmony_ci	EXPLODEYSP;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	ieee754_clearcx();
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	FLUSHXSP;
3562306a36Sopenharmony_ci	FLUSHYSP;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	switch (CLPAIR(xc, yc)) {
3862306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
3962306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
4062306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
4162306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
4262306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
4362306a36Sopenharmony_ci		return ieee754sp_nanxcpt(y);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
4662306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
4762306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
4862306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
4962306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
5062306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
5162306a36Sopenharmony_ci		return ieee754sp_nanxcpt(x);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
5462306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
5562306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
5662306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
5762306a36Sopenharmony_ci		return y;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
6062306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
6162306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
6262306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
6362306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
6462306a36Sopenharmony_ci		return x;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/*
6862306a36Sopenharmony_ci	 * Infinity handling
6962306a36Sopenharmony_ci	 */
7062306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
7162306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
7262306a36Sopenharmony_ci		ieee754_setcx(IEEE754_INVALID_OPERATION);
7362306a36Sopenharmony_ci		return ieee754sp_indef();
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
7662306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
7762306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
7862306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
7962306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
8062306a36Sopenharmony_ci		return ieee754sp_inf(xs ^ ys);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
8362306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
8462306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
8562306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
8662306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
8762306a36Sopenharmony_ci		return ieee754sp_zero(xs ^ ys);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
9162306a36Sopenharmony_ci		SPDNORMX;
9262306a36Sopenharmony_ci		fallthrough;
9362306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
9462306a36Sopenharmony_ci		SPDNORMY;
9562306a36Sopenharmony_ci		break;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
9862306a36Sopenharmony_ci		SPDNORMX;
9962306a36Sopenharmony_ci		break;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
10262306a36Sopenharmony_ci		break;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci	/* rm = xm * ym, re = xe+ye basically */
10562306a36Sopenharmony_ci	assert(xm & SP_HIDDEN_BIT);
10662306a36Sopenharmony_ci	assert(ym & SP_HIDDEN_BIT);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	re = xe + ye;
10962306a36Sopenharmony_ci	rs = xs ^ ys;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* shunt to top of word */
11262306a36Sopenharmony_ci	xm <<= 32 - (SP_FBITS + 1);
11362306a36Sopenharmony_ci	ym <<= 32 - (SP_FBITS + 1);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/*
11662306a36Sopenharmony_ci	 * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
11762306a36Sopenharmony_ci	 */
11862306a36Sopenharmony_ci	lxm = xm & 0xffff;
11962306a36Sopenharmony_ci	hxm = xm >> 16;
12062306a36Sopenharmony_ci	lym = ym & 0xffff;
12162306a36Sopenharmony_ci	hym = ym >> 16;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	lrm = lxm * lym;	/* 16 * 16 => 32 */
12462306a36Sopenharmony_ci	hrm = hxm * hym;	/* 16 * 16 => 32 */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	t = lxm * hym; /* 16 * 16 => 32 */
12762306a36Sopenharmony_ci	at = lrm + (t << 16);
12862306a36Sopenharmony_ci	hrm += at < lrm;
12962306a36Sopenharmony_ci	lrm = at;
13062306a36Sopenharmony_ci	hrm = hrm + (t >> 16);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	t = hxm * lym; /* 16 * 16 => 32 */
13362306a36Sopenharmony_ci	at = lrm + (t << 16);
13462306a36Sopenharmony_ci	hrm += at < lrm;
13562306a36Sopenharmony_ci	lrm = at;
13662306a36Sopenharmony_ci	hrm = hrm + (t >> 16);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	rm = hrm | (lrm != 0);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/*
14162306a36Sopenharmony_ci	 * Sticky shift down to normal rounding precision.
14262306a36Sopenharmony_ci	 */
14362306a36Sopenharmony_ci	if ((int) rm < 0) {
14462306a36Sopenharmony_ci		rm = (rm >> (32 - (SP_FBITS + 1 + 3))) |
14562306a36Sopenharmony_ci		    ((rm << (SP_FBITS + 1 + 3)) != 0);
14662306a36Sopenharmony_ci		re++;
14762306a36Sopenharmony_ci	} else {
14862306a36Sopenharmony_ci		rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) |
14962306a36Sopenharmony_ci		     ((rm << (SP_FBITS + 1 + 3 + 1)) != 0);
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci	assert(rm & (SP_HIDDEN_BIT << 3));
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return ieee754sp_format(rs, re, rm);
15462306a36Sopenharmony_ci}
155