xref: /csrg-svn/lib/libm/national/support.s (revision 34129)
1*34129Sbostic;
2*34129Sbostic; Copyright (c) 1985 Regents of the University of California.
3*34129Sbostic; All rights reserved.
4*34129Sbostic;
5*34129Sbostic; Redistribution and use in source and binary forms are permitted
6*34129Sbostic; provided that this notice is preserved and that due credit is given
7*34129Sbostic; to the University of California at Berkeley. The name of the University
8*34129Sbostic; may not be used to endorse or promote products derived from this
9*34129Sbostic; software without specific prior written permission. This software
10*34129Sbostic; is provided ``as is'' without express or implied warranty.
11*34129Sbostic;
12*34129Sbostic; All recipients should regard themselves as participants in an ongoing
13*34129Sbostic; research project and hence should feel obligated to report their
14*34129Sbostic; experiences (good or bad) with these elementary function codes, using
15*34129Sbostic; the sendbug(8) program, to the authors.
16*34129Sbostic;
17*34129Sbostic;	@(#)support.s	5.2 (Berkeley) 04/29/88
18*34129Sbostic;
19*34129Sbostic
2026460Selefunt; IEEE recommended functions
2126460Selefunt;
2226460Selefunt; double copysign(x,y)
2326460Selefunt; double x,y;
2426460Selefunt; IEEE 754 recommended function, return x*sign(y)
2526460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85.
2626460Selefunt;
2726460Selefunt	.vers	2
2826460Selefunt	.text
2926460Selefunt	.align	2
3026460Selefunt	.globl	_copysign
3126460Selefunt_copysign:
3226460Selefunt	movl	4(sp),f0
3326460Selefunt	movd	8(sp),r0
3426460Selefunt	movd	16(sp),r1
3526460Selefunt	xord	r0,r1
3626907Selefunt	andd	0x80000000,r1
3726460Selefunt	cmpqd	0,r1
3826460Selefunt	beq	end
3926460Selefunt	negl	f0,f0
4026460Selefuntend:	ret	0
4126460Selefunt
4226460Selefunt;
4326460Selefunt; double logb(x)
4426460Selefunt; double x;
4526460Selefunt; IEEE p854 recommended function, return the exponent of x (return float(N)
4626460Selefunt; such that 1 <= x*2**-N < 2, even for subnormal number.
4726460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85.
4826460Selefunt; Note: subnormal number (if implemented) will be taken care of.
4926460Selefunt;
5026460Selefunt	.vers	2
5126460Selefunt	.text
5226460Selefunt	.align	2
5326460Selefunt	.globl	_logb
5426460Selefunt_logb:
5526460Selefunt;
5626460Selefunt; extract the exponent of x
5726460Selefunt; glossaries:	r0 = high part of x
5826460Selefunt;		r1 = unbias exponent of x
5926460Selefunt;		r2 = 20 (first exponent bit position)
6026460Selefunt;
6126460Selefunt	movd	8(sp),r0
6226460Selefunt	movd	20,r2
6326460Selefunt	extd	r2,r0,r1,11	; extract the exponent of x
6426460Selefunt	cmpqd	0,r1		; if exponent bits = 0, goto L3
6526460Selefunt	beq	L3
6626460Selefunt	cmpd	0x7ff,r1
6726460Selefunt	beq	L2		; if exponent bits = 0x7ff, goto L2
6826460SelefuntL1:	subd	1023,r1		; unbias the exponent
6926460Selefunt	movdl	r1,f0		; convert the exponent to floating value
7026460Selefunt	ret	0
7126460Selefunt;
7226460Selefunt; x is INF or NaN, simply return x
7326460Selefunt;
7426460SelefuntL2:
7526460Selefunt	movl	4(sp),f0	; logb(+inf)=+inf, logb(NaN)=NaN
7626460Selefunt	ret	0
7726460Selefunt;
7826460Selefunt; x is 0 or subnormal
7926460Selefunt;
8026460SelefuntL3:
8126460Selefunt	movl	4(sp),f0
8226460Selefunt	cmpl	0f0,f0
8326460Selefunt	beq	L5		; x is 0 , goto L5 (return -inf)
8426460Selefunt;
8526460Selefunt; Now x is subnormal
8626460Selefunt;
8726460Selefunt	mull	L64,f0		; scale up f0 with 2**64
8826460Selefunt	movl	f0,tos
8926460Selefunt	movd	tos,r0
9026460Selefunt	movd	tos,r0		; now r0 = new high part of x
9126460Selefunt	extd	r2,r0,r1,11	; extract the exponent of x to r1
9226460Selefunt	subd	1087,r1		; unbias the exponent with correction
9326460Selefunt	movdl	r1,f0		; convert the exponent to floating value
9426460Selefunt	ret	0
9526460Selefunt;
9626460Selefunt; x is 0, return logb(0)= -INF
9726460Selefunt;
9826460SelefuntL5:
9926460Selefunt	movl	0f1.0e300,f0
10026460Selefunt	mull	0f-1.0e300,f0	; multiply two big numbers to get -INF
10126460Selefunt	ret	0
10226460Selefunt;
10326460Selefunt; double rint(x)
10426460Selefunt; double x;
10526460Selefunt; ... delivers integer nearest x in direction of prevailing rounding
10626460Selefunt; ... mode
10726460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85.
10826460Selefunt; Note: subnormal number (if implemented) will be taken care of.
10926460Selefunt;
11026460Selefunt	.vers	2
11126460Selefunt	.text
11226460Selefunt	.align	2
11326460Selefunt	.globl	_rint
11426460Selefunt_rint:
11526460Selefunt;
11626460Selefunt	movd	8(sp),r0
11726460Selefunt	movd	20,r2
11826460Selefunt	extd	r2,r0,r1,11	; extract the exponent of x
11926460Selefunt	cmpd	0x433,r1
12026460Selefunt	ble	itself
12126460Selefunt	movl	L52,f2		; f2 = L = 2**52
12226460Selefunt	cmpqd	0,r0
12326460Selefunt	ble	L1
12426460Selefunt	negl	f2,f2		; f2 = s = copysign(L,x)
12526460SelefuntL1:	addl	f2,f0		; f0 = x + s
12626460Selefunt	subl	f2,f0		; f0 = f0 - s
12726460Selefunt	ret	0
12826460Selefuntitself:	movl	4(sp),f0
12926460Selefunt	ret	0
13026460SelefuntL52:	.double	0x0,0x43300000	; L52=2**52
13126460Selefunt;
13226460Selefunt; int finite(x)
13326460Selefunt; double x;
13426460Selefunt; IEEE 754 recommended function, return 0 if x is NaN or INF, else 0
13526460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85.
13626460Selefunt;
13726460Selefunt	.vers	2
13826460Selefunt	.text
13926460Selefunt	.align	2
14026460Selefunt	.globl	_finite
14126460Selefunt_finite:
14226460Selefunt	movd	4(sp),r1
14326460Selefunt	andd	0x800fffff,r1
14426460Selefunt	cmpd	0x7ff00000,r1
14526460Selefunt	sned	r0		; r0=0 if exponent(x) = 0x7ff
14626460Selefunt	ret	0
14726460Selefunt;
14826460Selefunt; double scalb(x,N)
14926460Selefunt; double x; int N;
15026460Selefunt; IEEE 754 recommended function, return x*2**N by adjusting
15126460Selefunt; exponent of x.
15226460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85.
15326460Selefunt; Note: subnormal number (if implemented) will be taken care of
15426460Selefunt;
15526460Selefunt	.vers	2
15626460Selefunt	.text
15726460Selefunt	.align	2
15826460Selefunt	.globl	_scalb
15926460Selefunt_scalb:
16026460Selefunt;
16126460Selefunt; if x=0 return 0
16226460Selefunt;
16326460Selefunt	movl	4(sp),f0
16426460Selefunt	cmpl	0f0,f0
16526460Selefunt	beq	end		; scalb(0,N) is x itself
16626460Selefunt;
16726460Selefunt; extract the exponent of x
16826460Selefunt; glossaries:	r0 = high part of x,
16926460Selefunt;		r1 = unbias exponent of x,
17026460Selefunt;		r2 = 20 (first exponent bit position).
17126460Selefunt;
17226460Selefunt	movd	8(sp),r0	; r0 = high part of x
17326460Selefunt	movd	20,r2		; r2 = 20
17426460Selefunt	extd	r2,r0,r1,11	; extract the exponent of x in r1
17526460Selefunt	cmpd	0x7ff,r1
17626460Selefunt;
17726460Selefunt; if exponent of x is 0x7ff, then x is NaN or INF; simply return x
17826460Selefunt;
17926460Selefunt	beq	end
18026460Selefunt	cmpqd	0,r1
18126460Selefunt;
18226460Selefunt; if exponent of x is zero, then x is subnormal; goto L19
18326460Selefunt;
18426460Selefunt	beq	L19
18526460Selefunt	addd	12(sp),r1	; r1 = (exponent of x) + N
18626460Selefunt	bfs	inof		; if integer overflows, goto inof
18726460Selefunt	cmpqd	0,r1		; if new exponent <= 0, goto underflow
18826460Selefunt	bge	underflow
18926460Selefunt	cmpd	2047,r1		; if new exponent >= 2047 goto overflow
19026460Selefunt	ble	overflow
19126460Selefunt	insd	r2,r1,r0,11	; insert the new exponent
19226460Selefunt	movd	r0,tos
19326460Selefunt	movd	8(sp),tos
19426460Selefunt	movl	tos,f0		; return x*2**N
19526460Selefuntend:	ret	0
19626460Selefuntinof:	bcs	underflow	; negative int overflow if Carry bit is set
19726460Selefuntoverflow:
19826460Selefunt	andd	0x80000000,r0	; keep the sign of x
19926460Selefunt	ord	0x7fe00000,r0	; set x to a huge number
20026460Selefunt	movd	r0,tos
20126460Selefunt	movqd	0,tos
20226460Selefunt	movl	tos,f0
20326460Selefunt	mull	0f1.0e300,f0	; multiply two huge number to get overflow
20426460Selefunt	ret	0
20526460Selefuntunderflow:
20626460Selefunt	addd	64,r1		; add 64 to exonent to see if it is subnormal
20726460Selefunt	cmpqd	0,r1
20826460Selefunt	bge	zero		; underflow to zero
20926460Selefunt	insd	r2,r1,r0,11	; insert the new exponent
21026460Selefunt	movd	r0,tos
21126460Selefunt	movd	8(sp),tos
21226460Selefunt	movl	tos,f0
21326460Selefunt	mull	L30,f0		; readjust x by multiply it with 2**-64
21426460Selefunt	ret	0
21526460Selefuntzero:	andd	0x80000000,r0	; keep the sign of x
21626460Selefunt	ord	0x00100000,r0	; set x to a tiny number
21726460Selefunt	movd	r0,tos
21826460Selefunt	movqd	0,tos
21926460Selefunt	movl	tos,f0
22026460Selefunt	mull	0f1.0e-300,f0	; underflow to 0  by multipling two tiny nos.
22126460Selefunt	ret	0
22226460SelefuntL19:		; subnormal number
22326460Selefunt	mull	L32,f0		; scale up x by 2**64
22426460Selefunt	movl	f0,tos
22526460Selefunt	movd	tos,r0
22626460Selefunt	movd	tos,r0		; get the high part of new x
22726460Selefunt	extd	r2,r0,r1,11	; extract the exponent of x in r1
22826460Selefunt	addd	12(sp),r1	; exponent of x + N
22926460Selefunt	subd	64,r1		; adjust it by subtracting 64
23026460Selefunt	cmpqd	0,r1
23126460Selefunt	bge	underflow
23226460Selefunt	cmpd	2047,r1
23326460Selefunt	ble	overflow
23426460Selefunt	insd	r2,r1,r0,11	; insert back the incremented exponent
23526460Selefunt	movd	r0,tos
23626460Selefunt	movd	8(sp),tos
23726460Selefunt	movl	tos,f0
23826460Selefuntend:	ret	0
23926460SelefuntL30:	.double	0x0,0x3bf00000	; floating point 2**-64
24026460SelefuntL32:	.double	0x0,0x43f00000	; floating point 2**64
24131848Szliu;
24231848Szliu; double drem(x,y)
24331848Szliu; double x,y;
24431848Szliu; IEEE double remainder function, return x-n*y, where n=x/y rounded to
24531848Szliu; nearest integer (half way case goes to even). Result exact.
24631848Szliu; Coded by K.C. Ng in National 32k assembly, 11/19/85.
24731848Szliu;
24831848Szliu	.vers	2
24931848Szliu	.text
25031848Szliu	.align	2
25131848Szliu	.globl	_drem
25231848Szliu_drem:
25331848Szliu;
25431848Szliu; glossaries:
25531848Szliu;		r2 = high part of x
25631848Szliu;		r3 = exponent of x
25731848Szliu;		r4 = high part of y
25831848Szliu;		r5 = exponent of y
25931848Szliu;		r6 = sign of x
26031848Szliu;		r7 = constant 0x7ff00000
26131848Szliu;
26231848Szliu;  16(fp) : y
26331848Szliu;   8(fp) : x
26431848Szliu; -12(fp) : adjustment on y when y is subnormal
26531848Szliu; -16(fp) : fsr
26631848Szliu; -20(fp) : nx
26731848Szliu; -28(fp) : t
26831848Szliu; -36(fp) : t1
26931848Szliu; -40(fp) : nf
27031848Szliu;
27131848Szliu;
27231848Szliu	enter	[r3,r4,r5,r6,r7],40
27331848Szliu	movl	f6,tos
27431848Szliu	movl	f4,tos
27531848Szliu	movl	0f0,-12(fp)
27631848Szliu	movd	0,-20(fp)
27731848Szliu	movd	0,-40(fp)
27831848Szliu	movd	0x7ff00000,r7	; initialize r7=0x7ff00000
27931848Szliu	movd	12(fp),r2	; r2 = high(x)
28031848Szliu	movd	r2,r3
28131848Szliu	andd	r7,r3		; r3 = xexp
28231848Szliu	cmpd	r7,r3
28331848Szliu; if x is NaN or INF goto L1
28431848Szliu	beq	L1
28531848Szliu	movd	20(fp),r4
28631848Szliu	bicd	[31],r4		; r4 = high part of |y|
28731848Szliu	movd	r4,20(fp)	; y = |y|
28831848Szliu	movd	r4,r5
28931848Szliu	andd	r7,r5		; r5 = yexp
29031848Szliu	cmpd	r7,r5
29131848Szliu	beq	L2		; if y is NaN or INF goto L2
29231848Szliu	cmpd	0x04000000,r5	;
29331848Szliu	bgt	L3		; if y is tiny goto L3
29431848Szliu;
29531848Szliu; now y != 0 , x is finite
29631848Szliu;
29731848SzliuL10:
29831848Szliu	movd	r2,r6
29931848Szliu	andd	0x80000000,r6	; r6 = sign(x)
30031848Szliu	bicd	[31],r2		; x <- |x|
30131848Szliu	sfsr	r1
30231848Szliu	movd	r1,-16(fp)	; save fsr in -16(fp)
30331848Szliu	bicd	[5],r1
30431848Szliu	lfsr	r1		; disable inexact interupt
30531848Szliu	movd	16(fp),r0	; r0 = low part of y
30631848Szliu	movd	r0,r1		; r1 = r0 = low part of y
30731848Szliu	andd	0xf8000000,r1	; mask off the lsb 27 bits of y
30831848Szliu
30931848Szliu	movd	r2,12(fp)	; update x to |x|
31031848Szliu	movd	r0,-28(fp)	;
31131848Szliu	movd	r4,-24(fp)	; t  = y
31231848Szliu	movd	r4,-32(fp)	;
31331848Szliu	movd	r1,-36(fp)	; t1 = y with trialing 27 zeros
31431848Szliu	movd	0x01900000,r1	; r1 = 25 in exponent field
31531848SzliuLOOP:
31631848Szliu	movl	8(fp),f0	; f0 = x
31731848Szliu	movl	16(fp),f2	; f2 = y
31831848Szliu	cmpl	f0,f2
31931848Szliu	ble	fnad		; goto fnad (final adjustment) if x <= y
32031848Szliu	movd	r4,-32(fp)
32131848Szliu	movd	r3,r0
32231848Szliu	subd	r5,r0		; xexp - yexp
32331848Szliu	subd	r1,r0		; r0 = xexp - yexp - m25
32431848Szliu	cmpqd	0,r0		; r0 > 0 ?
32531848Szliu	bge	1f
32631848Szliu	addd	r4,r0		; scale up (high) y
32731848Szliu	movd	r0,-24(fp)	; scale up t
32831848Szliu	movl	-28(fp),f2	; t
32931848Szliu	movd	r0,-32(fp)	; scale up t1
33031848Szliu1:
33131848Szliu	movl	-36(fp),f4	; t1
33231848Szliu	movl	f0,f6
33331848Szliu	divl	f2,f6		; f6 = x/t
33431848Szliu	floorld	f6,r0		; r0 = [x/t]
33531848Szliu	movdl	r0,f6		; f6 = n
33631848Szliu	subl	f4,f2		; t = t - t1 (tail of t1)
33731848Szliu	mull	f6,f4		; f4 = n*t1	...exact
33831848Szliu	subl	f4,f0		; x = x - n*t1
33931848Szliu	mull	f6,f2		; n*(t-t1)	...exact
34031848Szliu	subl	f2,f0		; x = x - n*(t-t1)
34131848Szliu; update xexp
34231848Szliu	movl	f0,8(fp)
34331848Szliu	movd	12(fp),r3
34431848Szliu	andd	r7,r3
34531848Szliu	jump	LOOP
34631848Szliufnad:
34731848Szliu	cmpqd	0,-20(fp)	; 0 = nx?
34831848Szliu	beq	final
34931848Szliu	mull	-12(fp),8(fp)	; scale up x the same amount as y
35031848Szliu	movd	0,-20(fp)
35131848Szliu	movd	12(fp),r2
35231848Szliu	movd	r2,r3
35331848Szliu	andd	r7,r3		; update exponent of x
35431848Szliu	jump	LOOP
35531848Szliu
35631848Szliufinal:
35731848Szliu	movl	16(fp),f2	; f2 = y (f0=x, r0=n)
35831848Szliu	subd	0x100000,r4	; high y /2
35931848Szliu	movd	r4,-24(fp)
36031848Szliu	movl	-28(fp),f4	; f4 = y/2
36131848Szliu	cmpl	f0,f4		; x > y/2 ?
36231848Szliu	bgt	1f
36331848Szliu	bne	2f
36431848Szliu	andd	1,r0		; n is odd or even
36531848Szliu	cmpqd	0,r0
36631848Szliu	beq	2f
36731848Szliu1:
36831848Szliu	subl	f2,f0		; x = x - y
36931848Szliu2:
37031848Szliu	cmpqd	0,-40(fp)
37131848Szliu	beq	3f
37231848Szliu	divl	-12(fp),f0	; scale down the answer
37331848Szliu3:
37431848Szliu	movl	f0,tos
37531848Szliu	xord	r6,tos
37631848Szliu	movl	tos,f0
37731848Szliu	movd	-16(fp),r0
37831848Szliu	lfsr	r0		; restore the fsr
37931848Szliu
38031848Szliuend:	movl	tos,f4
38131848Szliu	movl	tos,f6
38231848Szliu	exit	[r3,r4,r5,r6,r7]
38331848Szliu	ret	0
38431848Szliu;
38531848Szliu; y is NaN or INF
38631848Szliu;
38731848SzliuL2:
38831848Szliu	movd	16(fp),r0	; r0 = low part of y
38931848Szliu	andd	0xfffff,r4	; r4 = high part of y & 0x000fffff
39031848Szliu	ord	r4,r0
39131848Szliu	cmpqd	0,r0
39231848Szliu	beq	L4
39331848Szliu	movl	16(fp),f0	; y is NaN, return y
39431848Szliu	jump	end
39531848SzliuL4:	movl	8(fp),f0	; y is inf, return x
39631848Szliu	jump	end
39731848Szliu;
39831848Szliu; exponent of y is less than 64, y may be zero or subnormal
39931848Szliu;
40031848SzliuL3:
40131848Szliu	movl	16(fp),f0
40231848Szliu	cmpl	0f0,f0
40331848Szliu	bne	L5
40431848Szliu	divl	f0,f0		; y is 0, return NaN by doing 0/0
40531848Szliu	jump	end
40631848Szliu;
40731848Szliu; subnormal y or tiny y
40831848Szliu;
40931848SzliuL5:
41031848Szliu	movd	0x04000000,-20(fp)	; nx = 64 in exponent field
41131848Szliu	movl	L64,f2
41231848Szliu	movl	f2,-12(fp)
41331848Szliu	mull	f2,f0
41431848Szliu	cmpl	f0,LTINY
41531848Szliu	bgt	L6
41631848Szliu	mull	f2,f0
41731848Szliu	addd	0x04000000,-20(fp)	; nx = nx + 64 in exponent field
41831848Szliu	mull	f2,-12(fp)
41931848SzliuL6:
42031848Szliu	movd	-20(fp),-40(fp)
42131848Szliu	movl	f0,16(fp)
42231848Szliu	movd	20(fp),r4
42331848Szliu	movd	r4,r5
42431848Szliu	andd	r7,r5		; exponent of new y
42531848Szliu	jump	L10
42631848Szliu;
42731848Szliu; x is NaN or INF, return x-x
42831848Szliu;
42931848SzliuL1:
43031848Szliu	movl	8(fp),f0
43131848Szliu	subl	f0,f0		; if x is INF, then INF-INF is NaN
43231848Szliu	ret	0
43331848SzliuL64:	.double 0x0,0x43f00000	; L64 = 2**64
43431848SzliuLTINY:	.double 0x0,0x04000000	; LTINY = 2**-959
435