1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
4 *
5 * Floating-point emulation code
6 *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
7 */
8/*
9 * BEGIN_DESC
10 *
11 *  File:
12 *	@(#)	pa/spmath/dfmpy.c		$Revision: 1.1 $
13 *
14 *  Purpose:
15 *	Double Precision Floating-point Multiply
16 *
17 *  External Interfaces:
18 *	dbl_fmpy(srcptr1,srcptr2,dstptr,status)
19 *
20 *  Internal Interfaces:
21 *
22 *  Theory:
23 *	<<please update with a overview of the operation of this file>>
24 *
25 * END_DESC
26*/
27
28
29#include "float.h"
30#include "dbl_float.h"
31
32/*
33 *  Double Precision Floating-point Multiply
34 */
35
36int
37dbl_fmpy(
38	    dbl_floating_point *srcptr1,
39	    dbl_floating_point *srcptr2,
40	    dbl_floating_point *dstptr,
41	    unsigned int *status)
42{
43	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
44	register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
45	register int dest_exponent, count;
46	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
47	boolean is_tiny;
48
49	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
50	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
51
52	/*
53	 * set sign bit of result
54	 */
55	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
56		Dbl_setnegativezerop1(resultp1);
57	else Dbl_setzerop1(resultp1);
58	/*
59	 * check first operand for NaN's or infinity
60	 */
61	if (Dbl_isinfinity_exponent(opnd1p1)) {
62		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
63			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
64				if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
65					/*
66					 * invalid since operands are infinity
67					 * and zero
68					 */
69					if (Is_invalidtrap_enabled())
70                                		return(INVALIDEXCEPTION);
71                                	Set_invalidflag();
72                                	Dbl_makequietnan(resultp1,resultp2);
73					Dbl_copytoptr(resultp1,resultp2,dstptr);
74					return(NOEXCEPTION);
75				}
76				/*
77			 	 * return infinity
78			 	 */
79				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
80				Dbl_copytoptr(resultp1,resultp2,dstptr);
81				return(NOEXCEPTION);
82			}
83		}
84		else {
85                	/*
86                 	 * is NaN; signaling or quiet?
87                 	 */
88                	if (Dbl_isone_signaling(opnd1p1)) {
89                        	/* trap if INVALIDTRAP enabled */
90                        	if (Is_invalidtrap_enabled())
91                            		return(INVALIDEXCEPTION);
92                        	/* make NaN quiet */
93                        	Set_invalidflag();
94                        	Dbl_set_quiet(opnd1p1);
95                	}
96			/*
97			 * is second operand a signaling NaN?
98			 */
99			else if (Dbl_is_signalingnan(opnd2p1)) {
100                        	/* trap if INVALIDTRAP enabled */
101                        	if (Is_invalidtrap_enabled())
102                            		return(INVALIDEXCEPTION);
103                        	/* make NaN quiet */
104                        	Set_invalidflag();
105                        	Dbl_set_quiet(opnd2p1);
106				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
107                		return(NOEXCEPTION);
108			}
109                	/*
110                 	 * return quiet NaN
111                 	 */
112			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
113                	return(NOEXCEPTION);
114		}
115	}
116	/*
117	 * check second operand for NaN's or infinity
118	 */
119	if (Dbl_isinfinity_exponent(opnd2p1)) {
120		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
121			if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
122				/* invalid since operands are zero & infinity */
123				if (Is_invalidtrap_enabled())
124                                	return(INVALIDEXCEPTION);
125                                Set_invalidflag();
126                                Dbl_makequietnan(opnd2p1,opnd2p2);
127				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
128				return(NOEXCEPTION);
129			}
130			/*
131			 * return infinity
132			 */
133			Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
134			Dbl_copytoptr(resultp1,resultp2,dstptr);
135			return(NOEXCEPTION);
136		}
137                /*
138                 * is NaN; signaling or quiet?
139                 */
140                if (Dbl_isone_signaling(opnd2p1)) {
141                        /* trap if INVALIDTRAP enabled */
142                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
143                        /* make NaN quiet */
144                        Set_invalidflag();
145                        Dbl_set_quiet(opnd2p1);
146                }
147                /*
148                 * return quiet NaN
149                 */
150		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
151                return(NOEXCEPTION);
152	}
153	/*
154	 * Generate exponent
155	 */
156	dest_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) -DBL_BIAS;
157
158	/*
159	 * Generate mantissa
160	 */
161	if (Dbl_isnotzero_exponent(opnd1p1)) {
162		/* set hidden bit */
163		Dbl_clear_signexponent_set_hidden(opnd1p1);
164	}
165	else {
166		/* check for zero */
167		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
168			Dbl_setzero_exponentmantissa(resultp1,resultp2);
169			Dbl_copytoptr(resultp1,resultp2,dstptr);
170			return(NOEXCEPTION);
171		}
172                /* is denormalized, adjust exponent */
173                Dbl_clear_signexponent(opnd1p1);
174                Dbl_leftshiftby1(opnd1p1,opnd1p2);
175		Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
176	}
177	/* opnd2 needs to have hidden bit set with msb in hidden bit */
178	if (Dbl_isnotzero_exponent(opnd2p1)) {
179		Dbl_clear_signexponent_set_hidden(opnd2p1);
180	}
181	else {
182		/* check for zero */
183		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
184			Dbl_setzero_exponentmantissa(resultp1,resultp2);
185			Dbl_copytoptr(resultp1,resultp2,dstptr);
186			return(NOEXCEPTION);
187		}
188                /* is denormalized; want to normalize */
189                Dbl_clear_signexponent(opnd2p1);
190                Dbl_leftshiftby1(opnd2p1,opnd2p2);
191		Dbl_normalize(opnd2p1,opnd2p2,dest_exponent);
192	}
193
194	/* Multiply two source mantissas together */
195
196	/* make room for guard bits */
197	Dbl_leftshiftby7(opnd2p1,opnd2p2);
198	Dbl_setzero(opnd3p1,opnd3p2);
199        /*
200         * Four bits at a time are inspected in each loop, and a
201         * simple shift and add multiply algorithm is used.
202         */
203	for (count=1;count<=DBL_P;count+=4) {
204		stickybit |= Dlow4p2(opnd3p2);
205		Dbl_rightshiftby4(opnd3p1,opnd3p2);
206		if (Dbit28p2(opnd1p2)) {
207	 		/* Twoword_add should be an ADDC followed by an ADD. */
208                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<3 | opnd2p2>>29,
209				    opnd2p2<<3);
210		}
211		if (Dbit29p2(opnd1p2)) {
212                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<2 | opnd2p2>>30,
213				    opnd2p2<<2);
214		}
215		if (Dbit30p2(opnd1p2)) {
216                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<1 | opnd2p2>>31,
217				    opnd2p2<<1);
218		}
219		if (Dbit31p2(opnd1p2)) {
220                        Twoword_add(opnd3p1, opnd3p2, opnd2p1, opnd2p2);
221		}
222		Dbl_rightshiftby4(opnd1p1,opnd1p2);
223	}
224	if (Dbit3p1(opnd3p1)==0) {
225		Dbl_leftshiftby1(opnd3p1,opnd3p2);
226	}
227	else {
228		/* result mantissa >= 2. */
229		dest_exponent++;
230	}
231	/* check for denormalized result */
232	while (Dbit3p1(opnd3p1)==0) {
233		Dbl_leftshiftby1(opnd3p1,opnd3p2);
234		dest_exponent--;
235	}
236	/*
237	 * check for guard, sticky and inexact bits
238	 */
239	stickybit |= Dallp2(opnd3p2) << 25;
240	guardbit = (Dallp2(opnd3p2) << 24) >> 31;
241	inexact = guardbit | stickybit;
242
243	/* align result mantissa */
244	Dbl_rightshiftby8(opnd3p1,opnd3p2);
245
246	/*
247	 * round result
248	 */
249	if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
250		Dbl_clear_signexponent(opnd3p1);
251		switch (Rounding_mode()) {
252			case ROUNDPLUS:
253				if (Dbl_iszero_sign(resultp1))
254					Dbl_increment(opnd3p1,opnd3p2);
255				break;
256			case ROUNDMINUS:
257				if (Dbl_isone_sign(resultp1))
258					Dbl_increment(opnd3p1,opnd3p2);
259				break;
260			case ROUNDNEAREST:
261				if (guardbit) {
262			   	if (stickybit || Dbl_isone_lowmantissap2(opnd3p2))
263			      	Dbl_increment(opnd3p1,opnd3p2);
264				}
265		}
266		if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
267	}
268	Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
269
270        /*
271         * Test for overflow
272         */
273	if (dest_exponent >= DBL_INFINITY_EXPONENT) {
274                /* trap if OVERFLOWTRAP enabled */
275                if (Is_overflowtrap_enabled()) {
276                        /*
277                         * Adjust bias of result
278                         */
279			Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
280			Dbl_copytoptr(resultp1,resultp2,dstptr);
281			if (inexact)
282			    if (Is_inexacttrap_enabled())
283				return (OVERFLOWEXCEPTION | INEXACTEXCEPTION);
284			    else Set_inexactflag();
285			return (OVERFLOWEXCEPTION);
286                }
287		inexact = TRUE;
288		Set_overflowflag();
289                /* set result to infinity or largest number */
290		Dbl_setoverflow(resultp1,resultp2);
291	}
292        /*
293         * Test for underflow
294         */
295	else if (dest_exponent <= 0) {
296                /* trap if UNDERFLOWTRAP enabled */
297                if (Is_underflowtrap_enabled()) {
298                        /*
299                         * Adjust bias of result
300                         */
301			Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
302			Dbl_copytoptr(resultp1,resultp2,dstptr);
303			if (inexact)
304			    if (Is_inexacttrap_enabled())
305				return (UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
306			    else Set_inexactflag();
307			return (UNDERFLOWEXCEPTION);
308                }
309
310		/* Determine if should set underflow flag */
311		is_tiny = TRUE;
312		if (dest_exponent == 0 && inexact) {
313			switch (Rounding_mode()) {
314			case ROUNDPLUS:
315				if (Dbl_iszero_sign(resultp1)) {
316					Dbl_increment(opnd3p1,opnd3p2);
317					if (Dbl_isone_hiddenoverflow(opnd3p1))
318                			    is_tiny = FALSE;
319					Dbl_decrement(opnd3p1,opnd3p2);
320				}
321				break;
322			case ROUNDMINUS:
323				if (Dbl_isone_sign(resultp1)) {
324					Dbl_increment(opnd3p1,opnd3p2);
325					if (Dbl_isone_hiddenoverflow(opnd3p1))
326                			    is_tiny = FALSE;
327					Dbl_decrement(opnd3p1,opnd3p2);
328				}
329				break;
330			case ROUNDNEAREST:
331				if (guardbit && (stickybit ||
332				    Dbl_isone_lowmantissap2(opnd3p2))) {
333				      	Dbl_increment(opnd3p1,opnd3p2);
334					if (Dbl_isone_hiddenoverflow(opnd3p1))
335                			    is_tiny = FALSE;
336					Dbl_decrement(opnd3p1,opnd3p2);
337				}
338				break;
339			}
340		}
341
342		/*
343		 * denormalize result or set to signed zero
344		 */
345		stickybit = inexact;
346		Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
347		 stickybit,inexact);
348
349		/* return zero or smallest number */
350		if (inexact) {
351			switch (Rounding_mode()) {
352			case ROUNDPLUS:
353				if (Dbl_iszero_sign(resultp1)) {
354					Dbl_increment(opnd3p1,opnd3p2);
355				}
356				break;
357			case ROUNDMINUS:
358				if (Dbl_isone_sign(resultp1)) {
359					Dbl_increment(opnd3p1,opnd3p2);
360				}
361				break;
362			case ROUNDNEAREST:
363				if (guardbit && (stickybit ||
364				    Dbl_isone_lowmantissap2(opnd3p2))) {
365			      		Dbl_increment(opnd3p1,opnd3p2);
366				}
367				break;
368			}
369                	if (is_tiny) Set_underflowflag();
370		}
371		Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
372	}
373	else Dbl_set_exponent(resultp1,dest_exponent);
374	/* check for inexact */
375	Dbl_copytoptr(resultp1,resultp2,dstptr);
376	if (inexact) {
377		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
378		else Set_inexactflag();
379	}
380	return(NOEXCEPTION);
381}
382