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