date and time created 88/08/31 23:01:12 by bostic
[unix-history] / usr / src / lib / libm / national / support.s
CommitLineData
bc0f2b0e
KB
1; Copyright (c) 1985 Regents of the University of California.
2; All rights reserved.
3;
4; Redistribution and use in source and binary forms are permitted
a399f6c8
KB
5; provided that the above copyright notice and this paragraph are
6; duplicated in all such forms and that any documentation,
7; advertising materials, and other materials related to such
8; distribution and use acknowledge that the software was developed
9; by the University of California, Berkeley. The name of the
10; University may not be used to endorse or promote products derived
11; from this software without specific prior written permission.
12; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13; IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14; WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
bc0f2b0e
KB
15;
16; All recipients should regard themselves as participants in an ongoing
17; research project and hence should feel obligated to report their
18; experiences (good or bad) with these elementary function codes, using
19; the sendbug(8) program, to the authors.
20;
a399f6c8 21; @(#)support.s 5.3 (Berkeley) %G%
bc0f2b0e
KB
22;
23
ab5cf571 24; IEEE recommended functions
ab5cf571
GK
25;
26; double copysign(x,y)
27; double x,y;
28; IEEE 754 recommended function, return x*sign(y)
29; Coded by K.C. Ng in National 32k assembler, 11/9/85.
30;
31 .vers 2
32 .text
33 .align 2
34 .globl _copysign
35_copysign:
36 movl 4(sp),f0
37 movd 8(sp),r0
38 movd 16(sp),r1
39 xord r0,r1
599b6e68 40 andd 0x80000000,r1
ab5cf571
GK
41 cmpqd 0,r1
42 beq end
43 negl f0,f0
44end: ret 0
45
46;
47; double logb(x)
48; double x;
49; IEEE p854 recommended function, return the exponent of x (return float(N)
50; such that 1 <= x*2**-N < 2, even for subnormal number.
51; Coded by K.C. Ng in National 32k assembler, 11/9/85.
52; Note: subnormal number (if implemented) will be taken care of.
53;
54 .vers 2
55 .text
56 .align 2
57 .globl _logb
58_logb:
59;
60; extract the exponent of x
61; glossaries: r0 = high part of x
62; r1 = unbias exponent of x
63; r2 = 20 (first exponent bit position)
64;
65 movd 8(sp),r0
66 movd 20,r2
67 extd r2,r0,r1,11 ; extract the exponent of x
68 cmpqd 0,r1 ; if exponent bits = 0, goto L3
69 beq L3
70 cmpd 0x7ff,r1
71 beq L2 ; if exponent bits = 0x7ff, goto L2
72L1: subd 1023,r1 ; unbias the exponent
73 movdl r1,f0 ; convert the exponent to floating value
74 ret 0
75;
76; x is INF or NaN, simply return x
77;
78L2:
79 movl 4(sp),f0 ; logb(+inf)=+inf, logb(NaN)=NaN
80 ret 0
81;
82; x is 0 or subnormal
83;
84L3:
85 movl 4(sp),f0
86 cmpl 0f0,f0
87 beq L5 ; x is 0 , goto L5 (return -inf)
88;
89; Now x is subnormal
90;
91 mull L64,f0 ; scale up f0 with 2**64
92 movl f0,tos
93 movd tos,r0
94 movd tos,r0 ; now r0 = new high part of x
95 extd r2,r0,r1,11 ; extract the exponent of x to r1
96 subd 1087,r1 ; unbias the exponent with correction
97 movdl r1,f0 ; convert the exponent to floating value
98 ret 0
99;
100; x is 0, return logb(0)= -INF
101;
102L5:
103 movl 0f1.0e300,f0
104 mull 0f-1.0e300,f0 ; multiply two big numbers to get -INF
105 ret 0
ab5cf571
GK
106;
107; double rint(x)
108; double x;
109; ... delivers integer nearest x in direction of prevailing rounding
110; ... mode
111; Coded by K.C. Ng in National 32k assembler, 11/9/85.
112; Note: subnormal number (if implemented) will be taken care of.
113;
114 .vers 2
115 .text
116 .align 2
117 .globl _rint
118_rint:
119;
120 movd 8(sp),r0
121 movd 20,r2
122 extd r2,r0,r1,11 ; extract the exponent of x
123 cmpd 0x433,r1
124 ble itself
125 movl L52,f2 ; f2 = L = 2**52
126 cmpqd 0,r0
127 ble L1
128 negl f2,f2 ; f2 = s = copysign(L,x)
129L1: addl f2,f0 ; f0 = x + s
130 subl f2,f0 ; f0 = f0 - s
131 ret 0
132itself: movl 4(sp),f0
133 ret 0
134L52: .double 0x0,0x43300000 ; L52=2**52
135;
136; int finite(x)
137; double x;
138; IEEE 754 recommended function, return 0 if x is NaN or INF, else 0
139; Coded by K.C. Ng in National 32k assembler, 11/9/85.
140;
141 .vers 2
142 .text
143 .align 2
144 .globl _finite
145_finite:
146 movd 4(sp),r1
147 andd 0x800fffff,r1
148 cmpd 0x7ff00000,r1
149 sned r0 ; r0=0 if exponent(x) = 0x7ff
150 ret 0
151;
152; double scalb(x,N)
153; double x; int N;
154; IEEE 754 recommended function, return x*2**N by adjusting
155; exponent of x.
156; Coded by K.C. Ng in National 32k assembler, 11/9/85.
157; Note: subnormal number (if implemented) will be taken care of
158;
159 .vers 2
160 .text
161 .align 2
162 .globl _scalb
163_scalb:
164;
165; if x=0 return 0
166;
167 movl 4(sp),f0
168 cmpl 0f0,f0
169 beq end ; scalb(0,N) is x itself
170;
171; extract the exponent of x
172; glossaries: r0 = high part of x,
173; r1 = unbias exponent of x,
174; r2 = 20 (first exponent bit position).
175;
176 movd 8(sp),r0 ; r0 = high part of x
177 movd 20,r2 ; r2 = 20
178 extd r2,r0,r1,11 ; extract the exponent of x in r1
179 cmpd 0x7ff,r1
180;
181; if exponent of x is 0x7ff, then x is NaN or INF; simply return x
182;
183 beq end
184 cmpqd 0,r1
185;
186; if exponent of x is zero, then x is subnormal; goto L19
187;
188 beq L19
189 addd 12(sp),r1 ; r1 = (exponent of x) + N
190 bfs inof ; if integer overflows, goto inof
191 cmpqd 0,r1 ; if new exponent <= 0, goto underflow
192 bge underflow
193 cmpd 2047,r1 ; if new exponent >= 2047 goto overflow
194 ble overflow
195 insd r2,r1,r0,11 ; insert the new exponent
196 movd r0,tos
197 movd 8(sp),tos
198 movl tos,f0 ; return x*2**N
199end: ret 0
200inof: bcs underflow ; negative int overflow if Carry bit is set
201overflow:
202 andd 0x80000000,r0 ; keep the sign of x
203 ord 0x7fe00000,r0 ; set x to a huge number
204 movd r0,tos
205 movqd 0,tos
206 movl tos,f0
207 mull 0f1.0e300,f0 ; multiply two huge number to get overflow
208 ret 0
209underflow:
210 addd 64,r1 ; add 64 to exonent to see if it is subnormal
211 cmpqd 0,r1
212 bge zero ; underflow to zero
213 insd r2,r1,r0,11 ; insert the new exponent
214 movd r0,tos
215 movd 8(sp),tos
216 movl tos,f0
217 mull L30,f0 ; readjust x by multiply it with 2**-64
218 ret 0
219zero: andd 0x80000000,r0 ; keep the sign of x
220 ord 0x00100000,r0 ; set x to a tiny number
221 movd r0,tos
222 movqd 0,tos
223 movl tos,f0
224 mull 0f1.0e-300,f0 ; underflow to 0 by multipling two tiny nos.
225 ret 0
226L19: ; subnormal number
227 mull L32,f0 ; scale up x by 2**64
228 movl f0,tos
229 movd tos,r0
230 movd tos,r0 ; get the high part of new x
231 extd r2,r0,r1,11 ; extract the exponent of x in r1
232 addd 12(sp),r1 ; exponent of x + N
233 subd 64,r1 ; adjust it by subtracting 64
234 cmpqd 0,r1
235 bge underflow
236 cmpd 2047,r1
237 ble overflow
238 insd r2,r1,r0,11 ; insert back the incremented exponent
239 movd r0,tos
240 movd 8(sp),tos
241 movl tos,f0
242end: ret 0
243L30: .double 0x0,0x3bf00000 ; floating point 2**-64
244L32: .double 0x0,0x43f00000 ; floating point 2**64
dc4bce59
ZAL
245;
246; double drem(x,y)
247; double x,y;
248; IEEE double remainder function, return x-n*y, where n=x/y rounded to
249; nearest integer (half way case goes to even). Result exact.
250; Coded by K.C. Ng in National 32k assembly, 11/19/85.
251;
252 .vers 2
253 .text
254 .align 2
255 .globl _drem
256_drem:
257;
258; glossaries:
259; r2 = high part of x
260; r3 = exponent of x
261; r4 = high part of y
262; r5 = exponent of y
263; r6 = sign of x
264; r7 = constant 0x7ff00000
265;
266; 16(fp) : y
267; 8(fp) : x
268; -12(fp) : adjustment on y when y is subnormal
269; -16(fp) : fsr
270; -20(fp) : nx
271; -28(fp) : t
272; -36(fp) : t1
273; -40(fp) : nf
274;
275;
276 enter [r3,r4,r5,r6,r7],40
277 movl f6,tos
278 movl f4,tos
279 movl 0f0,-12(fp)
280 movd 0,-20(fp)
281 movd 0,-40(fp)
282 movd 0x7ff00000,r7 ; initialize r7=0x7ff00000
283 movd 12(fp),r2 ; r2 = high(x)
284 movd r2,r3
285 andd r7,r3 ; r3 = xexp
286 cmpd r7,r3
287; if x is NaN or INF goto L1
288 beq L1
289 movd 20(fp),r4
290 bicd [31],r4 ; r4 = high part of |y|
291 movd r4,20(fp) ; y = |y|
292 movd r4,r5
293 andd r7,r5 ; r5 = yexp
294 cmpd r7,r5
295 beq L2 ; if y is NaN or INF goto L2
296 cmpd 0x04000000,r5 ;
297 bgt L3 ; if y is tiny goto L3
298;
299; now y != 0 , x is finite
300;
301L10:
302 movd r2,r6
303 andd 0x80000000,r6 ; r6 = sign(x)
304 bicd [31],r2 ; x <- |x|
305 sfsr r1
306 movd r1,-16(fp) ; save fsr in -16(fp)
307 bicd [5],r1
308 lfsr r1 ; disable inexact interupt
309 movd 16(fp),r0 ; r0 = low part of y
310 movd r0,r1 ; r1 = r0 = low part of y
311 andd 0xf8000000,r1 ; mask off the lsb 27 bits of y
312
313 movd r2,12(fp) ; update x to |x|
314 movd r0,-28(fp) ;
315 movd r4,-24(fp) ; t = y
316 movd r4,-32(fp) ;
317 movd r1,-36(fp) ; t1 = y with trialing 27 zeros
318 movd 0x01900000,r1 ; r1 = 25 in exponent field
319LOOP:
320 movl 8(fp),f0 ; f0 = x
321 movl 16(fp),f2 ; f2 = y
322 cmpl f0,f2
323 ble fnad ; goto fnad (final adjustment) if x <= y
324 movd r4,-32(fp)
325 movd r3,r0
326 subd r5,r0 ; xexp - yexp
327 subd r1,r0 ; r0 = xexp - yexp - m25
328 cmpqd 0,r0 ; r0 > 0 ?
329 bge 1f
330 addd r4,r0 ; scale up (high) y
331 movd r0,-24(fp) ; scale up t
332 movl -28(fp),f2 ; t
333 movd r0,-32(fp) ; scale up t1
3341:
335 movl -36(fp),f4 ; t1
336 movl f0,f6
337 divl f2,f6 ; f6 = x/t
338 floorld f6,r0 ; r0 = [x/t]
339 movdl r0,f6 ; f6 = n
340 subl f4,f2 ; t = t - t1 (tail of t1)
341 mull f6,f4 ; f4 = n*t1 ...exact
342 subl f4,f0 ; x = x - n*t1
343 mull f6,f2 ; n*(t-t1) ...exact
344 subl f2,f0 ; x = x - n*(t-t1)
345; update xexp
346 movl f0,8(fp)
347 movd 12(fp),r3
348 andd r7,r3
349 jump LOOP
350fnad:
351 cmpqd 0,-20(fp) ; 0 = nx?
352 beq final
353 mull -12(fp),8(fp) ; scale up x the same amount as y
354 movd 0,-20(fp)
355 movd 12(fp),r2
356 movd r2,r3
357 andd r7,r3 ; update exponent of x
358 jump LOOP
359
360final:
361 movl 16(fp),f2 ; f2 = y (f0=x, r0=n)
362 subd 0x100000,r4 ; high y /2
363 movd r4,-24(fp)
364 movl -28(fp),f4 ; f4 = y/2
365 cmpl f0,f4 ; x > y/2 ?
366 bgt 1f
367 bne 2f
368 andd 1,r0 ; n is odd or even
369 cmpqd 0,r0
370 beq 2f
3711:
372 subl f2,f0 ; x = x - y
3732:
374 cmpqd 0,-40(fp)
375 beq 3f
376 divl -12(fp),f0 ; scale down the answer
3773:
378 movl f0,tos
379 xord r6,tos
380 movl tos,f0
381 movd -16(fp),r0
382 lfsr r0 ; restore the fsr
383
384end: movl tos,f4
385 movl tos,f6
386 exit [r3,r4,r5,r6,r7]
387 ret 0
388;
389; y is NaN or INF
390;
391L2:
392 movd 16(fp),r0 ; r0 = low part of y
393 andd 0xfffff,r4 ; r4 = high part of y & 0x000fffff
394 ord r4,r0
395 cmpqd 0,r0
396 beq L4
397 movl 16(fp),f0 ; y is NaN, return y
398 jump end
399L4: movl 8(fp),f0 ; y is inf, return x
400 jump end
401;
402; exponent of y is less than 64, y may be zero or subnormal
403;
404L3:
405 movl 16(fp),f0
406 cmpl 0f0,f0
407 bne L5
408 divl f0,f0 ; y is 0, return NaN by doing 0/0
409 jump end
410;
411; subnormal y or tiny y
412;
413L5:
414 movd 0x04000000,-20(fp) ; nx = 64 in exponent field
415 movl L64,f2
416 movl f2,-12(fp)
417 mull f2,f0
418 cmpl f0,LTINY
419 bgt L6
420 mull f2,f0
421 addd 0x04000000,-20(fp) ; nx = nx + 64 in exponent field
422 mull f2,-12(fp)
423L6:
424 movd -20(fp),-40(fp)
425 movl f0,16(fp)
426 movd 20(fp),r4
427 movd r4,r5
428 andd r7,r5 ; exponent of new y
429 jump L10
430;
431; x is NaN or INF, return x-x
432;
433L1:
434 movl 8(fp),f0
435 subl f0,f0 ; if x is INF, then INF-INF is NaN
436 ret 0
437L64: .double 0x0,0x43f00000 ; L64 = 2**64
438LTINY: .double 0x0,0x04000000 ; LTINY = 2**-959