summaryrefslogtreecommitdiff
path: root/libc/i386fp/fpullf.x
diff options
context:
space:
mode:
Diffstat (limited to 'libc/i386fp/fpullf.x')
-rw-r--r--libc/i386fp/fpullf.x101
1 files changed, 101 insertions, 0 deletions
diff --git a/libc/i386fp/fpullf.x b/libc/i386fp/fpullf.x
new file mode 100644
index 0000000..417ef92
--- /dev/null
+++ b/libc/i386fp/fpullf.x
@@ -0,0 +1,101 @@
+! bcc 386 floating point routines (version 2) -- Fpullf
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern fpoverflow
+ .extern fpunderflow
+
+! pop double from stack, convert to float and store at address [ebx]
+
+ .globl Fpullf
+ .align ALIGNMENT
+Fpullf:
+
+! Step 1: load and shift left
+
+ mov eax,PC_SIZE+D_LOW[esp] ! lower dword
+ mov edx,PC_SIZE+D_HIGH[esp] ! upper dword
+ mov ecx,edx ! copy upper dword into ecx ...
+ and ecx,#D_SIGN_MASK ! ... and extract sign
+ and edx,#D_EXP_MASK | D_FRAC_MASK ! extract exponent and fraction
+ sub edx,#(D_EXP_BIAS-F_EXP_BIAS) << D_EXP_SHIFT ! adjust exponent bias
+ jz underflow
+ cmp edx,#F_EXP_INFINITE << D_EXP_SHIFT ! check if exponent lies in reduced range
+ jae outofbounds
+ shld edx,eax,#D_EXP_BIT-F_EXP_BIT ! shift exponent and fraction
+
+! Step 2: round
+
+ test eax,#1 << (REG_BIT-1-(D_EXP_BIT-F_EXP_BIT)) ! test upper rounding bit
+ jz step3 ! below middle, don't round up
+ test eax,#(1 << (REG_BIT-1-(D_EXP_BIT-F_EXP_BIT)))-1 ! test other rounding bits
+ jnz roundup ! above middle, round up
+ test dl,#1 ! in middle, check parity bit
+ jz step3 ! already even, otherwise round up to make even
+
+roundup:
+ inc edx ! carry 1
+ test edx,#F_FRAC_MASK ! is fraction now 0? (carry into F_EXPMASK)
+ jnz step3 ! no -- carry complete
+ cmp edx,#(F_EXP_INFINITE << F_EXP_SHIFT) & ~F_NORM_MASK ! yes (very unlikely): check for overflow
+ ! XXX - I think these tests say 0x7e7fffff overflows
+ jae overflow
+
+! Step 3: put it all together
+
+step3:
+ or edx,ecx ! include sign
+ mov F_HIGH[ebx],edx ! store the result in [ebx]
+ ret #D_SIZE ! return and release double from stack
+
+ .align ALIGNMENT
+outofbounds:
+ jns overflow ! have just compared exponent with the max
+underflow:
+! call fpunderflow ! XXX
+ push ecx ! save sign
+ mov ecx,edx
+ and ecx,#~D_FRAC_MASK ! assume fraction is below exp
+ cmp ecx,#-((D_EXP_BIAS-F_EXP_BIAS) << D_EXP_SHIFT) ! was exp = 0?
+ jz exp_x_0
+ shr ecx,#D_EXP_SHIFT
+ neg ecx
+ and edx,#D_FRAC_MASK
+ or edx,#D_NORM_MASK
+ shld edx,eax,#D_EXP_BIT-F_EXP_BIT-1
+ shl eax,#D_EXP_BIT-F_EXP_BIT-1
+ push ebx ! save to use for rounding
+ sub ebx,ebx
+ shrd ebx,eax,cl
+ shrd eax,edx,cl
+ shr edx,cl
+ cmp eax,#1 << (REG_BIT-1)
+ jb over_denorm_roundup
+ ja denorm_roundup
+ test dl,#1
+ jz over_denorm_roundup
+denorm_roundup:
+#if F_NORM_BIT != F_EXP_SHIFT
+#include "carry into norm bit doesn't go into low exp bit"
+#endif
+ inc edx
+over_denorm_roundup:
+ pop ebx
+ pop ecx
+ or edx,ecx
+ mov F_HIGH[ebx],edx
+ ret #D_SIZE
+
+ .align ALIGNMENT
+exp_x_0: ! XXX check for denormals - they underflow
+ pop ecx
+ mov dword F_HIGH[ebx],#0
+ ret #D_SIZE
+
+ .align ALIGNMENT
+overflow:
+ mov edx,ebx ! put sign in usual reg
+ call fpoverflow
+ mov F_HIGH[ebx],dword #F_HUGE_HIGH ! XXX - should use infinity
+ ret #D_SIZE ! ... if fpoverflow does