summaryrefslogtreecommitdiff
path: root/libc/i386fp/frexp.x
blob: 318fc3423a1179f920633f9e4bc6a505ccb30d5b (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
! bcc 386 floating point routines (version 2) -- _frexp
! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans

#include "fplib.h"

	.extern	fpdenormal

! void frexp(double value, int *exponent);
! splits a double into exponent and fraction (where 0.5 <= fraction < 1.0)

	.globl	_frexp
	.align	ALIGNMENT
_frexp:
push ebx
#undef PC_SIZE
#define PC_SIZE 8
	mov	eax,PC_SIZE+D_LOW[esp]	! lower dword of x
	mov	ebx,PC_SIZE+D_HIGH[esp]	! upper dword of x
	mov	edx,PC_SIZE+D_SIZE[esp]	! exponent pointer
	mov	ecx,ebx		! extract exponent here
	and	ecx,#D_EXP_MASK
	jz	exp_x_0

	shr	ecx,#D_EXP_SHIFT	! exponent + bias
got_x:
	sub	ecx,#D_EXP_BIAS-1	! D_EXP_BIAS is for 1.x form, we want 0.1x form
	mov	[edx],ecx	! return exponent
	and	ebx,#D_SIGN_MASK | D_FRAC_MASK	! extract sign and fraction
	or	ebx,#(D_EXP_BIAS-1) << D_EXP_SHIFT	! set new exponent for 0.1x
mov edx,ebx
pop ebx
	ret

	.align	ALIGNMENT
exp_x_0:
	test	ebx,#D_FRAC_MASK
	jnz	xu_denorm
	test	eax,eax
	jnz	xl_denorm
	mov	[edx],ecx	! return zero exponent
	mov	ebx,ecx		! guard against -0 (may not be necessary)
mov edx,ebx
pop ebx
	ret

	.align	ALIGNMENT
xl_denorm:
	call	fpdenormal
	bsr	ecx,eax		! zzzz
	neg	ecx
	add	ecx,#REG_BIT-1
	shl	eax,cl
	shld	ebx,eax,#D_NORM_BIT+1
	shl	eax,#D_NORM_BIT+1
	sub	ecx,#D_NORM_BIT+1
	jmp	got_x

	.align	ALIGNMENT
xu_denorm:
	call	fpdenormal
	bsr	ecx,ebx
	neg	ecx
	add	ecx,#D_NORM_BIT
	shld	ebx,eax,cl
	shl	eax,cl
	jmp	got_x