summaryrefslogtreecommitdiff
path: root/libc/i386fp/fcomp.x
diff options
context:
space:
mode:
Diffstat (limited to 'libc/i386fp/fcomp.x')
-rw-r--r--libc/i386fp/fcomp.x89
1 files changed, 89 insertions, 0 deletions
diff --git a/libc/i386fp/fcomp.x b/libc/i386fp/fcomp.x
new file mode 100644
index 0000000..71148ab
--- /dev/null
+++ b/libc/i386fp/fcomp.x
@@ -0,0 +1,89 @@
+! bcc 386 floating point routines (version 2) -- Fcomp, Fcompd, Fcompf
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern Fpushf
+
+! Pop 2 doubles from stack and compare them, return result in flags so
+! normal signed branches work (unlike 80x87 which returns the result in
+! the zero and carry flags).
+
+ .globl Fcomp
+ .align ALIGNMENT
+Fcomp:
+ pop ecx ! get return address
+ pop eax ! xl
+ pop edx ! xu
+ push ecx ! put back ret address - pop 2nd double later
+
+! All this popping is bad on 486's since plain mov takes 1+ cycle and pop
+! takes 4 cycles. But this code is designed for 386's where popping is
+! nominally the same speed and saves code space and so maybe instruction
+! fetch time as well as the instruction to adjust the stack (ret #n takes
+! no longer than plain ret but inhibits gotos).
+
+ mov ebx,PC_SIZE+D_LOW[esp] ! yl
+ mov ecx,PC_SIZE+D_HIGH[esp] ! yu
+ jmp compare
+
+! Pop double from stack and compare with double at [ebx]
+
+ .globl Fcompd
+ .align ALIGNMENT
+Fcompd:
+ mov eax,PC_SIZE+D_LOW[esp] ! xl
+ mov edx,PC_SIZE+D_HIGH[esp] ! xu
+ mov ecx,D_HIGH[ebx] ! yu
+ mov ebx,D_LOW[ebx] ! yl
+
+compare:
+ test edx,#D_SIGN_MASK ! is x >= 0?
+ jz cmp0 ! yes; just compare x and y
+ test ecx,#D_SIGN_MASK ! no; but is y >= 0?
+ jz cmp0 ! yes; just compare x and y
+
+ xchg edx,ecx ! x, y < 0, so ...
+ xchg eax,ebx ! ... swap x and y ...
+ xor edx,#D_SIGN_MASK ! ... and toggle signs
+ xor ecx,#D_SIGN_MASK
+
+cmp0:
+ cmp edx,ecx ! compare upper dwords
+ jnz checkneg0 ! if upper dwords differ, job is almost done
+ mov edx,eax ! upper dwords equal, so ...
+ mov ecx,ebx ! ... must make unsigned comparison of lower dwords
+ shr edx,#1 ! shift past sign
+ shr ecx,#1
+ cmp edx,ecx ! compare top 31 bits of lower dwords
+ jnz return ! if these differ, job is done
+ and eax,#1 ! compare lowest bits
+ and ebx,#1
+ cmp eax,ebx
+
+return:
+ ret #D_SIZE ! return, popping 1 double from stack
+
+checkneg0:
+ test edx,#D_EXP_MASK | D_FRAC_MASK ! check to catch unusual case ...
+ jnz recheck
+ test eax,eax
+ jnz recheck
+ test ecx,#D_EXP_MASK | D_FRAC_MASK
+ jnz recheck
+ test ebx,ebx
+ jz return ! ... both are (+-) zero, return 'z'
+
+recheck:
+ cmp edx,ecx ! the upper words were really different
+ ret #D_SIZE
+
+ .globl Fcompf
+ .align ALIGNMENT
+Fcompf:
+ call Fpushf
+ pop ebx ! yl
+ pop ecx ! yu
+ mov eax,PC_SIZE+D_LOW[esp] ! xl
+ mov edx,PC_SIZE+D_HIGH[esp] ! xu
+ jmp compare