summaryrefslogtreecommitdiff
path: root/libc/i386fp/fcomp.x
blob: 71148abd68601b04f42baf81d97b1972a7c93383 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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