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 * Copyright (C) 2017 Imagination Technologies, Ltd.
962306a36Sopenharmony_ci * Author: Aleksandar Markovic <aleksandar.markovic@imgtec.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "ieee754dp.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciunion ieee754dp ieee754dp_rint(union ieee754dp x)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	union ieee754dp ret;
1762306a36Sopenharmony_ci	u64 residue;
1862306a36Sopenharmony_ci	int sticky;
1962306a36Sopenharmony_ci	int round;
2062306a36Sopenharmony_ci	int odd;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	COMPXDP;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	ieee754_clearcx();
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	EXPLODEXDP;
2762306a36Sopenharmony_ci	FLUSHXDP;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (xc == IEEE754_CLASS_SNAN)
3062306a36Sopenharmony_ci		return ieee754dp_nanxcpt(x);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	if ((xc == IEEE754_CLASS_QNAN) ||
3362306a36Sopenharmony_ci	    (xc == IEEE754_CLASS_INF) ||
3462306a36Sopenharmony_ci	    (xc == IEEE754_CLASS_ZERO))
3562306a36Sopenharmony_ci		return x;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (xe >= DP_FBITS)
3862306a36Sopenharmony_ci		return x;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (xe < -1) {
4162306a36Sopenharmony_ci		residue = xm;
4262306a36Sopenharmony_ci		round = 0;
4362306a36Sopenharmony_ci		sticky = residue != 0;
4462306a36Sopenharmony_ci		xm = 0;
4562306a36Sopenharmony_ci	} else {
4662306a36Sopenharmony_ci		residue = xm << (64 - DP_FBITS + xe);
4762306a36Sopenharmony_ci		round = (residue >> 63) != 0;
4862306a36Sopenharmony_ci		sticky = (residue << 1) != 0;
4962306a36Sopenharmony_ci		xm >>= DP_FBITS - xe;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	odd = (xm & 0x1) != 0x0;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	switch (ieee754_csr.rm) {
5562306a36Sopenharmony_ci	case FPU_CSR_RN:	/* toward nearest */
5662306a36Sopenharmony_ci		if (round && (sticky || odd))
5762306a36Sopenharmony_ci			xm++;
5862306a36Sopenharmony_ci		break;
5962306a36Sopenharmony_ci	case FPU_CSR_RZ:	/* toward zero */
6062306a36Sopenharmony_ci		break;
6162306a36Sopenharmony_ci	case FPU_CSR_RU:	/* toward +infinity */
6262306a36Sopenharmony_ci		if ((round || sticky) && !xs)
6362306a36Sopenharmony_ci			xm++;
6462306a36Sopenharmony_ci		break;
6562306a36Sopenharmony_ci	case FPU_CSR_RD:	/* toward -infinity */
6662306a36Sopenharmony_ci		if ((round || sticky) && xs)
6762306a36Sopenharmony_ci			xm++;
6862306a36Sopenharmony_ci		break;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (round || sticky)
7262306a36Sopenharmony_ci		ieee754_setcx(IEEE754_INEXACT);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	ret = ieee754dp_flong(xm);
7562306a36Sopenharmony_ci	DPSIGN(ret) = xs;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return ret;
7862306a36Sopenharmony_ci}
79