xref: /netbsd-src/lib/libc/softfloat/softfloat-specialize (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1/*	$NetBSD: softfloat-specialize,v 1.8 2013/01/10 08:16:10 matt Exp $	*/
2
3/* This is a derivative work. */
4
5/*
6===============================================================================
7
8This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
9Arithmetic Package, Release 2a.
10
11Written by John R. Hauser.  This work was made possible in part by the
12International Computer Science Institute, located at Suite 600, 1947 Center
13Street, Berkeley, California 94704.  Funding was partially provided by the
14National Science Foundation under grant MIP-9311980.  The original version
15of this code was written as part of a project to build a fixed-point vector
16processor in collaboration with the University of California at Berkeley,
17overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
18is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
19arithmetic/SoftFloat.html'.
20
21THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
22has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
23TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
24PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
25AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
26
27Derivative works are acceptable, even for commercial purposes, so long as
28(1) they include prominent notice that the work is derivative, and (2) they
29include prominent notice akin to these four paragraphs for those parts of
30this code that are retained.
31
32===============================================================================
33*/
34
35#include <signal.h>
36#include <string.h>
37#include <unistd.h>
38
39/*
40-------------------------------------------------------------------------------
41Underflow tininess-detection mode, statically initialized to default value.
42(The declaration in `softfloat.h' must match the `int8' type here.)
43-------------------------------------------------------------------------------
44*/
45#ifdef SOFTFLOAT_FOR_GCC
46static
47#endif
48int8 float_detect_tininess = float_tininess_after_rounding;
49
50/*
51-------------------------------------------------------------------------------
52Raises the exceptions specified by `flags'.  Floating-point traps can be
53defined here if desired.  It is currently not possible for such a trap to
54substitute a result value.  If traps are not implemented, this routine
55should be simply `float_exception_flags |= flags;'.
56-------------------------------------------------------------------------------
57*/
58#ifdef SOFTFLOAT_FOR_GCC
59#ifndef set_float_exception_mask
60#define float_exception_mask	_softfloat_float_exception_mask
61#endif
62#endif
63#ifndef set_float_exception_mask
64fp_except float_exception_mask = 0;
65#endif
66void
67float_raise( fp_except flags )
68{
69    siginfo_t info;
70    fp_except mask = float_exception_mask;
71
72#ifdef set_float_exception_mask
73    flags |= set_float_exception_flags(flags, 0);
74#else
75    float_exception_flags |= flags;
76    flags = float_exception_flags;
77#endif
78
79    flags &= mask;
80    if ( flags ) {
81	memset(&info, 0, sizeof info);
82	info.si_signo = SIGFPE;
83	info.si_pid = getpid();
84	info.si_uid = geteuid();
85	if (flags & float_flag_underflow)
86	    info.si_code = FPE_FLTUND;
87	else if (flags & float_flag_overflow)
88	    info.si_code = FPE_FLTOVF;
89	else if (flags & float_flag_divbyzero)
90	    info.si_code = FPE_FLTDIV;
91	else if (flags & float_flag_invalid)
92	    info.si_code = FPE_FLTINV;
93	else if (flags & float_flag_inexact)
94	    info.si_code = FPE_FLTRES;
95	sigqueueinfo(getpid(), &info);
96    }
97}
98#undef float_exception_mask
99
100/*
101-------------------------------------------------------------------------------
102Internal canonical NaN format.
103-------------------------------------------------------------------------------
104*/
105typedef struct {
106    flag sign;
107    bits64 high, low;
108} commonNaNT;
109
110/*
111-------------------------------------------------------------------------------
112The pattern for a default generated single-precision NaN.
113-------------------------------------------------------------------------------
114*/
115#define float32_default_nan 0xFFFFFFFF
116
117/*
118-------------------------------------------------------------------------------
119Returns 1 if the single-precision floating-point value `a' is a NaN;
120otherwise returns 0.
121-------------------------------------------------------------------------------
122*/
123#ifdef SOFTFLOAT_FOR_GCC
124static
125#endif
126flag float32_is_nan( float32 a )
127{
128
129    return ( (bits32)0xFF000000 < (bits32) ( a<<1 ) );
130
131}
132
133/*
134-------------------------------------------------------------------------------
135Returns 1 if the single-precision floating-point value `a' is a signaling
136NaN; otherwise returns 0.
137-------------------------------------------------------------------------------
138*/
139#if defined(SOFTFLOAT_FOR_GCC) && !defined(SOFTFLOATSPARC64_FOR_GCC) && \
140    !defined(SOFTFLOAT_M68K_FOR_GCC)
141static
142#endif
143flag float32_is_signaling_nan( float32 a )
144{
145
146    return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
147
148}
149
150/*
151-------------------------------------------------------------------------------
152Returns the result of converting the single-precision floating-point NaN
153`a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
154exception is raised.
155-------------------------------------------------------------------------------
156*/
157static commonNaNT float32ToCommonNaN( float32 a )
158{
159    commonNaNT z;
160
161    if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
162    z.sign = a>>31;
163    z.low = 0;
164    z.high = ( (bits64) a )<<41;
165    return z;
166
167}
168
169/*
170-------------------------------------------------------------------------------
171Returns the result of converting the canonical NaN `a' to the single-
172precision floating-point format.
173-------------------------------------------------------------------------------
174*/
175static float32 commonNaNToFloat32( commonNaNT a )
176{
177
178    return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | (bits32)( a.high>>41 );
179
180}
181
182/*
183-------------------------------------------------------------------------------
184Takes two single-precision floating-point values `a' and `b', one of which
185is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
186signaling NaN, the invalid exception is raised.
187-------------------------------------------------------------------------------
188*/
189static float32 propagateFloat32NaN( float32 a, float32 b )
190{
191    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
192
193    aIsNaN = float32_is_nan( a );
194    aIsSignalingNaN = float32_is_signaling_nan( a );
195    bIsNaN = float32_is_nan( b );
196    bIsSignalingNaN = float32_is_signaling_nan( b );
197    a |= 0x00400000;
198    b |= 0x00400000;
199    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
200    if ( aIsNaN ) {
201        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
202    }
203    else {
204        return b;
205    }
206
207}
208
209/*
210-------------------------------------------------------------------------------
211The pattern for a default generated double-precision NaN.
212-------------------------------------------------------------------------------
213*/
214#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
215
216/*
217-------------------------------------------------------------------------------
218Returns 1 if the double-precision floating-point value `a' is a NaN;
219otherwise returns 0.
220-------------------------------------------------------------------------------
221*/
222#ifdef SOFTFLOAT_FOR_GCC
223static
224#endif
225flag float64_is_nan( float64 a )
226{
227
228    return ( (bits64)LIT64( 0xFFE0000000000000 ) <
229	     (bits64) ( FLOAT64_DEMANGLE(a)<<1 ) );
230
231}
232
233/*
234-------------------------------------------------------------------------------
235Returns 1 if the double-precision floating-point value `a' is a signaling
236NaN; otherwise returns 0.
237-------------------------------------------------------------------------------
238*/
239#if defined(SOFTFLOAT_FOR_GCC) && !defined(SOFTFLOATSPARC64_FOR_GCC) && \
240    !defined(SOFTFLOATM68K_FOR_GCC)
241static
242#endif
243flag float64_is_signaling_nan( float64 a )
244{
245
246    return
247           ( ( ( FLOAT64_DEMANGLE(a)>>51 ) & 0xFFF ) == 0xFFE )
248        && ( FLOAT64_DEMANGLE(a) & LIT64( 0x0007FFFFFFFFFFFF ) );
249
250}
251
252/*
253-------------------------------------------------------------------------------
254Returns the result of converting the double-precision floating-point NaN
255`a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
256exception is raised.
257-------------------------------------------------------------------------------
258*/
259static commonNaNT float64ToCommonNaN( float64 a )
260{
261    commonNaNT z;
262
263    if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
264    z.sign = (flag)(FLOAT64_DEMANGLE(a)>>63);
265    z.low = 0;
266    z.high = FLOAT64_DEMANGLE(a)<<12;
267    return z;
268
269}
270
271/*
272-------------------------------------------------------------------------------
273Returns the result of converting the canonical NaN `a' to the double-
274precision floating-point format.
275-------------------------------------------------------------------------------
276*/
277static float64 commonNaNToFloat64( commonNaNT a )
278{
279
280    return FLOAT64_MANGLE(
281	( ( (bits64) a.sign )<<63 )
282        | LIT64( 0x7FF8000000000000 )
283        | ( a.high>>12 ) );
284
285}
286
287/*
288-------------------------------------------------------------------------------
289Takes two double-precision floating-point values `a' and `b', one of which
290is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
291signaling NaN, the invalid exception is raised.
292-------------------------------------------------------------------------------
293*/
294static float64 propagateFloat64NaN( float64 a, float64 b )
295{
296    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
297
298    aIsNaN = float64_is_nan( a );
299    aIsSignalingNaN = float64_is_signaling_nan( a );
300    bIsNaN = float64_is_nan( b );
301    bIsSignalingNaN = float64_is_signaling_nan( b );
302    a |= FLOAT64_MANGLE(LIT64( 0x0008000000000000 ));
303    b |= FLOAT64_MANGLE(LIT64( 0x0008000000000000 ));
304    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
305    if ( aIsNaN ) {
306        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
307    }
308    else {
309        return b;
310    }
311
312}
313
314#ifdef FLOATX80
315
316/*
317-------------------------------------------------------------------------------
318The pattern for a default generated extended double-precision NaN.  The
319`high' and `low' values hold the most- and least-significant bits,
320respectively.
321-------------------------------------------------------------------------------
322*/
323#define floatx80_default_nan_high 0xFFFF
324#define floatx80_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
325
326/*
327-------------------------------------------------------------------------------
328Returns 1 if the extended double-precision floating-point value `a' is a
329NaN; otherwise returns 0.
330-------------------------------------------------------------------------------
331*/
332flag floatx80_is_nan( floatx80 a )
333{
334
335    return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
336
337}
338
339/*
340-------------------------------------------------------------------------------
341Returns 1 if the extended double-precision floating-point value `a' is a
342signaling NaN; otherwise returns 0.
343-------------------------------------------------------------------------------
344*/
345flag floatx80_is_signaling_nan( floatx80 a )
346{
347    bits64 aLow;
348
349    aLow = a.low & ~ LIT64( 0x4000000000000000 );
350    return
351           ( ( a.high & 0x7FFF ) == 0x7FFF )
352        && (bits64) ( aLow<<1 )
353        && ( a.low == aLow );
354
355}
356
357/*
358-------------------------------------------------------------------------------
359Returns the result of converting the extended double-precision floating-
360point NaN `a' to the canonical NaN format.  If `a' is a signaling NaN, the
361invalid exception is raised.
362-------------------------------------------------------------------------------
363*/
364static commonNaNT floatx80ToCommonNaN( floatx80 a )
365{
366    commonNaNT z;
367
368    if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
369    z.sign = a.high>>15;
370    z.low = 0;
371    z.high = a.low<<1;
372    return z;
373
374}
375
376/*
377-------------------------------------------------------------------------------
378Returns the result of converting the canonical NaN `a' to the extended
379double-precision floating-point format.
380-------------------------------------------------------------------------------
381*/
382static floatx80 commonNaNToFloatx80( commonNaNT a )
383{
384    floatx80 z;
385
386    z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
387    z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
388    return z;
389
390}
391
392/*
393-------------------------------------------------------------------------------
394Takes two extended double-precision floating-point values `a' and `b', one
395of which is a NaN, and returns the appropriate NaN result.  If either `a' or
396`b' is a signaling NaN, the invalid exception is raised.
397-------------------------------------------------------------------------------
398*/
399static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
400{
401    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
402
403    aIsNaN = floatx80_is_nan( a );
404    aIsSignalingNaN = floatx80_is_signaling_nan( a );
405    bIsNaN = floatx80_is_nan( b );
406    bIsSignalingNaN = floatx80_is_signaling_nan( b );
407    a.low |= LIT64( 0xC000000000000000 );
408    b.low |= LIT64( 0xC000000000000000 );
409    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
410    if ( aIsNaN ) {
411        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
412    }
413    else {
414        return b;
415    }
416
417}
418
419#endif
420
421#ifdef FLOAT128
422
423/*
424-------------------------------------------------------------------------------
425The pattern for a default generated quadruple-precision NaN.  The `high' and
426`low' values hold the most- and least-significant bits, respectively.
427-------------------------------------------------------------------------------
428*/
429#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
430#define float128_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
431
432/*
433-------------------------------------------------------------------------------
434Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
435otherwise returns 0.
436-------------------------------------------------------------------------------
437*/
438flag float128_is_nan( float128 a )
439{
440
441    return
442           ( (bits64)LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
443        && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
444
445}
446
447/*
448-------------------------------------------------------------------------------
449Returns 1 if the quadruple-precision floating-point value `a' is a
450signaling NaN; otherwise returns 0.
451-------------------------------------------------------------------------------
452*/
453flag float128_is_signaling_nan( float128 a )
454{
455
456    return
457           ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
458        && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
459
460}
461
462/*
463-------------------------------------------------------------------------------
464Returns the result of converting the quadruple-precision floating-point NaN
465`a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
466exception is raised.
467-------------------------------------------------------------------------------
468*/
469static commonNaNT float128ToCommonNaN( float128 a )
470{
471    commonNaNT z;
472
473    if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
474    z.sign = (flag)(a.high>>63);
475    shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
476    return z;
477
478}
479
480/*
481-------------------------------------------------------------------------------
482Returns the result of converting the canonical NaN `a' to the quadruple-
483precision floating-point format.
484-------------------------------------------------------------------------------
485*/
486static float128 commonNaNToFloat128( commonNaNT a )
487{
488    float128 z;
489
490    shift128Right( a.high, a.low, 16, &z.high, &z.low );
491    z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
492    return z;
493
494}
495
496/*
497-------------------------------------------------------------------------------
498Takes two quadruple-precision floating-point values `a' and `b', one of
499which is a NaN, and returns the appropriate NaN result.  If either `a' or
500`b' is a signaling NaN, the invalid exception is raised.
501-------------------------------------------------------------------------------
502*/
503static float128 propagateFloat128NaN( float128 a, float128 b )
504{
505    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
506
507    aIsNaN = float128_is_nan( a );
508    aIsSignalingNaN = float128_is_signaling_nan( a );
509    bIsNaN = float128_is_nan( b );
510    bIsSignalingNaN = float128_is_signaling_nan( b );
511    a.high |= LIT64( 0x0000800000000000 );
512    b.high |= LIT64( 0x0000800000000000 );
513    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
514    if ( aIsNaN ) {
515        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
516    }
517    else {
518        return b;
519    }
520
521}
522
523#endif
524
525