162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* IEEE754 floating point arithmetic
362306a36Sopenharmony_ci * double precision: common utilities
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 "ieee754dp.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciunion ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	int re;
1562306a36Sopenharmony_ci	int rs;
1662306a36Sopenharmony_ci	u64 rm;
1762306a36Sopenharmony_ci	unsigned int lxm;
1862306a36Sopenharmony_ci	unsigned int hxm;
1962306a36Sopenharmony_ci	unsigned int lym;
2062306a36Sopenharmony_ci	unsigned int hym;
2162306a36Sopenharmony_ci	u64 lrm;
2262306a36Sopenharmony_ci	u64 hrm;
2362306a36Sopenharmony_ci	u64 t;
2462306a36Sopenharmony_ci	u64 at;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	COMPXDP;
2762306a36Sopenharmony_ci	COMPYDP;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	EXPLODEXDP;
3062306a36Sopenharmony_ci	EXPLODEYDP;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	ieee754_clearcx();
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	FLUSHXDP;
3562306a36Sopenharmony_ci	FLUSHYDP;
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 ieee754dp_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 ieee754dp_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 ieee754dp_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 ieee754dp_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 ieee754dp_zero(xs ^ ys);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
9162306a36Sopenharmony_ci		DPDNORMX;
9262306a36Sopenharmony_ci		fallthrough;
9362306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
9462306a36Sopenharmony_ci		DPDNORMY;
9562306a36Sopenharmony_ci		break;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
9862306a36Sopenharmony_ci		DPDNORMX;
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 & DP_HIDDEN_BIT);
10662306a36Sopenharmony_ci	assert(ym & DP_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 <<= 64 - (DP_FBITS + 1);
11362306a36Sopenharmony_ci	ym <<= 64 - (DP_FBITS + 1);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/*
11662306a36Sopenharmony_ci	 * Multiply 64 bits xm, ym to give high 64 bits rm with stickness.
11762306a36Sopenharmony_ci	 */
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	lxm = xm;
12062306a36Sopenharmony_ci	hxm = xm >> 32;
12162306a36Sopenharmony_ci	lym = ym;
12262306a36Sopenharmony_ci	hym = ym >> 32;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	lrm = DPXMULT(lxm, lym);
12562306a36Sopenharmony_ci	hrm = DPXMULT(hxm, hym);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	t = DPXMULT(lxm, hym);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	at = lrm + (t << 32);
13062306a36Sopenharmony_ci	hrm += at < lrm;
13162306a36Sopenharmony_ci	lrm = at;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	hrm = hrm + (t >> 32);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	t = DPXMULT(hxm, lym);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	at = lrm + (t << 32);
13862306a36Sopenharmony_ci	hrm += at < lrm;
13962306a36Sopenharmony_ci	lrm = at;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	hrm = hrm + (t >> 32);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	rm = hrm | (lrm != 0);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/*
14662306a36Sopenharmony_ci	 * Sticky shift down to normal rounding precision.
14762306a36Sopenharmony_ci	 */
14862306a36Sopenharmony_ci	if ((s64) rm < 0) {
14962306a36Sopenharmony_ci		rm = (rm >> (64 - (DP_FBITS + 1 + 3))) |
15062306a36Sopenharmony_ci		     ((rm << (DP_FBITS + 1 + 3)) != 0);
15162306a36Sopenharmony_ci		re++;
15262306a36Sopenharmony_ci	} else {
15362306a36Sopenharmony_ci		rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) |
15462306a36Sopenharmony_ci		     ((rm << (DP_FBITS + 1 + 3 + 1)) != 0);
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	assert(rm & (DP_HIDDEN_BIT << 3));
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return ieee754dp_format(rs, re, rm);
15962306a36Sopenharmony_ci}
160