xref: /openbmc/linux/arch/x86/math-emu/reg_round.S (revision 14b476e0)
1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */
2da957e11SThomas Gleixner	.file "reg_round.S"
3da957e11SThomas Gleixner/*---------------------------------------------------------------------------+
4da957e11SThomas Gleixner |  reg_round.S                                                              |
5da957e11SThomas Gleixner |                                                                           |
6da957e11SThomas Gleixner | Rounding/truncation/etc for FPU basic arithmetic functions.               |
7da957e11SThomas Gleixner |                                                                           |
8da957e11SThomas Gleixner | Copyright (C) 1993,1995,1997                                              |
9da957e11SThomas Gleixner |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
10da957e11SThomas Gleixner |                       Australia.  E-mail billm@suburbia.net               |
11da957e11SThomas Gleixner |                                                                           |
12da957e11SThomas Gleixner | This code has four possible entry points.                                 |
13da957e11SThomas Gleixner | The following must be entered by a jmp instruction:                       |
14da957e11SThomas Gleixner |   fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit.                  |
15da957e11SThomas Gleixner |                                                                           |
16da957e11SThomas Gleixner | The FPU_round entry point is intended to be used by C code.               |
17da957e11SThomas Gleixner | From C, call as:                                                          |
18da957e11SThomas Gleixner |  int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
19da957e11SThomas Gleixner |                                                                           |
20da957e11SThomas Gleixner |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
21da957e11SThomas Gleixner |    one was raised, or -1 on internal error.                               |
22da957e11SThomas Gleixner |                                                                           |
23da957e11SThomas Gleixner | For correct "up" and "down" rounding, the argument must have the correct  |
24da957e11SThomas Gleixner | sign.                                                                     |
25da957e11SThomas Gleixner |                                                                           |
26da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
27da957e11SThomas Gleixner
28da957e11SThomas Gleixner/*---------------------------------------------------------------------------+
29da957e11SThomas Gleixner | Four entry points.                                                        |
30da957e11SThomas Gleixner |                                                                           |
31da957e11SThomas Gleixner | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points:     |
32da957e11SThomas Gleixner |  %eax:%ebx  64 bit significand                                            |
33da957e11SThomas Gleixner |  %edx       32 bit extension of the significand                           |
34da957e11SThomas Gleixner |  %edi       pointer to an FPU_REG for the result to be stored             |
35da957e11SThomas Gleixner |  stack      calling function must have set up a C stack frame and         |
36da957e11SThomas Gleixner |             pushed %esi, %edi, and %ebx                                   |
37da957e11SThomas Gleixner |                                                                           |
38da957e11SThomas Gleixner | Needed just for the fpu_reg_round_sqrt entry point:                       |
39da957e11SThomas Gleixner |  %cx  A control word in the same format as the FPU control word.          |
40da957e11SThomas Gleixner | Otherwise, PARAM4 must give such a value.                                 |
41da957e11SThomas Gleixner |                                                                           |
42da957e11SThomas Gleixner |                                                                           |
43da957e11SThomas Gleixner | The significand and its extension are assumed to be exact in the          |
44da957e11SThomas Gleixner | following sense:                                                          |
45da957e11SThomas Gleixner |   If the significand by itself is the exact result then the significand   |
46da957e11SThomas Gleixner |   extension (%edx) must contain 0, otherwise the significand extension    |
47da957e11SThomas Gleixner |   must be non-zero.                                                       |
48da957e11SThomas Gleixner |   If the significand extension is non-zero then the significand is        |
49da957e11SThomas Gleixner |   smaller than the magnitude of the correct exact result by an amount     |
50da957e11SThomas Gleixner |   greater than zero and less than one ls bit of the significand.          |
51da957e11SThomas Gleixner |   The significand extension is only required to have three possible       |
52da957e11SThomas Gleixner |   non-zero values:                                                        |
53da957e11SThomas Gleixner |       less than 0x80000000  <=> the significand is less than 1/2 an ls    |
54da957e11SThomas Gleixner |                                 bit smaller than the magnitude of the     |
55da957e11SThomas Gleixner |                                 true exact result.                        |
56da957e11SThomas Gleixner |         exactly 0x80000000  <=> the significand is exactly 1/2 an ls bit  |
57da957e11SThomas Gleixner |                                 smaller than the magnitude of the true    |
58da957e11SThomas Gleixner |                                 exact result.                             |
59da957e11SThomas Gleixner |    greater than 0x80000000  <=> the significand is more than 1/2 an ls    |
60da957e11SThomas Gleixner |                                 bit smaller than the magnitude of the     |
61da957e11SThomas Gleixner |                                 true exact result.                        |
62da957e11SThomas Gleixner |                                                                           |
63da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
64da957e11SThomas Gleixner
65da957e11SThomas Gleixner/*---------------------------------------------------------------------------+
66da957e11SThomas Gleixner |  The code in this module has become quite complex, but it should handle   |
67da957e11SThomas Gleixner |  all of the FPU flags which are set at this stage of the basic arithmetic |
68da957e11SThomas Gleixner |  computations.                                                            |
69da957e11SThomas Gleixner |  There are a few rare cases where the results are not set identically to  |
70da957e11SThomas Gleixner |  a real FPU. These require a bit more thought because at this stage the   |
71da957e11SThomas Gleixner |  results of the code here appear to be more consistent...                 |
72da957e11SThomas Gleixner |  This may be changed in a future version.                                 |
73da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
74da957e11SThomas Gleixner
75da957e11SThomas Gleixner
76da957e11SThomas Gleixner#include "fpu_emu.h"
77da957e11SThomas Gleixner#include "exception.h"
78da957e11SThomas Gleixner#include "control_w.h"
79da957e11SThomas Gleixner
80da957e11SThomas Gleixner/* Flags for FPU_bits_lost */
81da957e11SThomas Gleixner#define	LOST_DOWN	$1
82da957e11SThomas Gleixner#define	LOST_UP		$2
83da957e11SThomas Gleixner
84da957e11SThomas Gleixner/* Flags for FPU_denormal */
85da957e11SThomas Gleixner#define	DENORMAL	$1
86da957e11SThomas Gleixner#define	UNMASKED_UNDERFLOW $2
87da957e11SThomas Gleixner
88da957e11SThomas Gleixner
89da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU
90da957e11SThomas Gleixner/*	Make the code re-entrant by putting
91da957e11SThomas Gleixner	local storage on the stack: */
92da957e11SThomas Gleixner#define FPU_bits_lost	(%esp)
93da957e11SThomas Gleixner#define FPU_denormal	1(%esp)
94da957e11SThomas Gleixner
95da957e11SThomas Gleixner#else
96da957e11SThomas Gleixner/*	Not re-entrant, so we can gain speed by putting
97da957e11SThomas Gleixner	local storage in a static area: */
98da957e11SThomas Gleixner.data
99da957e11SThomas Gleixner	.align 4,0
100da957e11SThomas GleixnerFPU_bits_lost:
101da957e11SThomas Gleixner	.byte	0
102da957e11SThomas GleixnerFPU_denormal:
103da957e11SThomas Gleixner	.byte	0
104da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */
105da957e11SThomas Gleixner
106da957e11SThomas Gleixner
107da957e11SThomas Gleixner.text
108da957e11SThomas Gleixner.globl fpu_reg_round
109da957e11SThomas Gleixner.globl fpu_Arith_exit
110da957e11SThomas Gleixner
111da957e11SThomas Gleixner/* Entry point when called from C */
1126d685e53SJiri SlabySYM_FUNC_START(FPU_round)
113da957e11SThomas Gleixner	pushl	%ebp
114da957e11SThomas Gleixner	movl	%esp,%ebp
115da957e11SThomas Gleixner	pushl	%esi
116da957e11SThomas Gleixner	pushl	%edi
117da957e11SThomas Gleixner	pushl	%ebx
118da957e11SThomas Gleixner
119da957e11SThomas Gleixner	movl	PARAM1,%edi
120da957e11SThomas Gleixner	movl	SIGH(%edi),%eax
121da957e11SThomas Gleixner	movl	SIGL(%edi),%ebx
122da957e11SThomas Gleixner	movl	PARAM2,%edx
123da957e11SThomas Gleixner
124da957e11SThomas Gleixnerfpu_reg_round:			/* Normal entry point */
125da957e11SThomas Gleixner	movl	PARAM4,%ecx
126da957e11SThomas Gleixner
127da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU
128da957e11SThomas Gleixner	pushl	%ebx		/* adjust the stack pointer */
129da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */
130da957e11SThomas Gleixner
131da957e11SThomas Gleixner#ifdef PARANOID
132da957e11SThomas Gleixner/* Cannot use this here yet */
133da957e11SThomas Gleixner/*	orl	%eax,%eax */
134da957e11SThomas Gleixner/*	jns	L_entry_bugged */
135da957e11SThomas Gleixner#endif /* PARANOID */
136da957e11SThomas Gleixner
137da957e11SThomas Gleixner	cmpw	EXP_UNDER,EXP(%edi)
138da957e11SThomas Gleixner	jle	L_Make_denorm			/* The number is a de-normal */
139da957e11SThomas Gleixner
140da957e11SThomas Gleixner	movb	$0,FPU_denormal			/* 0 -> not a de-normal */
141da957e11SThomas Gleixner
142da957e11SThomas GleixnerDenorm_done:
143da957e11SThomas Gleixner	movb	$0,FPU_bits_lost		/* No bits yet lost in rounding */
144da957e11SThomas Gleixner
145da957e11SThomas Gleixner	movl	%ecx,%esi
146da957e11SThomas Gleixner	andl	CW_PC,%ecx
147da957e11SThomas Gleixner	cmpl	PR_64_BITS,%ecx
148da957e11SThomas Gleixner	je	LRound_To_64
149da957e11SThomas Gleixner
150da957e11SThomas Gleixner	cmpl	PR_53_BITS,%ecx
151da957e11SThomas Gleixner	je	LRound_To_53
152da957e11SThomas Gleixner
153da957e11SThomas Gleixner	cmpl	PR_24_BITS,%ecx
154da957e11SThomas Gleixner	je	LRound_To_24
155da957e11SThomas Gleixner
156da957e11SThomas Gleixner#ifdef PECULIAR_486
157da957e11SThomas Gleixner/* With the precision control bits set to 01 "(reserved)", a real 80486
158da957e11SThomas Gleixner   behaves as if the precision control bits were set to 11 "64 bits" */
159da957e11SThomas Gleixner	cmpl	PR_RESERVED_BITS,%ecx
160da957e11SThomas Gleixner	je	LRound_To_64
161da957e11SThomas Gleixner#ifdef PARANOID
162da957e11SThomas Gleixner	jmp	L_bugged_denorm_486
163da957e11SThomas Gleixner#endif /* PARANOID */
164da957e11SThomas Gleixner#else
165da957e11SThomas Gleixner#ifdef PARANOID
166da957e11SThomas Gleixner	jmp	L_bugged_denorm	/* There is no bug, just a bad control word */
167da957e11SThomas Gleixner#endif /* PARANOID */
168da957e11SThomas Gleixner#endif /* PECULIAR_486 */
169da957e11SThomas Gleixner
170da957e11SThomas Gleixner
171da957e11SThomas Gleixner/* Round etc to 24 bit precision */
172da957e11SThomas GleixnerLRound_To_24:
173da957e11SThomas Gleixner	movl	%esi,%ecx
174da957e11SThomas Gleixner	andl	CW_RC,%ecx
175da957e11SThomas Gleixner	cmpl	RC_RND,%ecx
176da957e11SThomas Gleixner	je	LRound_nearest_24
177da957e11SThomas Gleixner
178da957e11SThomas Gleixner	cmpl	RC_CHOP,%ecx
179da957e11SThomas Gleixner	je	LCheck_truncate_24
180da957e11SThomas Gleixner
181da957e11SThomas Gleixner	cmpl	RC_UP,%ecx		/* Towards +infinity */
182da957e11SThomas Gleixner	je	LUp_24
183da957e11SThomas Gleixner
184da957e11SThomas Gleixner	cmpl	RC_DOWN,%ecx		/* Towards -infinity */
185da957e11SThomas Gleixner	je	LDown_24
186da957e11SThomas Gleixner
187da957e11SThomas Gleixner#ifdef PARANOID
188da957e11SThomas Gleixner	jmp	L_bugged_round24
189da957e11SThomas Gleixner#endif /* PARANOID */
190da957e11SThomas Gleixner
191da957e11SThomas GleixnerLUp_24:
192da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
193da957e11SThomas Gleixner	jne	LCheck_truncate_24	/* If negative then  up==truncate */
194da957e11SThomas Gleixner
195da957e11SThomas Gleixner	jmp	LCheck_24_round_up
196da957e11SThomas Gleixner
197da957e11SThomas GleixnerLDown_24:
198da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
199da957e11SThomas Gleixner	je	LCheck_truncate_24	/* If positive then  down==truncate */
200da957e11SThomas Gleixner
201da957e11SThomas GleixnerLCheck_24_round_up:
202da957e11SThomas Gleixner	movl	%eax,%ecx
203da957e11SThomas Gleixner	andl	$0x000000ff,%ecx
204da957e11SThomas Gleixner	orl	%ebx,%ecx
205da957e11SThomas Gleixner	orl	%edx,%ecx
206da957e11SThomas Gleixner	jnz	LDo_24_round_up
207da957e11SThomas Gleixner	jmp	L_Re_normalise
208da957e11SThomas Gleixner
209da957e11SThomas GleixnerLRound_nearest_24:
210da957e11SThomas Gleixner	/* Do rounding of the 24th bit if needed (nearest or even) */
211da957e11SThomas Gleixner	movl	%eax,%ecx
212da957e11SThomas Gleixner	andl	$0x000000ff,%ecx
213da957e11SThomas Gleixner	cmpl	$0x00000080,%ecx
214da957e11SThomas Gleixner	jc	LCheck_truncate_24	/* less than half, no increment needed */
215da957e11SThomas Gleixner
216da957e11SThomas Gleixner	jne	LGreater_Half_24	/* greater than half, increment needed */
217da957e11SThomas Gleixner
218da957e11SThomas Gleixner	/* Possibly half, we need to check the ls bits */
219da957e11SThomas Gleixner	orl	%ebx,%ebx
220da957e11SThomas Gleixner	jnz	LGreater_Half_24	/* greater than half, increment needed */
221da957e11SThomas Gleixner
222da957e11SThomas Gleixner	orl	%edx,%edx
223da957e11SThomas Gleixner	jnz	LGreater_Half_24	/* greater than half, increment needed */
224da957e11SThomas Gleixner
225da957e11SThomas Gleixner	/* Exactly half, increment only if 24th bit is 1 (round to even) */
226da957e11SThomas Gleixner	testl	$0x00000100,%eax
227da957e11SThomas Gleixner	jz	LDo_truncate_24
228da957e11SThomas Gleixner
229da957e11SThomas GleixnerLGreater_Half_24:			/* Rounding: increment at the 24th bit */
230da957e11SThomas GleixnerLDo_24_round_up:
231da957e11SThomas Gleixner	andl	$0xffffff00,%eax	/* Truncate to 24 bits */
232da957e11SThomas Gleixner	xorl	%ebx,%ebx
233da957e11SThomas Gleixner	movb	LOST_UP,FPU_bits_lost
234da957e11SThomas Gleixner	addl	$0x00000100,%eax
235da957e11SThomas Gleixner	jmp	LCheck_Round_Overflow
236da957e11SThomas Gleixner
237da957e11SThomas GleixnerLCheck_truncate_24:
238da957e11SThomas Gleixner	movl	%eax,%ecx
239da957e11SThomas Gleixner	andl	$0x000000ff,%ecx
240da957e11SThomas Gleixner	orl	%ebx,%ecx
241da957e11SThomas Gleixner	orl	%edx,%ecx
242da957e11SThomas Gleixner	jz	L_Re_normalise		/* No truncation needed */
243da957e11SThomas Gleixner
244da957e11SThomas GleixnerLDo_truncate_24:
245da957e11SThomas Gleixner	andl	$0xffffff00,%eax	/* Truncate to 24 bits */
246da957e11SThomas Gleixner	xorl	%ebx,%ebx
247da957e11SThomas Gleixner	movb	LOST_DOWN,FPU_bits_lost
248da957e11SThomas Gleixner	jmp	L_Re_normalise
249da957e11SThomas Gleixner
250da957e11SThomas Gleixner
251da957e11SThomas Gleixner/* Round etc to 53 bit precision */
252da957e11SThomas GleixnerLRound_To_53:
253da957e11SThomas Gleixner	movl	%esi,%ecx
254da957e11SThomas Gleixner	andl	CW_RC,%ecx
255da957e11SThomas Gleixner	cmpl	RC_RND,%ecx
256da957e11SThomas Gleixner	je	LRound_nearest_53
257da957e11SThomas Gleixner
258da957e11SThomas Gleixner	cmpl	RC_CHOP,%ecx
259da957e11SThomas Gleixner	je	LCheck_truncate_53
260da957e11SThomas Gleixner
261da957e11SThomas Gleixner	cmpl	RC_UP,%ecx		/* Towards +infinity */
262da957e11SThomas Gleixner	je	LUp_53
263da957e11SThomas Gleixner
264da957e11SThomas Gleixner	cmpl	RC_DOWN,%ecx		/* Towards -infinity */
265da957e11SThomas Gleixner	je	LDown_53
266da957e11SThomas Gleixner
267da957e11SThomas Gleixner#ifdef PARANOID
268da957e11SThomas Gleixner	jmp	L_bugged_round53
269da957e11SThomas Gleixner#endif /* PARANOID */
270da957e11SThomas Gleixner
271da957e11SThomas GleixnerLUp_53:
272da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
273da957e11SThomas Gleixner	jne	LCheck_truncate_53	/* If negative then  up==truncate */
274da957e11SThomas Gleixner
275da957e11SThomas Gleixner	jmp	LCheck_53_round_up
276da957e11SThomas Gleixner
277da957e11SThomas GleixnerLDown_53:
278da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
279da957e11SThomas Gleixner	je	LCheck_truncate_53	/* If positive then  down==truncate */
280da957e11SThomas Gleixner
281da957e11SThomas GleixnerLCheck_53_round_up:
282da957e11SThomas Gleixner	movl	%ebx,%ecx
283da957e11SThomas Gleixner	andl	$0x000007ff,%ecx
284da957e11SThomas Gleixner	orl	%edx,%ecx
285da957e11SThomas Gleixner	jnz	LDo_53_round_up
286da957e11SThomas Gleixner	jmp	L_Re_normalise
287da957e11SThomas Gleixner
288da957e11SThomas GleixnerLRound_nearest_53:
289da957e11SThomas Gleixner	/* Do rounding of the 53rd bit if needed (nearest or even) */
290da957e11SThomas Gleixner	movl	%ebx,%ecx
291da957e11SThomas Gleixner	andl	$0x000007ff,%ecx
292da957e11SThomas Gleixner	cmpl	$0x00000400,%ecx
293da957e11SThomas Gleixner	jc	LCheck_truncate_53	/* less than half, no increment needed */
294da957e11SThomas Gleixner
295da957e11SThomas Gleixner	jnz	LGreater_Half_53	/* greater than half, increment needed */
296da957e11SThomas Gleixner
297da957e11SThomas Gleixner	/* Possibly half, we need to check the ls bits */
298da957e11SThomas Gleixner	orl	%edx,%edx
299da957e11SThomas Gleixner	jnz	LGreater_Half_53	/* greater than half, increment needed */
300da957e11SThomas Gleixner
301da957e11SThomas Gleixner	/* Exactly half, increment only if 53rd bit is 1 (round to even) */
302da957e11SThomas Gleixner	testl	$0x00000800,%ebx
303da957e11SThomas Gleixner	jz	LTruncate_53
304da957e11SThomas Gleixner
305da957e11SThomas GleixnerLGreater_Half_53:			/* Rounding: increment at the 53rd bit */
306da957e11SThomas GleixnerLDo_53_round_up:
307da957e11SThomas Gleixner	movb	LOST_UP,FPU_bits_lost
308da957e11SThomas Gleixner	andl	$0xfffff800,%ebx	/* Truncate to 53 bits */
309da957e11SThomas Gleixner	addl	$0x00000800,%ebx
310da957e11SThomas Gleixner	adcl	$0,%eax
311da957e11SThomas Gleixner	jmp	LCheck_Round_Overflow
312da957e11SThomas Gleixner
313da957e11SThomas GleixnerLCheck_truncate_53:
314da957e11SThomas Gleixner	movl	%ebx,%ecx
315da957e11SThomas Gleixner	andl	$0x000007ff,%ecx
316da957e11SThomas Gleixner	orl	%edx,%ecx
317da957e11SThomas Gleixner	jz	L_Re_normalise
318da957e11SThomas Gleixner
319da957e11SThomas GleixnerLTruncate_53:
320da957e11SThomas Gleixner	movb	LOST_DOWN,FPU_bits_lost
321da957e11SThomas Gleixner	andl	$0xfffff800,%ebx	/* Truncate to 53 bits */
322da957e11SThomas Gleixner	jmp	L_Re_normalise
323da957e11SThomas Gleixner
324da957e11SThomas Gleixner
325da957e11SThomas Gleixner/* Round etc to 64 bit precision */
326da957e11SThomas GleixnerLRound_To_64:
327da957e11SThomas Gleixner	movl	%esi,%ecx
328da957e11SThomas Gleixner	andl	CW_RC,%ecx
329da957e11SThomas Gleixner	cmpl	RC_RND,%ecx
330da957e11SThomas Gleixner	je	LRound_nearest_64
331da957e11SThomas Gleixner
332da957e11SThomas Gleixner	cmpl	RC_CHOP,%ecx
333da957e11SThomas Gleixner	je	LCheck_truncate_64
334da957e11SThomas Gleixner
335da957e11SThomas Gleixner	cmpl	RC_UP,%ecx		/* Towards +infinity */
336da957e11SThomas Gleixner	je	LUp_64
337da957e11SThomas Gleixner
338da957e11SThomas Gleixner	cmpl	RC_DOWN,%ecx		/* Towards -infinity */
339da957e11SThomas Gleixner	je	LDown_64
340da957e11SThomas Gleixner
341da957e11SThomas Gleixner#ifdef PARANOID
342da957e11SThomas Gleixner	jmp	L_bugged_round64
343da957e11SThomas Gleixner#endif /* PARANOID */
344da957e11SThomas Gleixner
345da957e11SThomas GleixnerLUp_64:
346da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
347da957e11SThomas Gleixner	jne	LCheck_truncate_64	/* If negative then  up==truncate */
348da957e11SThomas Gleixner
349da957e11SThomas Gleixner	orl	%edx,%edx
350da957e11SThomas Gleixner	jnz	LDo_64_round_up
351da957e11SThomas Gleixner	jmp	L_Re_normalise
352da957e11SThomas Gleixner
353da957e11SThomas GleixnerLDown_64:
354da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
355da957e11SThomas Gleixner	je	LCheck_truncate_64	/* If positive then  down==truncate */
356da957e11SThomas Gleixner
357da957e11SThomas Gleixner	orl	%edx,%edx
358da957e11SThomas Gleixner	jnz	LDo_64_round_up
359da957e11SThomas Gleixner	jmp	L_Re_normalise
360da957e11SThomas Gleixner
361da957e11SThomas GleixnerLRound_nearest_64:
362da957e11SThomas Gleixner	cmpl	$0x80000000,%edx
363da957e11SThomas Gleixner	jc	LCheck_truncate_64
364da957e11SThomas Gleixner
365da957e11SThomas Gleixner	jne	LDo_64_round_up
366da957e11SThomas Gleixner
367da957e11SThomas Gleixner	/* Now test for round-to-even */
368da957e11SThomas Gleixner	testb	$1,%bl
369da957e11SThomas Gleixner	jz	LCheck_truncate_64
370da957e11SThomas Gleixner
371da957e11SThomas GleixnerLDo_64_round_up:
372da957e11SThomas Gleixner	movb	LOST_UP,FPU_bits_lost
373da957e11SThomas Gleixner	addl	$1,%ebx
374da957e11SThomas Gleixner	adcl	$0,%eax
375da957e11SThomas Gleixner
376da957e11SThomas GleixnerLCheck_Round_Overflow:
377da957e11SThomas Gleixner	jnc	L_Re_normalise
378da957e11SThomas Gleixner
379da957e11SThomas Gleixner	/* Overflow, adjust the result (significand to 1.0) */
380da957e11SThomas Gleixner	rcrl	$1,%eax
381da957e11SThomas Gleixner	rcrl	$1,%ebx
382da957e11SThomas Gleixner	incw	EXP(%edi)
383da957e11SThomas Gleixner	jmp	L_Re_normalise
384da957e11SThomas Gleixner
385da957e11SThomas GleixnerLCheck_truncate_64:
386da957e11SThomas Gleixner	orl	%edx,%edx
387da957e11SThomas Gleixner	jz	L_Re_normalise
388da957e11SThomas Gleixner
389da957e11SThomas GleixnerLTruncate_64:
390da957e11SThomas Gleixner	movb	LOST_DOWN,FPU_bits_lost
391da957e11SThomas Gleixner
392da957e11SThomas GleixnerL_Re_normalise:
393da957e11SThomas Gleixner	testb	$0xff,FPU_denormal
394da957e11SThomas Gleixner	jnz	Normalise_result
395da957e11SThomas Gleixner
396da957e11SThomas GleixnerL_Normalised:
397da957e11SThomas Gleixner	movl	TAG_Valid,%edx
398da957e11SThomas Gleixner
399da957e11SThomas GleixnerL_deNormalised:
400da957e11SThomas Gleixner	cmpb	LOST_UP,FPU_bits_lost
401da957e11SThomas Gleixner	je	L_precision_lost_up
402da957e11SThomas Gleixner
403da957e11SThomas Gleixner	cmpb	LOST_DOWN,FPU_bits_lost
404da957e11SThomas Gleixner	je	L_precision_lost_down
405da957e11SThomas Gleixner
406da957e11SThomas GleixnerL_no_precision_loss:
407da957e11SThomas Gleixner	/* store the result */
408da957e11SThomas Gleixner
409da957e11SThomas GleixnerL_Store_significand:
410da957e11SThomas Gleixner	movl	%eax,SIGH(%edi)
411da957e11SThomas Gleixner	movl	%ebx,SIGL(%edi)
412da957e11SThomas Gleixner
413da957e11SThomas Gleixner	cmpw	EXP_OVER,EXP(%edi)
414da957e11SThomas Gleixner	jge	L_overflow
415da957e11SThomas Gleixner
416da957e11SThomas Gleixner	movl	%edx,%eax
417da957e11SThomas Gleixner
418da957e11SThomas Gleixner	/* Convert the exponent to 80x87 form. */
419da957e11SThomas Gleixner	addw	EXTENDED_Ebias,EXP(%edi)
420da957e11SThomas Gleixner	andw	$0x7fff,EXP(%edi)
421da957e11SThomas Gleixner
422da957e11SThomas Gleixnerfpu_reg_round_signed_special_exit:
423da957e11SThomas Gleixner
424da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
425da957e11SThomas Gleixner	je	fpu_reg_round_special_exit
426da957e11SThomas Gleixner
427da957e11SThomas Gleixner	orw	$0x8000,EXP(%edi)	/* Negative sign for the result. */
428da957e11SThomas Gleixner
429da957e11SThomas Gleixnerfpu_reg_round_special_exit:
430da957e11SThomas Gleixner
431da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU
432da957e11SThomas Gleixner	popl	%ebx		/* adjust the stack pointer */
433da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */
434da957e11SThomas Gleixner
435da957e11SThomas Gleixnerfpu_Arith_exit:
436da957e11SThomas Gleixner	popl	%ebx
437da957e11SThomas Gleixner	popl	%edi
438da957e11SThomas Gleixner	popl	%esi
439da957e11SThomas Gleixner	leave
440*14b476e0SPeter Zijlstra	RET
441da957e11SThomas Gleixner
442da957e11SThomas Gleixner
443da957e11SThomas Gleixner/*
444da957e11SThomas Gleixner * Set the FPU status flags to represent precision loss due to
445da957e11SThomas Gleixner * round-up.
446da957e11SThomas Gleixner */
447da957e11SThomas GleixnerL_precision_lost_up:
448da957e11SThomas Gleixner	push	%edx
449da957e11SThomas Gleixner	push	%eax
450da957e11SThomas Gleixner	call	set_precision_flag_up
451da957e11SThomas Gleixner	popl	%eax
452da957e11SThomas Gleixner	popl	%edx
453da957e11SThomas Gleixner	jmp	L_no_precision_loss
454da957e11SThomas Gleixner
455da957e11SThomas Gleixner/*
456da957e11SThomas Gleixner * Set the FPU status flags to represent precision loss due to
457da957e11SThomas Gleixner * truncation.
458da957e11SThomas Gleixner */
459da957e11SThomas GleixnerL_precision_lost_down:
460da957e11SThomas Gleixner	push	%edx
461da957e11SThomas Gleixner	push	%eax
462da957e11SThomas Gleixner	call	set_precision_flag_down
463da957e11SThomas Gleixner	popl	%eax
464da957e11SThomas Gleixner	popl	%edx
465da957e11SThomas Gleixner	jmp	L_no_precision_loss
466da957e11SThomas Gleixner
467da957e11SThomas Gleixner
468da957e11SThomas Gleixner/*
469da957e11SThomas Gleixner * The number is a denormal (which might get rounded up to a normal)
470da957e11SThomas Gleixner * Shift the number right the required number of bits, which will
471da957e11SThomas Gleixner * have to be undone later...
472da957e11SThomas Gleixner */
473da957e11SThomas GleixnerL_Make_denorm:
474da957e11SThomas Gleixner	/* The action to be taken depends upon whether the underflow
475da957e11SThomas Gleixner	   exception is masked */
476da957e11SThomas Gleixner	testb	CW_Underflow,%cl		/* Underflow mask. */
477da957e11SThomas Gleixner	jz	Unmasked_underflow		/* Do not make a denormal. */
478da957e11SThomas Gleixner
479da957e11SThomas Gleixner	movb	DENORMAL,FPU_denormal
480da957e11SThomas Gleixner
481da957e11SThomas Gleixner	pushl	%ecx		/* Save */
482da957e11SThomas Gleixner	movw	EXP_UNDER+1,%cx
483da957e11SThomas Gleixner	subw	EXP(%edi),%cx
484da957e11SThomas Gleixner
485da957e11SThomas Gleixner	cmpw	$64,%cx	/* shrd only works for 0..31 bits */
486da957e11SThomas Gleixner	jnc	Denorm_shift_more_than_63
487da957e11SThomas Gleixner
488da957e11SThomas Gleixner	cmpw	$32,%cx	/* shrd only works for 0..31 bits */
489da957e11SThomas Gleixner	jnc	Denorm_shift_more_than_32
490da957e11SThomas Gleixner
491da957e11SThomas Gleixner/*
492da957e11SThomas Gleixner * We got here without jumps by assuming that the most common requirement
493da957e11SThomas Gleixner *   is for a small de-normalising shift.
494da957e11SThomas Gleixner * Shift by [1..31] bits
495da957e11SThomas Gleixner */
496da957e11SThomas Gleixner	addw	%cx,EXP(%edi)
497da957e11SThomas Gleixner	orl	%edx,%edx	/* extension */
498da957e11SThomas Gleixner	setne	%ch		/* Save whether %edx is non-zero */
499da957e11SThomas Gleixner	xorl	%edx,%edx
500da957e11SThomas Gleixner	shrd	%cl,%ebx,%edx
501da957e11SThomas Gleixner	shrd	%cl,%eax,%ebx
502da957e11SThomas Gleixner	shr	%cl,%eax
503da957e11SThomas Gleixner	orb	%ch,%dl
504da957e11SThomas Gleixner	popl	%ecx
505da957e11SThomas Gleixner	jmp	Denorm_done
506da957e11SThomas Gleixner
507da957e11SThomas Gleixner/* Shift by [32..63] bits */
508da957e11SThomas GleixnerDenorm_shift_more_than_32:
509da957e11SThomas Gleixner	addw	%cx,EXP(%edi)
510da957e11SThomas Gleixner	subb	$32,%cl
511da957e11SThomas Gleixner	orl	%edx,%edx
512da957e11SThomas Gleixner	setne	%ch
513da957e11SThomas Gleixner	orb	%ch,%bl
514da957e11SThomas Gleixner	xorl	%edx,%edx
515da957e11SThomas Gleixner	shrd	%cl,%ebx,%edx
516da957e11SThomas Gleixner	shrd	%cl,%eax,%ebx
517da957e11SThomas Gleixner	shr	%cl,%eax
518da957e11SThomas Gleixner	orl	%edx,%edx		/* test these 32 bits */
519da957e11SThomas Gleixner	setne	%cl
520da957e11SThomas Gleixner	orb	%ch,%bl
521da957e11SThomas Gleixner	orb	%cl,%bl
522da957e11SThomas Gleixner	movl	%ebx,%edx
523da957e11SThomas Gleixner	movl	%eax,%ebx
524da957e11SThomas Gleixner	xorl	%eax,%eax
525da957e11SThomas Gleixner	popl	%ecx
526da957e11SThomas Gleixner	jmp	Denorm_done
527da957e11SThomas Gleixner
528da957e11SThomas Gleixner/* Shift by [64..) bits */
529da957e11SThomas GleixnerDenorm_shift_more_than_63:
530da957e11SThomas Gleixner	cmpw	$64,%cx
531da957e11SThomas Gleixner	jne	Denorm_shift_more_than_64
532da957e11SThomas Gleixner
533da957e11SThomas Gleixner/* Exactly 64 bit shift */
534da957e11SThomas Gleixner	addw	%cx,EXP(%edi)
535da957e11SThomas Gleixner	xorl	%ecx,%ecx
536da957e11SThomas Gleixner	orl	%edx,%edx
537da957e11SThomas Gleixner	setne	%cl
538da957e11SThomas Gleixner	orl	%ebx,%ebx
539da957e11SThomas Gleixner	setne	%ch
540da957e11SThomas Gleixner	orb	%ch,%cl
541da957e11SThomas Gleixner	orb	%cl,%al
542da957e11SThomas Gleixner	movl	%eax,%edx
543da957e11SThomas Gleixner	xorl	%eax,%eax
544da957e11SThomas Gleixner	xorl	%ebx,%ebx
545da957e11SThomas Gleixner	popl	%ecx
546da957e11SThomas Gleixner	jmp	Denorm_done
547da957e11SThomas Gleixner
548da957e11SThomas GleixnerDenorm_shift_more_than_64:
549da957e11SThomas Gleixner	movw	EXP_UNDER+1,EXP(%edi)
550da957e11SThomas Gleixner/* This is easy, %eax must be non-zero, so.. */
551da957e11SThomas Gleixner	movl	$1,%edx
552da957e11SThomas Gleixner	xorl	%eax,%eax
553da957e11SThomas Gleixner	xorl	%ebx,%ebx
554da957e11SThomas Gleixner	popl	%ecx
555da957e11SThomas Gleixner	jmp	Denorm_done
556da957e11SThomas Gleixner
557da957e11SThomas Gleixner
558da957e11SThomas GleixnerUnmasked_underflow:
559da957e11SThomas Gleixner	movb	UNMASKED_UNDERFLOW,FPU_denormal
560da957e11SThomas Gleixner	jmp	Denorm_done
561da957e11SThomas Gleixner
562da957e11SThomas Gleixner
563da957e11SThomas Gleixner/* Undo the de-normalisation. */
564da957e11SThomas GleixnerNormalise_result:
565da957e11SThomas Gleixner	cmpb	UNMASKED_UNDERFLOW,FPU_denormal
566da957e11SThomas Gleixner	je	Signal_underflow
567da957e11SThomas Gleixner
568da957e11SThomas Gleixner/* The number must be a denormal if we got here. */
569da957e11SThomas Gleixner#ifdef PARANOID
570da957e11SThomas Gleixner	/* But check it... just in case. */
571da957e11SThomas Gleixner	cmpw	EXP_UNDER+1,EXP(%edi)
572da957e11SThomas Gleixner	jne	L_norm_bugged
573da957e11SThomas Gleixner#endif /* PARANOID */
574da957e11SThomas Gleixner
575da957e11SThomas Gleixner#ifdef PECULIAR_486
576da957e11SThomas Gleixner	/*
577da957e11SThomas Gleixner	 * This implements a special feature of 80486 behaviour.
578163b0991SIngo Molnar	 * Underflow will be signaled even if the number is
579da957e11SThomas Gleixner	 * not a denormal after rounding.
580da957e11SThomas Gleixner	 * This difference occurs only for masked underflow, and not
581da957e11SThomas Gleixner	 * in the unmasked case.
582da957e11SThomas Gleixner	 * Actual 80486 behaviour differs from this in some circumstances.
583da957e11SThomas Gleixner	 */
584da957e11SThomas Gleixner	orl	%eax,%eax		/* ms bits */
585da957e11SThomas Gleixner	js	LPseudoDenormal		/* Will be masked underflow */
586da957e11SThomas Gleixner#else
587da957e11SThomas Gleixner	orl	%eax,%eax		/* ms bits */
588da957e11SThomas Gleixner	js	L_Normalised		/* No longer a denormal */
589da957e11SThomas Gleixner#endif /* PECULIAR_486 */
590da957e11SThomas Gleixner
591da957e11SThomas Gleixner	jnz	LDenormal_adj_exponent
592da957e11SThomas Gleixner
593da957e11SThomas Gleixner	orl	%ebx,%ebx
594da957e11SThomas Gleixner	jz	L_underflow_to_zero	/* The contents are zero */
595da957e11SThomas Gleixner
596da957e11SThomas GleixnerLDenormal_adj_exponent:
597da957e11SThomas Gleixner	decw	EXP(%edi)
598da957e11SThomas Gleixner
599da957e11SThomas GleixnerLPseudoDenormal:
600da957e11SThomas Gleixner	testb	$0xff,FPU_bits_lost	/* bits lost == underflow */
601da957e11SThomas Gleixner	movl	TAG_Special,%edx
602da957e11SThomas Gleixner	jz	L_deNormalised
603da957e11SThomas Gleixner
604da957e11SThomas Gleixner	/* There must be a masked underflow */
605da957e11SThomas Gleixner	push	%eax
606da957e11SThomas Gleixner	pushl	EX_Underflow
607da957e11SThomas Gleixner	call	EXCEPTION
608da957e11SThomas Gleixner	popl	%eax
609da957e11SThomas Gleixner	popl	%eax
610da957e11SThomas Gleixner	movl	TAG_Special,%edx
611da957e11SThomas Gleixner	jmp	L_deNormalised
612da957e11SThomas Gleixner
613da957e11SThomas Gleixner
614da957e11SThomas Gleixner/*
615da957e11SThomas Gleixner * The operations resulted in a number too small to represent.
616da957e11SThomas Gleixner * Masked response.
617da957e11SThomas Gleixner */
618da957e11SThomas GleixnerL_underflow_to_zero:
619da957e11SThomas Gleixner	push	%eax
620da957e11SThomas Gleixner	call	set_precision_flag_down
621da957e11SThomas Gleixner	popl	%eax
622da957e11SThomas Gleixner
623da957e11SThomas Gleixner	push	%eax
624da957e11SThomas Gleixner	pushl	EX_Underflow
625da957e11SThomas Gleixner	call	EXCEPTION
626da957e11SThomas Gleixner	popl	%eax
627da957e11SThomas Gleixner	popl	%eax
628da957e11SThomas Gleixner
629da957e11SThomas Gleixner/* Reduce the exponent to EXP_UNDER */
630da957e11SThomas Gleixner	movw	EXP_UNDER,EXP(%edi)
631da957e11SThomas Gleixner	movl	TAG_Zero,%edx
632da957e11SThomas Gleixner	jmp	L_Store_significand
633da957e11SThomas Gleixner
634da957e11SThomas Gleixner
635da957e11SThomas Gleixner/* The operations resulted in a number too large to represent. */
636da957e11SThomas GleixnerL_overflow:
637da957e11SThomas Gleixner	addw	EXTENDED_Ebias,EXP(%edi)	/* Set for unmasked response. */
638da957e11SThomas Gleixner	push	%edi
639da957e11SThomas Gleixner	call	arith_overflow
640da957e11SThomas Gleixner	pop	%edi
641da957e11SThomas Gleixner	jmp	fpu_reg_round_signed_special_exit
642da957e11SThomas Gleixner
643da957e11SThomas Gleixner
644da957e11SThomas GleixnerSignal_underflow:
645da957e11SThomas Gleixner	/* The number may have been changed to a non-denormal */
646da957e11SThomas Gleixner	/* by the rounding operations. */
647da957e11SThomas Gleixner	cmpw	EXP_UNDER,EXP(%edi)
648da957e11SThomas Gleixner	jle	Do_unmasked_underflow
649da957e11SThomas Gleixner
650da957e11SThomas Gleixner	jmp	L_Normalised
651da957e11SThomas Gleixner
652da957e11SThomas GleixnerDo_unmasked_underflow:
653da957e11SThomas Gleixner	/* Increase the exponent by the magic number */
654da957e11SThomas Gleixner	addw	$(3*(1<<13)),EXP(%edi)
655da957e11SThomas Gleixner	push	%eax
656da957e11SThomas Gleixner	pushl	EX_Underflow
657da957e11SThomas Gleixner	call	EXCEPTION
658da957e11SThomas Gleixner	popl	%eax
659da957e11SThomas Gleixner	popl	%eax
660da957e11SThomas Gleixner	jmp	L_Normalised
661da957e11SThomas Gleixner
662da957e11SThomas Gleixner
663da957e11SThomas Gleixner#ifdef PARANOID
664da957e11SThomas Gleixner#ifdef PECULIAR_486
665da957e11SThomas GleixnerL_bugged_denorm_486:
666da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x236
667da957e11SThomas Gleixner	call	EXCEPTION
668da957e11SThomas Gleixner	popl	%ebx
669da957e11SThomas Gleixner	jmp	L_exception_exit
670da957e11SThomas Gleixner#else
671da957e11SThomas GleixnerL_bugged_denorm:
672da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x230
673da957e11SThomas Gleixner	call	EXCEPTION
674da957e11SThomas Gleixner	popl	%ebx
675da957e11SThomas Gleixner	jmp	L_exception_exit
676da957e11SThomas Gleixner#endif /* PECULIAR_486 */
677da957e11SThomas Gleixner
678da957e11SThomas GleixnerL_bugged_round24:
679da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x231
680da957e11SThomas Gleixner	call	EXCEPTION
681da957e11SThomas Gleixner	popl	%ebx
682da957e11SThomas Gleixner	jmp	L_exception_exit
683da957e11SThomas Gleixner
684da957e11SThomas GleixnerL_bugged_round53:
685da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x232
686da957e11SThomas Gleixner	call	EXCEPTION
687da957e11SThomas Gleixner	popl	%ebx
688da957e11SThomas Gleixner	jmp	L_exception_exit
689da957e11SThomas Gleixner
690da957e11SThomas GleixnerL_bugged_round64:
691da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x233
692da957e11SThomas Gleixner	call	EXCEPTION
693da957e11SThomas Gleixner	popl	%ebx
694da957e11SThomas Gleixner	jmp	L_exception_exit
695da957e11SThomas Gleixner
696da957e11SThomas GleixnerL_norm_bugged:
697da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x234
698da957e11SThomas Gleixner	call	EXCEPTION
699da957e11SThomas Gleixner	popl	%ebx
700da957e11SThomas Gleixner	jmp	L_exception_exit
701da957e11SThomas Gleixner
702da957e11SThomas GleixnerL_entry_bugged:
703da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x235
704da957e11SThomas Gleixner	call	EXCEPTION
705da957e11SThomas Gleixner	popl	%ebx
706da957e11SThomas GleixnerL_exception_exit:
707da957e11SThomas Gleixner	mov	$-1,%eax
708da957e11SThomas Gleixner	jmp	fpu_reg_round_special_exit
709da957e11SThomas Gleixner#endif /* PARANOID */
710bd6be579SJiri Slaby
7116d685e53SJiri SlabySYM_FUNC_END(FPU_round)
712