1 ! bcc 386 floating point routines (version 2)
2 ! -- Fadd, Faddd, Faddf, Fsub, Fsubd, Fsubf, normalize2
7 #define FRAME_SIZE (3 * GENREG_SIZE + PC_SIZE)
20 mov eax,FRAME_SIZE+D_LOW[esp]
21 mov edx,FRAME_SIZE+D_HIGH[esp]
22 mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp]
23 mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp]
25 mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax
26 mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx
38 mov eax,FRAME_SIZE+D_LOW[esp]
39 mov edx,FRAME_SIZE+D_HIGH[esp]
43 mov FRAME_SIZE+D_LOW[esp],eax
44 mov FRAME_SIZE+D_HIGH[esp],edx
59 mov eax,FRAME_SIZE+D_LOW[esp] ! xl
60 mov edx,FRAME_SIZE+D_HIGH[esp] ! xu
62 mov FRAME_SIZE+D_LOW[esp],eax
63 mov FRAME_SIZE+D_HIGH[esp],edx
75 mov eax,FRAME_SIZE+D_LOW[esp]
76 mov edx,FRAME_SIZE+D_HIGH[esp]
77 mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp]
78 mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp]
79 xor ecx,#D_SIGN_MASK ! complement sign
81 mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax
82 mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx
94 mov eax,FRAME_SIZE+D_LOW[esp]
95 mov edx,FRAME_SIZE+D_HIGH[esp]
98 xor ecx,#D_SIGN_MASK ! complement sign
100 mov FRAME_SIZE+D_LOW[esp],eax
101 mov FRAME_SIZE+D_HIGH[esp],edx
116 mov eax,FRAME_SIZE+D_LOW[esp] ! xl
117 mov edx,FRAME_SIZE+D_HIGH[esp] ! xu
118 xor ecx,#D_SIGN_MASK ! complement sign
120 mov FRAME_SIZE+D_LOW[esp],eax
121 mov FRAME_SIZE+D_HIGH[esp],edx
130 ! Check for x denormal, to split off special case where both are denormal,
131 ! so the norm bit (or 1 higher) is known to be set for addition, so addition
136 test esi,esi ! test top bits of x fraction
137 jnz both_denorm ! denormal iff nonzero fraction with zero exp
138 test eax,eax ! test rest of fraction
139 jz return_edx_eax ! everything 0 (XXX - do signs matter?)
142 test ebp,#D_SIGN_MASK
145 ! Add denormal x to denormal or zero y
147 #if D_NORM_BIT != D_EXP_SHIFT
148 #include "error, carry into norm bit does not go into exponent"
164 test edi,edi ! this is like the check for x denormal
167 jz return_edx_eax ! y = 0
170 or ecx,#1 << D_EXP_SHIFT ! normalize y by setting exponent to 1
179 cmp ecx,#D_FRAC_BIT+2
180 jae return_edx_eax ! x dominates y
192 mov esi,edx ! this mainly for consistent naming
193 and esi,#D_EXP_MASK | D_FRAC_MASK ! discard sign so comparison is simple
194 mov edi,ecx ! free cl for shifts
195 and edi,#D_EXP_MASK | D_FRAC_MASK
207 ! edx holds sign of result from here on
208 ! and exponent of result before the normalization step
210 mov ebp,edx ! prepare difference of signs
213 and ecx,#D_EXP_MASK ! extract exp_y and check for y 0 or denormal
214 beq exp_y_0 ! otherwise x is not 0 or denormal either
215 and edi,#D_FRAC_MASK ! extract fraction
216 or edi,#D_NORM_MASK ! normalize
218 and esi,#D_FRAC_MASK ! extract fraction
219 or esi,#D_NORM_MASK ! normalize
221 sub ecx,edx ! carries from non-exp bits in edx killed later
224 shr ecx,#D_EXP_SHIFT ! difference of exponents
227 and ebp,#D_SIGN_MASK ! see if signs are same
228 bne subtract ! else roundoff reg ebp has been cleared
238 ! result edx(D_SIGN_MASK | D_EXP_MASK bits):esi:eax:ebp but needs normalization
242 test esi,#D_NORM_MASK << 1
246 cmp ebp,#1 << (REG_BIT-1) ! test roundoff register
247 jb add_done ! no rounding
252 test esi,#D_NORM_MASK << 1
253 jnz pre_add_loverflow ! rounding may cause overflow!
255 mov ecx,edx ! duplicated code from 'done'
264 test al,#1 ! tie case, round to even
265 jz add_done ! even, no rounding
270 sub ebp,ebp ! clear rounding register
271 ! probably avoiding tests for more rounding
274 jnc over_set_sticky_bit
279 add edi,1 << D_EXP_SHIFT
280 cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT
284 mov eax,ecx ! XXX - wrong reg
287 ! result edx(D_SIGN_MASK | D_EXP_MASK bits):
288 ! esi((D_NORM_MASK << 1) | D_NORM_MASK | D_FRAC_MASK bits):eax:ebp:ebx
289 ! but needs normalization
295 test esi,#D_NORM_MASK << 1
298 ! result edx(D_SIGN_MASK bit):edi(D_EXP_MASK bits):
299 ! esi(D_NORM_MASK | D_FRAC_MASK bits):eax:ebp:ebx
300 ! but needs normalization
304 test esi,#D_NORM_MASK ! already-normalized is very common
307 cmp ebp,#1 << (REG_BIT-1) ! test roundoff register
308 jb done ! no rounding
313 test esi,#D_NORM_MASK << 1
314 bne pre_loverflow ! rounding may cause overflow!
316 cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT
318 and edx,#D_SIGN_MASK ! extract sign of largest and result
319 or edx,edi ! include exponent with sign
320 and esi,#D_FRAC_MASK ! discard norm bit
321 or edx,esi ! include fraction with sign and exponent
328 test al,#1 ! tie case, round to even
329 jz done ! even, no rounding
334 shld ecx,esi,#REG_BIT-D_NORM_BIT+16 ! in 9 to 16 below?
335 jz not_in_16_below ! must be way below (17-20 for usual D_NORM_BIT)
336 mov cl,bsr_table[ecx] ! bsr(esi) - (D_NORM_BIT-16)
337 neg ecx ! (D_NORM_BIT-16) - bsr(esi)
343 mov cl,bsr_table[esi] ! bsr(esi) directly
345 add ecx,#D_NORM_BIT ! D_NORM_BIT - bsr(esi)
353 ! Find first nonzero bit in esi
354 ! Don't use bsr, it is very slow (const + 3 * bit_found)
355 ! We know that there is some nonzero bit, and the norm bit and above are clear
357 sub ecx,ecx ! prepare unsigned extension of cl
358 shld ecx,esi,#REG_BIT-D_NORM_BIT+8 ! any bits in 8 below norm bit?
360 mov cl,bsr_table[ecx] ! bsr(esi) - (D_NORM_BIT-8)
361 neg ecx ! (D_NORM_BIT-8) - bsr(esi)
362 add ecx,#8 ! D_NORM_BIT - bsr(esi)
370 bhi round ! XXX - can rounding change the exponent to > 0?
371 ! not bgt since edi may be 0x80000000
379 sub ebp,ebp ! clear rounding registers
380 sub ebx,ebx ! probably avoiding tests for more rounding
383 shr esi,#1 ! carry bit stayed in the reg
387 add edi,1 << D_EXP_SHIFT
388 cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT
391 mov eax,ecx ! XXX - wrong reg
402 sub edi,#REG_BIT << D_EXP_SHIFT
404 test esi,#~(D_NORM_MASK | D_FRAC_MASK)
405 jz over_adjust ! else too big already
406 shrd ebx,ebp,#D_BIT-D_FRAC_BIT
407 shrd ebp,eax,#D_BIT-D_FRAC_BIT
408 shrd eax,esi,#D_BIT-D_FRAC_BIT
409 shr esi,#D_BIT-D_FRAC_BIT
410 add edi,#(D_BIT-D_FRAC_BIT) << D_EXP_SHIFT
427 sub edi,#(2*REG_BIT) << D_EXP_SHIFT
432 test ebx,ebx ! XXX - this test is probably unnecessary
433 ! since the shift must be small unless we
434 ! are subtracting 2 almost-equal numbers,
435 ! and then the bits beyond 64 will mostly
437 jz return_esi_eax ! all zero
440 sub edi,#(3*REG_BIT) << D_EXP_SHIFT
450 sub ebp,ebp ! set up roundoff register
452 jae subtract_bigshift
456 neg ebp ! begin subtraction esi:eax:0 - edi:ebx:ebp
466 cmp ecx,#D_FRAC_BIT+2
467 bhis return_edx_eax ! x dominates y
472 not ebp ! begin subtraction esi:eax:0:0 - 0:edi:ebx:ebp