1
2/*
3===============================================================================
4
5This C source file is part of TestFloat, Release 2a, a package of programs
6for testing the correctness of floating-point arithmetic complying to the
7IEC/IEEE Standard for Floating-Point.
8
9Written by John R. Hauser.  More information is available through the Web
10page `http://HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/TestFloat.html'.
11
12THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
13has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
14TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
15PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
16AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
17
18Derivative works are acceptable, even for commercial purposes, so long as
19(1) they include prominent notice that the work is derivative, and (2) they
20include prominent notice akin to these four paragraphs for those parts of
21this code that are retained.
22
23===============================================================================
24*/
25
26int8 slow_float_rounding_mode;
27int8 slow_float_exception_flags;
28int8 slow_float_detect_tininess;
29#ifdef FLOATX80
30int8 slow_floatx80_rounding_precision;
31#endif
32
33typedef struct {
34    bits64 a0, a1;
35} bits128X;
36
37typedef struct {
38    flag isNaN;
39    flag isInf;
40    flag isZero;
41    flag sign;
42    int32 exp;
43    bits128X sig;
44} floatX;
45
46static const floatX floatXNaN = { TRUE, FALSE, FALSE, FALSE, 0, { 0, 0 } };
47static const floatX floatXPositiveZero =
48    { FALSE, FALSE, TRUE, FALSE, 0, { 0, 0 } };
49static const floatX floatXNegativeZero =
50    { FALSE, FALSE, TRUE, TRUE, 0, { 0, 0 } };
51
52static bits128X shortShift128Left( bits128X a, int8 shiftCount )
53{
54    int8 negShiftCount;
55
56    negShiftCount = ( - shiftCount & 63 );
57    a.a0 = ( a.a0<<shiftCount ) | ( a.a1>>negShiftCount );
58    a.a1 <<= shiftCount;
59    return a;
60
61}
62
63static bits128X shortShift128RightJamming( bits128X a, int8 shiftCount )
64{
65    int8 negShiftCount;
66    bits64 extra;
67
68    negShiftCount = ( - shiftCount & 63 );
69    extra = a.a1<<negShiftCount;
70    a.a1 = ( a.a0<<negShiftCount ) | ( a.a1>>shiftCount ) | ( extra != 0 );
71    a.a0 >>= shiftCount;
72    return a;
73
74}
75
76static bits128X neg128( bits128X a )
77{
78
79    if ( a.a1 == 0 ) {
80        a.a0 = - a.a0;
81    }
82    else {
83        a.a1 = - a.a1;
84        a.a0 = ~ a.a0;
85    }
86    return a;
87
88}
89
90static bits128X add128( bits128X a, bits128X b )
91{
92
93    a.a1 += b.a1;
94    a.a0 += b.a0 + ( a.a1 < b.a1 );
95    return a;
96
97}
98
99static flag eq128( bits128X a, bits128X b )
100{
101
102    return ( a.a0 == b.a0 ) && ( a.a1 == b.a1 );
103
104}
105
106static flag le128( bits128X a, bits128X b )
107{
108
109    return ( a.a0 < b.a0 ) || ( ( a.a0 == b.a0 ) && ( a.a1 <= b.a1 ) );
110
111}
112
113static flag lt128( bits128X a, bits128X b )
114{
115
116    return ( a.a0 < b.a0 ) || ( ( a.a0 == b.a0 ) && ( a.a1 < b.a1 ) );
117
118}
119
120static floatX roundFloatXTo24( flag isTiny, floatX zx )
121{
122    bits32 roundBits;
123
124    zx.sig.a0 |= ( zx.sig.a1 != 0 );
125    zx.sig.a1 = 0;
126    roundBits = zx.sig.a0 & 0xFFFFFFFF;
127    zx.sig.a0 -= roundBits;
128    if ( roundBits ) {
129        slow_float_exception_flags |= float_flag_inexact;
130        if ( isTiny ) slow_float_exception_flags |= float_flag_underflow;
131        switch ( slow_float_rounding_mode ) {
132         case float_round_nearest_even:
133            if ( roundBits < 0x80000000 ) goto noIncrement;
134            if (    ( roundBits == 0x80000000 )
135                 && ! ( zx.sig.a0 & LIT64( 0x100000000 ) ) ) {
136                goto noIncrement;
137            }
138            break;
139         case float_round_to_zero:
140            goto noIncrement;
141         case float_round_down:
142            if ( ! zx.sign ) goto noIncrement;
143            break;
144         case float_round_up:
145            if ( zx.sign ) goto noIncrement;
146            break;
147        }
148        zx.sig.a0 += LIT64( 0x100000000 );
149        if ( zx.sig.a0 == LIT64( 0x0100000000000000 ) ) {
150            zx.sig.a0 = LIT64( 0x0080000000000000 );
151            ++zx.exp;
152        }
153    }
154 noIncrement:
155    return zx;
156
157}
158
159static floatX roundFloatXTo53( flag isTiny, floatX zx )
160{
161    int8 roundBits;
162
163    zx.sig.a0 |= ( zx.sig.a1 != 0 );
164    zx.sig.a1 = 0;
165    roundBits = zx.sig.a0 & 7;
166    zx.sig.a0 -= roundBits;
167    if ( roundBits ) {
168        slow_float_exception_flags |= float_flag_inexact;
169        if ( isTiny ) slow_float_exception_flags |= float_flag_underflow;
170        switch ( slow_float_rounding_mode ) {
171         case float_round_nearest_even:
172            if ( roundBits < 4 ) goto noIncrement;
173            if ( ( roundBits == 4 ) && ! ( zx.sig.a0 & 8 ) ) goto noIncrement;
174            break;
175         case float_round_to_zero:
176            goto noIncrement;
177         case float_round_down:
178            if ( ! zx.sign ) goto noIncrement;
179            break;
180         case float_round_up:
181            if ( zx.sign ) goto noIncrement;
182            break;
183        }
184        zx.sig.a0 += 8;
185        if ( zx.sig.a0 == LIT64( 0x0100000000000000 ) ) {
186            zx.sig.a0 = LIT64( 0x0080000000000000 );
187            ++zx.exp;
188        }
189    }
190 noIncrement:
191    return zx;
192
193}
194
195static floatX roundFloatXTo64( flag isTiny, floatX zx )
196{
197    int64 roundBits;
198
199    roundBits = zx.sig.a1 & LIT64( 0x00FFFFFFFFFFFFFF );
200    zx.sig.a1 -= roundBits;
201    if ( roundBits ) {
202        slow_float_exception_flags |= float_flag_inexact;
203        if ( isTiny ) slow_float_exception_flags |= float_flag_underflow;
204        switch ( slow_float_rounding_mode ) {
205         case float_round_nearest_even:
206            if ( roundBits < LIT64( 0x0080000000000000 ) ) goto noIncrement;
207            if (    ( roundBits == LIT64( 0x0080000000000000 ) )
208                 && ! ( zx.sig.a1 & LIT64( 0x0100000000000000 ) ) ) {
209                goto noIncrement;
210            }
211            break;
212         case float_round_to_zero:
213            goto noIncrement;
214         case float_round_down:
215            if ( ! zx.sign ) goto noIncrement;
216            break;
217         case float_round_up:
218            if ( zx.sign ) goto noIncrement;
219            break;
220        }
221        zx.sig.a1 += LIT64( 0x0100000000000000 );
222        zx.sig.a0 += ( zx.sig.a1 == 0 );
223        if ( zx.sig.a0 == LIT64( 0x0100000000000000 ) ) {
224            zx.sig.a0 = LIT64( 0x0080000000000000 );
225            ++zx.exp;
226        }
227    }
228 noIncrement:
229    return zx;
230
231}
232
233static floatX roundFloatXTo113( flag isTiny, floatX zx )
234{
235    int8 roundBits;
236
237    roundBits = zx.sig.a1 & 0x7F;
238    zx.sig.a1 -= roundBits;
239    if ( roundBits ) {
240        slow_float_exception_flags |= float_flag_inexact;
241        if ( isTiny ) slow_float_exception_flags |= float_flag_underflow;
242        switch ( slow_float_rounding_mode ) {
243         case float_round_nearest_even:
244            if ( roundBits < 0x40 ) goto noIncrement;
245            if (    ( roundBits == 0x40 )
246                 && ! ( zx.sig.a1 & 0x80 ) ) goto noIncrement;
247            break;
248         case float_round_to_zero:
249            goto noIncrement;
250         case float_round_down:
251            if ( ! zx.sign ) goto noIncrement;
252            break;
253         case float_round_up:
254            if ( zx.sign ) goto noIncrement;
255            break;
256        }
257        zx.sig.a1 += 0x80;
258        zx.sig.a0 += ( zx.sig.a1 == 0 );
259        if ( zx.sig.a0 == LIT64( 0x0100000000000000 ) ) {
260            zx.sig.a0 = LIT64( 0x0080000000000000 );
261            ++zx.exp;
262        }
263    }
264 noIncrement:
265    return zx;
266
267}
268
269static floatX int32ToFloatX( int32 a )
270{
271    floatX ax;
272
273    ax.isNaN = FALSE;
274    ax.isInf = FALSE;
275    ax.sign = ( a < 0 );
276    ax.sig.a1 = 0;
277    ax.sig.a0 = ax.sign ? - (bits64) a : a;
278    if ( a == 0 ) {
279        ax.isZero = TRUE;
280        return ax;
281    }
282    ax.isZero = FALSE;
283    ax.sig.a0 <<= 24;
284    ax.exp = 31;
285    while ( ax.sig.a0 < LIT64( 0x0080000000000000 ) ) {
286        ax.sig.a0 <<= 1;
287        --ax.exp;
288    }
289    return ax;
290
291}
292
293static int32 floatXToInt32( floatX ax )
294{
295    int8 savedExceptionFlags;
296    int32 shiftCount;
297    int32 z;
298
299    if ( ax.isInf || ax.isNaN ) {
300        slow_float_exception_flags |= float_flag_invalid;
301        return ( ax.isInf & ax.sign ) ? (sbits32) 0x80000000 : 0x7FFFFFFF;
302    }
303    if ( ax.isZero ) return 0;
304    savedExceptionFlags = slow_float_exception_flags;
305    shiftCount = 52 - ax.exp;
306    if ( 56 < shiftCount ) {
307        ax.sig.a1 = 1;
308        ax.sig.a0 = 0;
309    }
310    else {
311        while ( 0 < shiftCount ) {
312            ax.sig = shortShift128RightJamming( ax.sig, 1 );
313            --shiftCount;
314        }
315    }
316    ax = roundFloatXTo53( FALSE, ax );
317    ax.sig = shortShift128RightJamming( ax.sig, 3 );
318    z = ax.sig.a0;
319    if ( ax.sign ) z = - z;
320    if (    ( shiftCount < 0 )
321         || ( ax.sig.a0>>32 )
322         || ( ( z != 0 ) && ( ( ax.sign ^ ( z < 0 ) ) != 0 ) )
323       ) {
324        slow_float_exception_flags = savedExceptionFlags | float_flag_invalid;
325        return ax.sign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
326    }
327    return z;
328
329}
330
331static floatX int64ToFloatX( int64 a )
332{
333    uint64 absA;
334    floatX ax;
335
336    ax.isNaN = FALSE;
337    ax.isInf = FALSE;
338    ax.sign = ( a < 0 );
339    ax.sig.a1 = ax.sign ? - a : a;
340    ax.sig.a0 = 0;
341    if ( a == 0 ) {
342        ax.isZero = TRUE;
343        return ax;
344    }
345    ax.isZero = FALSE;
346    ax.sig = shortShift128Left( ax.sig, 56 );
347    ax.exp = 63;
348    while ( ax.sig.a0 < LIT64( 0x0080000000000000 ) ) {
349        ax.sig = shortShift128Left( ax.sig, 1 );
350        --ax.exp;
351    }
352    return ax;
353
354}
355
356static int64 floatXToInt64( floatX ax )
357{
358    int8 savedExceptionFlags;
359    int32 shiftCount;
360    int64 z;
361
362    if ( ax.isInf || ax.isNaN ) {
363        slow_float_exception_flags |= float_flag_invalid;
364        return
365              ( ax.isInf & ax.sign ) ? (sbits64) LIT64( 0x8000000000000000 )
366            : LIT64( 0x7FFFFFFFFFFFFFFF );
367    }
368    if ( ax.isZero ) return 0;
369    savedExceptionFlags = slow_float_exception_flags;
370    shiftCount = 112 - ax.exp;
371    if ( 116 < shiftCount ) {
372        ax.sig.a1 = 1;
373        ax.sig.a0 = 0;
374    }
375    else {
376        while ( 0 < shiftCount ) {
377            ax.sig = shortShift128RightJamming( ax.sig, 1 );
378            --shiftCount;
379        }
380    }
381    ax = roundFloatXTo113( FALSE, ax );
382    ax.sig = shortShift128RightJamming( ax.sig, 7 );
383    z = ax.sig.a1;
384    if ( ax.sign ) z = - z;
385    if (    ( shiftCount < 0 )
386         || ax.sig.a0
387         || ( ( z != 0 ) && ( ( ax.sign ^ ( z < 0 ) ) != 0 ) )
388       ) {
389        slow_float_exception_flags = savedExceptionFlags | float_flag_invalid;
390        return
391              ax.sign ? (sbits64) LIT64( 0x8000000000000000 )
392            : LIT64( 0x7FFFFFFFFFFFFFFF );
393    }
394    return z;
395
396}
397
398static floatX float32ToFloatX( float32 a )
399{
400    int16 expField;
401    floatX ax;
402
403    ax.isNaN = FALSE;
404    ax.isInf = FALSE;
405    ax.isZero = FALSE;
406    ax.sign = ( ( a & 0x80000000 ) != 0 );
407    expField = ( a>>23 ) & 0xFF;
408    ax.sig.a1 = 0;
409    ax.sig.a0 = a & 0x007FFFFF;
410    ax.sig.a0 <<= 32;
411    if ( expField == 0 ) {
412        if ( ax.sig.a0 == 0 ) {
413            ax.isZero = TRUE;
414        }
415        else {
416            expField = 1 - 0x7F;
417            do {
418                ax.sig.a0 <<= 1;
419                --expField;
420            } while ( ax.sig.a0 < LIT64( 0x0080000000000000 ) );
421            ax.exp = expField;
422        }
423    }
424    else if ( expField == 0xFF ) {
425        if ( ax.sig.a0 == 0 ) {
426            ax.isInf = TRUE;
427        }
428        else {
429            ax.isNaN = TRUE;
430        }
431    }
432    else {
433        ax.sig.a0 |= LIT64( 0x0080000000000000 );
434        ax.exp = expField - 0x7F;
435    }
436    return ax;
437
438}
439
440static float32 floatXToFloat32( floatX zx )
441{
442    floatX savedZ;
443    flag isTiny;
444    int32 expField;
445    float32 z;
446
447    if ( zx.isZero ) return zx.sign ? 0x80000000 : 0;
448    if ( zx.isInf ) return zx.sign ? 0xFF800000 : 0x7F800000;
449    if ( zx.isNaN ) return 0xFFFFFFFF;
450    while ( LIT64( 0x0100000000000000 ) <= zx.sig.a0 ) {
451        zx.sig = shortShift128RightJamming( zx.sig, 1 );
452        ++zx.exp;
453    }
454    while ( zx.sig.a0 < LIT64( 0x0080000000000000 ) ) {
455        zx.sig = shortShift128Left( zx.sig, 1 );
456        --zx.exp;
457    }
458    savedZ = zx;
459    isTiny =
460           ( slow_float_detect_tininess == float_tininess_before_rounding )
461        && ( zx.exp + 0x7F <= 0 );
462    zx = roundFloatXTo24( isTiny, zx );
463    expField = zx.exp + 0x7F;
464    if ( 0xFF <= expField ) {
465        slow_float_exception_flags |=
466            float_flag_overflow | float_flag_inexact;
467        if ( zx.sign ) {
468            switch ( slow_float_rounding_mode ) {
469             case float_round_nearest_even:
470             case float_round_down:
471                z = 0xFF800000;
472                break;
473             case float_round_to_zero:
474             case float_round_up:
475                z = 0xFF7FFFFF;
476                break;
477            }
478        }
479        else {
480            switch ( slow_float_rounding_mode ) {
481             case float_round_nearest_even:
482             case float_round_up:
483                z = 0x7F800000;
484                break;
485             case float_round_to_zero:
486             case float_round_down:
487                z = 0x7F7FFFFF;
488                break;
489            }
490        }
491        return z;
492    }
493    if ( expField <= 0 ) {
494        isTiny = TRUE;
495        zx = savedZ;
496        expField = zx.exp + 0x7F;
497        if ( expField < -27 ) {
498            zx.sig.a1 = ( zx.sig.a0 != 0 ) || ( zx.sig.a1 != 0 );
499            zx.sig.a0 = 0;
500        }
501        else {
502            while ( expField <= 0 ) {
503                zx.sig = shortShift128RightJamming( zx.sig, 1 );
504                ++expField;
505            }
506        }
507        zx = roundFloatXTo24( isTiny, zx );
508        expField = ( LIT64( 0x0080000000000000 ) <= zx.sig.a0 ) ? 1 : 0;
509    }
510    z = expField;
511    z <<= 23;
512    if ( zx.sign ) z |= 0x80000000;
513    z |= ( zx.sig.a0>>32 ) & 0x007FFFFF;
514    return z;
515
516}
517
518static floatX float64ToFloatX( float64 a )
519{
520    int16 expField;
521    floatX ax;
522
523    ax.isNaN = FALSE;
524    ax.isInf = FALSE;
525    ax.isZero = FALSE;
526    ax.sign = ( ( a & LIT64( 0x8000000000000000 ) ) != 0 );
527    expField = ( a>>52 ) & 0x7FF;
528    ax.sig.a1 = 0;
529    ax.sig.a0 = a & LIT64( 0x000FFFFFFFFFFFFF );
530    if ( expField == 0 ) {
531        if ( ax.sig.a0 == 0 ) {
532            ax.isZero = TRUE;
533        }
534        else {
535            expField = 1 - 0x3FF;
536            do {
537                ax.sig.a0 <<= 1;
538                --expField;
539            } while ( ax.sig.a0 < LIT64( 0x0010000000000000 ) );
540            ax.exp = expField;
541        }
542    }
543    else if ( expField == 0x7FF ) {
544        if ( ax.sig.a0 == 0 ) {
545            ax.isInf = TRUE;
546        }
547        else {
548            ax.isNaN = TRUE;
549        }
550    }
551    else {
552        ax.exp = expField - 0x3FF;
553        ax.sig.a0 |= LIT64( 0x0010000000000000 );
554    }
555    ax.sig.a0 <<= 3;
556    return ax;
557
558}
559
560static float64 floatXToFloat64( floatX zx )
561{
562    floatX savedZ;
563    flag isTiny;
564    int32 expField;
565    float64 z;
566
567    if ( zx.isZero ) return zx.sign ? LIT64( 0x8000000000000000 ) : 0;
568    if ( zx.isInf ) {
569        return
570              zx.sign ? LIT64( 0xFFF0000000000000 )
571            : LIT64( 0x7FF0000000000000 );
572    }
573    if ( zx.isNaN ) return LIT64( 0xFFFFFFFFFFFFFFFF );
574    while ( LIT64( 0x0100000000000000 ) <= zx.sig.a0 ) {
575        zx.sig = shortShift128RightJamming( zx.sig, 1 );
576        ++zx.exp;
577    }
578    while ( zx.sig.a0 < LIT64( 0x0080000000000000 ) ) {
579        zx.sig = shortShift128Left( zx.sig, 1 );
580        --zx.exp;
581    }
582    savedZ = zx;
583    isTiny =
584           ( slow_float_detect_tininess == float_tininess_before_rounding )
585        && ( zx.exp + 0x3FF <= 0 );
586    zx = roundFloatXTo53( isTiny, zx );
587    expField = zx.exp + 0x3FF;
588    if ( 0x7FF <= expField ) {
589        slow_float_exception_flags |=
590            float_flag_overflow | float_flag_inexact;
591        if ( zx.sign ) {
592            switch ( slow_float_rounding_mode ) {
593             case float_round_nearest_even:
594             case float_round_down:
595                z = LIT64( 0xFFF0000000000000 );
596                break;
597             case float_round_to_zero:
598             case float_round_up:
599                z = LIT64( 0xFFEFFFFFFFFFFFFF );
600                break;
601            }
602        }
603        else {
604            switch ( slow_float_rounding_mode ) {
605             case float_round_nearest_even:
606             case float_round_up:
607                z = LIT64( 0x7FF0000000000000 );
608                break;
609             case float_round_to_zero:
610             case float_round_down:
611                z = LIT64( 0x7FEFFFFFFFFFFFFF );
612                break;
613            }
614        }
615        return z;
616    }
617    if ( expField <= 0 ) {
618        isTiny = TRUE;
619        zx = savedZ;
620        expField = zx.exp + 0x3FF;
621        if ( expField < -56 ) {
622            zx.sig.a1 = ( zx.sig.a0 != 0 ) || ( zx.sig.a1 != 0 );
623            zx.sig.a0 = 0;
624        }
625        else {
626            while ( expField <= 0 ) {
627                zx.sig = shortShift128RightJamming( zx.sig, 1 );
628                ++expField;
629            }
630        }
631        zx = roundFloatXTo53( isTiny, zx );
632        expField = ( LIT64( 0x0080000000000000 ) <= zx.sig.a0 ) ? 1 : 0;
633    }
634    zx.sig.a0 >>= 3;
635    z = expField;
636    z <<= 52;
637    if ( zx.sign ) z |= LIT64( 0x8000000000000000 );
638    z |= zx.sig.a0 & LIT64( 0x000FFFFFFFFFFFFF );
639    return z;
640
641}
642
643#ifdef FLOATX80
644
645static floatX floatx80ToFloatX( floatx80 a )
646{
647    int32 expField;
648    floatX ax;
649
650    ax.isNaN = FALSE;
651    ax.isInf = FALSE;
652    ax.isZero = FALSE;
653    ax.sign = ( ( a.high & 0x8000 ) != 0 );
654    expField = a.high & 0x7FFF;
655    ax.sig.a1 = a.low;
656    ax.sig.a0 = 0;
657    if ( expField == 0 ) {
658        if ( ax.sig.a1 == 0 ) {
659            ax.isZero = TRUE;
660        }
661        else {
662            expField = 1 - 0x3FFF;
663            while ( ax.sig.a1 < LIT64( 0x8000000000000000 ) ) {
664                ax.sig.a1 <<= 1;
665                --expField;
666            }
667            ax.exp = expField;
668        }
669    }
670    else if ( expField == 0x7FFF ) {
671        if ( ( ax.sig.a1 & LIT64( 0x7FFFFFFFFFFFFFFF ) ) == 0 ) {
672            ax.isInf = TRUE;
673        }
674        else {
675            ax.isNaN = TRUE;
676        }
677    }
678    else {
679        ax.exp = expField - 0x3FFF;
680    }
681    ax.sig = shortShift128Left( ax.sig, 56 );
682    return ax;
683
684}
685
686static floatx80 floatXToFloatx80( floatX zx )
687{
688    floatX savedZ;
689    flag isTiny;
690    int32 expField;
691    floatx80 z;
692
693    if ( zx.isZero ) {
694        z.low = 0;
695        z.high = zx.sign ? 0x8000 : 0;
696        return z;
697    }
698    if ( zx.isInf ) {
699        z.low = LIT64( 0x8000000000000000 );
700        z.high = zx.sign ? 0xFFFF : 0x7FFF;
701        return z;
702    }
703    if ( zx.isNaN ) {
704        z.low = LIT64( 0xFFFFFFFFFFFFFFFF );
705        z.high = 0xFFFF;
706        return z;
707    }
708    while ( LIT64( 0x0100000000000000 ) <= zx.sig.a0 ) {
709        zx.sig = shortShift128RightJamming( zx.sig, 1 );
710        ++zx.exp;
711    }
712    while ( zx.sig.a0 < LIT64( 0x0080000000000000 ) ) {
713        zx.sig = shortShift128Left( zx.sig, 1 );
714        --zx.exp;
715    }
716    savedZ = zx;
717    isTiny =
718           ( slow_float_detect_tininess == float_tininess_before_rounding )
719        && ( zx.exp + 0x3FFF <= 0 );
720    switch ( slow_floatx80_rounding_precision ) {
721     case 32:
722        zx = roundFloatXTo24( isTiny, zx );
723        break;
724     case 64:
725        zx = roundFloatXTo53( isTiny, zx );
726        break;
727     default:
728        zx = roundFloatXTo64( isTiny, zx );
729        break;
730    }
731    expField = zx.exp + 0x3FFF;
732    if ( 0x7FFF <= expField ) {
733        slow_float_exception_flags |=
734            float_flag_overflow | float_flag_inexact;
735        if ( zx.sign ) {
736            switch ( slow_float_rounding_mode ) {
737             case float_round_nearest_even:
738             case float_round_down:
739                z.low = LIT64( 0x8000000000000000 );
740                z.high = 0xFFFF;
741                break;
742             case float_round_to_zero:
743             case float_round_up:
744                switch ( slow_floatx80_rounding_precision ) {
745                 case 32:
746                    z.low = LIT64( 0xFFFFFF0000000000 );
747                    break;
748                 case 64:
749                    z.low = LIT64( 0xFFFFFFFFFFFFF800 );
750                    break;
751                 default:
752                    z.low = LIT64( 0xFFFFFFFFFFFFFFFF );
753                    break;
754                }
755                z.high = 0xFFFE;
756                break;
757            }
758        }
759        else {
760            switch ( slow_float_rounding_mode ) {
761             case float_round_nearest_even:
762             case float_round_up:
763                z.low = LIT64( 0x8000000000000000 );
764                z.high = 0x7FFF;
765                break;
766             case float_round_to_zero:
767             case float_round_down:
768                switch ( slow_floatx80_rounding_precision ) {
769                 case 32:
770                    z.low = LIT64( 0xFFFFFF0000000000 );
771                    break;
772                 case 64:
773                    z.low = LIT64( 0xFFFFFFFFFFFFF800 );
774                    break;
775                 default:
776                    z.low = LIT64( 0xFFFFFFFFFFFFFFFF );
777                    break;
778                }
779                z.high = 0x7FFE;
780                break;
781            }
782        }
783        return z;
784    }
785    if ( expField <= 0 ) {
786        isTiny = TRUE;
787        zx = savedZ;
788        expField = zx.exp + 0x3FFF;
789        if ( expField < -70 ) {
790            zx.sig.a1 = ( zx.sig.a0 != 0 ) || ( zx.sig.a1 != 0 );
791            zx.sig.a0 = 0;
792        }
793        else {
794            while ( expField <= 0 ) {
795                zx.sig = shortShift128RightJamming( zx.sig, 1 );
796                ++expField;
797            }
798        }
799        switch ( slow_floatx80_rounding_precision ) {
800         case 32:
801            zx = roundFloatXTo24( isTiny, zx );
802            break;
803         case 64:
804            zx = roundFloatXTo53( isTiny, zx );
805            break;
806         default:
807            zx = roundFloatXTo64( isTiny, zx );
808            break;
809        }
810        expField = ( LIT64( 0x0080000000000000 ) <= zx.sig.a0 ) ? 1 : 0;
811    }
812    zx.sig = shortShift128RightJamming( zx.sig, 56 );
813    z.low = zx.sig.a1;
814    z.high = expField;
815    if ( zx.sign ) z.high |= 0x8000;
816    return z;
817
818}
819
820#endif
821
822#ifdef FLOAT128
823
824static floatX float128ToFloatX( float128 a )
825{
826    int32 expField;
827    floatX ax;
828
829    ax.isNaN = FALSE;
830    ax.isInf = FALSE;
831    ax.isZero = FALSE;
832    ax.sign = ( ( a.high & LIT64( 0x8000000000000000 ) ) != 0 );
833    expField = ( a.high>>48 ) & 0x7FFF;
834    ax.sig.a1 = a.low;
835    ax.sig.a0 = a.high & LIT64( 0x0000FFFFFFFFFFFF );
836    if ( expField == 0 ) {
837        if ( ( ax.sig.a0 == 0 ) && ( ax.sig.a1 == 0 ) ) {
838            ax.isZero = TRUE;
839        }
840        else {
841            expField = 1 - 0x3FFF;
842            do {
843                ax.sig = shortShift128Left( ax.sig, 1 );
844                --expField;
845            } while ( ax.sig.a0 < LIT64( 0x0001000000000000 ) );
846            ax.exp = expField;
847        }
848    }
849    else if ( expField == 0x7FFF ) {
850        if ( ( ax.sig.a0 == 0 ) && ( ax.sig.a1 == 0 ) ) {
851            ax.isInf = TRUE;
852        }
853        else {
854            ax.isNaN = TRUE;
855        }
856    }
857    else {
858        ax.exp = expField - 0x3FFF;
859        ax.sig.a0 |= LIT64( 0x0001000000000000 );
860    }
861    ax.sig = shortShift128Left( ax.sig, 7 );
862    return ax;
863
864}
865
866static float128 floatXToFloat128( floatX zx )
867{
868    floatX savedZ;
869    flag isTiny;
870    int32 expField;
871    float128 z;
872
873    if ( zx.isZero ) {
874        z.low = 0;
875        z.high = zx.sign ? LIT64( 0x8000000000000000 ) : 0;
876        return z;
877    }
878    if ( zx.isInf ) {
879        z.low = 0;
880        z.high =
881              zx.sign ? LIT64( 0xFFFF000000000000 )
882            : LIT64( 0x7FFF000000000000 );
883        return z;
884    }
885    if ( zx.isNaN ) {
886        z.high = z.low = LIT64( 0xFFFFFFFFFFFFFFFF );
887        return z;
888    }
889    while ( LIT64( 0x0100000000000000 ) <= zx.sig.a0 ) {
890        zx.sig = shortShift128RightJamming( zx.sig, 1 );
891        ++zx.exp;
892    }
893    while ( zx.sig.a0 < LIT64( 0x0080000000000000 ) ) {
894        zx.sig = shortShift128Left( zx.sig, 1 );
895        --zx.exp;
896    }
897    savedZ = zx;
898    isTiny =
899           ( slow_float_detect_tininess == float_tininess_before_rounding )
900        && ( zx.exp + 0x3FFF <= 0 );
901    zx = roundFloatXTo113( isTiny, zx );
902    expField = zx.exp + 0x3FFF;
903    if ( 0x7FFF <= expField ) {
904        slow_float_exception_flags |=
905            float_flag_overflow | float_flag_inexact;
906        if ( zx.sign ) {
907            switch ( slow_float_rounding_mode ) {
908             case float_round_nearest_even:
909             case float_round_down:
910                z.low = 0;
911                z.high = LIT64( 0xFFFF000000000000 );
912                break;
913             case float_round_to_zero:
914             case float_round_up:
915                z.low = LIT64( 0xFFFFFFFFFFFFFFFF );
916                z.high = LIT64( 0xFFFEFFFFFFFFFFFF );
917                break;
918            }
919        }
920        else {
921            switch ( slow_float_rounding_mode ) {
922             case float_round_nearest_even:
923             case float_round_up:
924                z.low = 0;
925                z.high = LIT64( 0x7FFF000000000000 );
926                break;
927             case float_round_to_zero:
928             case float_round_down:
929                z.low = LIT64( 0xFFFFFFFFFFFFFFFF );
930                z.high = LIT64( 0x7FFEFFFFFFFFFFFF );
931                break;
932            }
933        }
934        return z;
935    }
936    if ( expField <= 0 ) {
937        isTiny = TRUE;
938        zx = savedZ;
939        expField = zx.exp + 0x3FFF;
940        if ( expField < -120 ) {
941            zx.sig.a1 = ( zx.sig.a0 != 0 ) || ( zx.sig.a1 != 0 );
942            zx.sig.a0 = 0;
943        }
944        else {
945            while ( expField <= 0 ) {
946                zx.sig = shortShift128RightJamming( zx.sig, 1 );
947                ++expField;
948            }
949        }
950        zx = roundFloatXTo113( isTiny, zx );
951        expField = ( LIT64( 0x0080000000000000 ) <= zx.sig.a0 ) ? 1 : 0;
952    }
953    zx.sig = shortShift128RightJamming( zx.sig, 7 );
954    z.low = zx.sig.a1;
955    z.high = expField;
956    z.high <<= 48;
957    if ( zx.sign ) z.high |= LIT64( 0x8000000000000000 );
958    z.high |= zx.sig.a0 & LIT64( 0x0000FFFFFFFFFFFF );
959    return z;
960
961}
962
963#endif
964
965static floatX floatXInvalid( void )
966{
967
968    slow_float_exception_flags |= float_flag_invalid;
969    return floatXNaN;
970
971}
972
973static floatX floatXRoundToInt( floatX ax )
974{
975    int32 shiftCount, i;
976
977    if ( ax.isNaN || ax.isInf ) return ax;
978    shiftCount = 112 - ax.exp;
979    if ( shiftCount <= 0 ) return ax;
980    if ( 119 < shiftCount ) {
981        ax.exp = 112;
982        ax.sig.a1 = ! ax.isZero;
983        ax.sig.a0 = 0;
984    }
985    else {
986        while ( 0 < shiftCount ) {
987            ax.sig = shortShift128RightJamming( ax.sig, 1 );
988            ++ax.exp;
989            --shiftCount;
990        }
991    }
992    ax = roundFloatXTo113( FALSE, ax );
993    if ( ( ax.sig.a0 == 0 ) && ( ax.sig.a1 == 0 ) ) ax.isZero = TRUE;
994    return ax;
995
996}
997
998static floatX floatXAdd( floatX ax, floatX bx )
999{
1000    int32 expDiff;
1001    floatX zx;
1002
1003    if ( ax.isNaN ) return ax;
1004    if ( bx.isNaN ) return bx;
1005    if ( ax.isInf && bx.isInf ) {
1006        if ( ax.sign == bx.sign ) return ax;
1007        return floatXInvalid();
1008    }
1009    if ( ax.isInf ) return ax;
1010    if ( bx.isInf ) return bx;
1011    if ( ax.isZero && bx.isZero ) {
1012        if ( ax.sign == bx.sign ) return ax;
1013        goto completeCancellation;
1014    }
1015    if (    ( ax.sign != bx.sign )
1016         && ( ax.exp == bx.exp )
1017         && eq128( ax.sig, bx.sig )
1018       ) {
1019 completeCancellation:
1020        return
1021              ( slow_float_rounding_mode == float_round_down ) ?
1022                  floatXNegativeZero
1023            : floatXPositiveZero;
1024    }
1025    if ( ax.isZero ) return bx;
1026    if ( bx.isZero ) return ax;
1027    expDiff = ax.exp - bx.exp;
1028    if ( expDiff < 0 ) {
1029        zx = ax;
1030        zx.exp = bx.exp;
1031        if ( expDiff < -120 ) {
1032            zx.sig.a1 = 1;
1033            zx.sig.a0 = 0;
1034        }
1035        else {
1036            while ( expDiff < 0 ) {
1037                zx.sig = shortShift128RightJamming( zx.sig, 1 );
1038                ++expDiff;
1039            }
1040        }
1041        if ( ax.sign != bx.sign ) zx.sig = neg128( zx.sig );
1042        zx.sign = bx.sign;
1043        zx.sig = add128( zx.sig, bx.sig );
1044    }
1045    else {
1046        zx = bx;
1047        zx.exp = ax.exp;
1048        if ( 120 < expDiff ) {
1049            zx.sig.a1 = 1;
1050            zx.sig.a0 = 0;
1051        }
1052        else {
1053            while ( 0 < expDiff ) {
1054                zx.sig = shortShift128RightJamming( zx.sig, 1 );
1055                --expDiff;
1056            }
1057        }
1058        if ( ax.sign != bx.sign ) zx.sig = neg128( zx.sig );
1059        zx.sign = ax.sign;
1060        zx.sig = add128( zx.sig, ax.sig );
1061    }
1062    if ( zx.sig.a0 & LIT64( 0x8000000000000000 ) ) {
1063        zx.sig = neg128( zx.sig );
1064        zx.sign = ! zx.sign;
1065    }
1066    return zx;
1067
1068}
1069
1070static floatX floatXMul( floatX ax, floatX bx )
1071{
1072    int8 bitNum;
1073    floatX zx;
1074
1075    if ( ax.isNaN ) return ax;
1076    if ( bx.isNaN ) return bx;
1077    if ( ax.isInf ) {
1078        if ( bx.isZero ) return floatXInvalid();
1079        if ( bx.sign ) ax.sign = ! ax.sign;
1080        return ax;
1081    }
1082    if ( bx.isInf ) {
1083        if ( ax.isZero ) return floatXInvalid();
1084        if ( ax.sign ) bx.sign = ! bx.sign;
1085        return bx;
1086    }
1087    zx = ax;
1088    zx.sign ^= bx.sign;
1089    if ( ax.isZero || bx.isZero ) {
1090        return zx.sign ? floatXNegativeZero : floatXPositiveZero;
1091    }
1092    zx.exp += bx.exp + 1;
1093    zx.sig.a1 = 0;
1094    zx.sig.a0 = 0;
1095    for ( bitNum = 0; bitNum < 119; ++bitNum ) {
1096        if ( bx.sig.a1 & 2 ) zx.sig = add128( zx.sig, ax.sig );
1097        bx.sig = shortShift128RightJamming( bx.sig, 1 );
1098        zx.sig = shortShift128RightJamming( zx.sig, 1 );
1099    }
1100    return zx;
1101
1102}
1103
1104static floatX floatXDiv( floatX ax, floatX bx )
1105{
1106    bits128X negBSig;
1107    int8 bitNum;
1108    floatX zx;
1109
1110    if ( ax.isNaN ) return ax;
1111    if ( bx.isNaN ) return bx;
1112    if ( ax.isInf ) {
1113        if ( bx.isInf ) return floatXInvalid();
1114        if ( bx.sign ) ax.sign = ! ax.sign;
1115        return ax;
1116    }
1117    if ( bx.isZero ) {
1118        if ( ax.isZero ) return floatXInvalid();
1119        slow_float_exception_flags |= float_flag_divbyzero;
1120        if ( ax.sign ) bx.sign = ! bx.sign;
1121        bx.isZero = FALSE;
1122        bx.isInf = TRUE;
1123        return bx;
1124    }
1125    zx = ax;
1126    zx.sign ^= bx.sign;
1127    if ( ax.isZero || bx.isInf ) {
1128        return zx.sign ? floatXNegativeZero : floatXPositiveZero;
1129    }
1130    zx.exp -= bx.exp + 1;
1131    zx.sig.a1 = 0;
1132    zx.sig.a0 = 0;
1133    negBSig = neg128( bx.sig );
1134    for ( bitNum = 0; bitNum < 120; ++bitNum ) {
1135        if ( le128( bx.sig, ax.sig ) ) {
1136            zx.sig.a1 |= 1;
1137            ax.sig = add128( ax.sig, negBSig );
1138        }
1139        ax.sig = shortShift128Left( ax.sig, 1 );
1140        zx.sig = shortShift128Left( zx.sig, 1 );
1141    }
1142    if ( ax.sig.a0 || ax.sig.a1 ) zx.sig.a1 |= 1;
1143    return zx;
1144
1145}
1146
1147static floatX floatXRem( floatX ax, floatX bx )
1148{
1149    bits128X negBSig;
1150    flag lastQuotientBit;
1151    bits128X savedASig;
1152
1153    if ( ax.isNaN ) return ax;
1154    if ( bx.isNaN ) return bx;
1155    if ( ax.isInf || bx.isZero ) return floatXInvalid();
1156    if ( ax.isZero || bx.isInf ) return ax;
1157    --bx.exp;
1158    if ( ax.exp < bx.exp ) return ax;
1159    bx.sig = shortShift128Left( bx.sig, 1 );
1160    negBSig = neg128( bx.sig );
1161    while ( bx.exp < ax.exp ) {
1162        if ( le128( bx.sig, ax.sig ) ) ax.sig = add128( ax.sig, negBSig );
1163        ax.sig = shortShift128Left( ax.sig, 1 );
1164        --ax.exp;
1165    }
1166    lastQuotientBit = le128( bx.sig, ax.sig );
1167    if ( lastQuotientBit ) ax.sig = add128( ax.sig, negBSig );
1168    savedASig = ax.sig;
1169    ax.sig = neg128( add128( ax.sig, negBSig ) );
1170    if ( lt128( ax.sig, savedASig ) ) {
1171        ax.sign = ! ax.sign;
1172    }
1173    else if ( lt128( savedASig, ax.sig ) ) {
1174        ax.sig = savedASig;
1175    }
1176    else {
1177        if ( lastQuotientBit ) {
1178            ax.sign = ! ax.sign;
1179        }
1180        else {
1181            ax.sig = savedASig;
1182        }
1183    }
1184    if ( ( ax.sig.a0 == 0 ) && ( ax.sig.a1 == 0 ) ) ax.isZero = TRUE;
1185    return ax;
1186
1187}
1188
1189static floatX floatXSqrt( floatX ax )
1190{
1191    int8 bitNum;
1192    bits128X bitSig, savedASig;
1193    floatX zx;
1194
1195    if ( ax.isNaN || ax.isZero ) return ax;
1196    if ( ax.sign ) return floatXInvalid();
1197    if ( ax.isInf ) return ax;
1198    zx = ax;
1199    zx.exp >>= 1;
1200    if ( ( ax.exp & 1 ) == 0 ) ax.sig = shortShift128RightJamming( ax.sig, 1 );
1201    zx.sig.a1 = 0;
1202    zx.sig.a0 = 0;
1203    bitSig.a1 = 0;
1204    bitSig.a0 = LIT64( 0x0080000000000000 );
1205    for ( bitNum = 0; bitNum < 120; ++bitNum ) {
1206        savedASig = ax.sig;
1207        ax.sig = add128( ax.sig, neg128( zx.sig ) );
1208        ax.sig = shortShift128Left( ax.sig, 1 );
1209        ax.sig = add128( ax.sig, neg128( bitSig ) );
1210        if ( ax.sig.a0 & LIT64( 0x8000000000000000 ) ) {
1211            ax.sig = shortShift128Left( savedASig, 1 );
1212        }
1213        else {
1214            zx.sig.a1 |= bitSig.a1;
1215            zx.sig.a0 |= bitSig.a0;
1216        }
1217        bitSig = shortShift128RightJamming( bitSig, 1 );
1218    }
1219    if ( ax.sig.a0 || ax.sig.a1 ) zx.sig.a1 |= 1;
1220    return zx;
1221
1222}
1223
1224static flag floatXEq( floatX ax, floatX bx )
1225{
1226
1227    if ( ax.isNaN || bx.isNaN ) return FALSE;
1228    if ( ax.isZero && bx.isZero ) return TRUE;
1229    if ( ax.sign != bx.sign ) return FALSE;
1230    if ( ax.isInf || bx.isInf ) return ax.isInf && bx.isInf;
1231    return ( ax.exp == bx.exp ) && eq128( ax.sig, bx.sig );
1232
1233}
1234
1235static flag floatXLe( floatX ax, floatX bx )
1236{
1237
1238    if ( ax.isNaN || bx.isNaN ) return FALSE;
1239    if ( ax.isZero && bx.isZero ) return TRUE;
1240    if ( ax.sign != bx.sign ) return ax.sign;
1241    if ( ax.sign ) {
1242        if ( ax.isInf || bx.isZero ) return TRUE;
1243        if ( bx.isInf || ax.isZero ) return FALSE;
1244        if ( bx.exp < ax.exp ) return TRUE;
1245        if ( ax.exp < bx.exp ) return FALSE;
1246        return le128( bx.sig, ax.sig );
1247    }
1248    else {
1249        if ( bx.isInf || ax.isZero ) return TRUE;
1250        if ( ax.isInf || bx.isZero ) return FALSE;
1251        if ( ax.exp < bx.exp ) return TRUE;
1252        if ( bx.exp < ax.exp ) return FALSE;
1253        return le128( ax.sig, bx.sig );
1254    }
1255
1256}
1257
1258static flag floatXLt( floatX ax, floatX bx )
1259{
1260
1261    if ( ax.isNaN || bx.isNaN ) return FALSE;
1262    if ( ax.isZero && bx.isZero ) return FALSE;
1263    if ( ax.sign != bx.sign ) return ax.sign;
1264    if ( ax.isInf && bx.isInf ) return FALSE;
1265    if ( ax.sign ) {
1266        if ( ax.isInf || bx.isZero ) return TRUE;
1267        if ( bx.isInf || ax.isZero ) return FALSE;
1268        if ( bx.exp < ax.exp ) return TRUE;
1269        if ( ax.exp < bx.exp ) return FALSE;
1270        return lt128( bx.sig, ax.sig );
1271    }
1272    else {
1273        if ( bx.isInf || ax.isZero ) return TRUE;
1274        if ( ax.isInf || bx.isZero ) return FALSE;
1275        if ( ax.exp < bx.exp ) return TRUE;
1276        if ( bx.exp < ax.exp ) return FALSE;
1277        return lt128( ax.sig, bx.sig );
1278    }
1279
1280}
1281
1282float32 slow_int32_to_float32( int32 a )
1283{
1284
1285    return floatXToFloat32( int32ToFloatX( a ) );
1286
1287}
1288
1289float64 slow_int32_to_float64( int32 a )
1290{
1291
1292    return floatXToFloat64( int32ToFloatX( a ) );
1293
1294}
1295
1296#ifdef FLOATX80
1297
1298floatx80 slow_int32_to_floatx80( int32 a )
1299{
1300
1301    return floatXToFloatx80( int32ToFloatX( a ) );
1302
1303}
1304
1305#endif
1306
1307#ifdef FLOAT128
1308
1309float128 slow_int32_to_float128( int32 a )
1310{
1311
1312    return floatXToFloat128( int32ToFloatX( a ) );
1313
1314}
1315
1316#endif
1317
1318float32 slow_int64_to_float32( int64 a )
1319{
1320
1321    return floatXToFloat32( int64ToFloatX( a ) );
1322
1323}
1324
1325float64 slow_int64_to_float64( int64 a )
1326{
1327
1328    return floatXToFloat64( int64ToFloatX( a ) );
1329
1330}
1331
1332#ifdef FLOATX80
1333
1334floatx80 slow_int64_to_floatx80( int64 a )
1335{
1336
1337    return floatXToFloatx80( int64ToFloatX( a ) );
1338
1339}
1340
1341#endif
1342
1343#ifdef FLOAT128
1344
1345float128 slow_int64_to_float128( int64 a )
1346{
1347
1348    return floatXToFloat128( int64ToFloatX( a ) );
1349
1350}
1351
1352#endif
1353
1354int32 slow_float32_to_int32( float32 a )
1355{
1356
1357    return floatXToInt32( float32ToFloatX( a ) );
1358
1359}
1360
1361int32 slow_float32_to_int32_round_to_zero( float32 a )
1362{
1363    int8 savedRoundingMode;
1364    int32 z;
1365
1366    savedRoundingMode = slow_float_rounding_mode;
1367    slow_float_rounding_mode = float_round_to_zero;
1368    z = floatXToInt32( float32ToFloatX( a ) );
1369    slow_float_rounding_mode = savedRoundingMode;
1370    return z;
1371
1372}
1373
1374int64 slow_float32_to_int64( float32 a )
1375{
1376
1377    return floatXToInt64( float32ToFloatX( a ) );
1378
1379}
1380
1381int64 slow_float32_to_int64_round_to_zero( float32 a )
1382{
1383    int8 savedRoundingMode;
1384    int64 z;
1385
1386    savedRoundingMode = slow_float_rounding_mode;
1387    slow_float_rounding_mode = float_round_to_zero;
1388    z = floatXToInt64( float32ToFloatX( a ) );
1389    slow_float_rounding_mode = savedRoundingMode;
1390    return z;
1391
1392}
1393
1394float64 slow_float32_to_float64( float32 a )
1395{
1396
1397    return floatXToFloat64( float32ToFloatX( a ) );
1398
1399}
1400
1401#ifdef FLOATX80
1402
1403floatx80 slow_float32_to_floatx80( float32 a )
1404{
1405
1406    return floatXToFloatx80( float32ToFloatX( a ) );
1407
1408}
1409
1410#endif
1411
1412#ifdef FLOAT128
1413
1414float128 slow_float32_to_float128( float32 a )
1415{
1416
1417    return floatXToFloat128( float32ToFloatX( a ) );
1418
1419}
1420
1421#endif
1422
1423float32 slow_float32_round_to_int( float32 a )
1424{
1425
1426    return floatXToFloat32( floatXRoundToInt( float32ToFloatX( a ) ) );
1427
1428}
1429
1430float32 slow_float32_add( float32 a, float32 b )
1431{
1432
1433    return
1434        floatXToFloat32(
1435            floatXAdd( float32ToFloatX( a ), float32ToFloatX( b ) ) );
1436
1437}
1438
1439float32 slow_float32_sub( float32 a, float32 b )
1440{
1441
1442    b ^= 0x80000000;
1443    return
1444        floatXToFloat32(
1445            floatXAdd( float32ToFloatX( a ), float32ToFloatX( b ) ) );
1446
1447}
1448
1449float32 slow_float32_mul( float32 a, float32 b )
1450{
1451
1452    return
1453        floatXToFloat32(
1454            floatXMul( float32ToFloatX( a ), float32ToFloatX( b ) ) );
1455
1456}
1457
1458float32 slow_float32_div( float32 a, float32 b )
1459{
1460
1461    return
1462        floatXToFloat32(
1463            floatXDiv( float32ToFloatX( a ), float32ToFloatX( b ) ) );
1464
1465}
1466
1467float32 slow_float32_rem( float32 a, float32 b )
1468{
1469
1470    return
1471        floatXToFloat32(
1472            floatXRem( float32ToFloatX( a ), float32ToFloatX( b ) ) );
1473
1474}
1475
1476float32 slow_float32_sqrt( float32 a )
1477{
1478
1479    return floatXToFloat32( floatXSqrt( float32ToFloatX( a ) ) );
1480
1481}
1482
1483flag slow_float32_eq( float32 a, float32 b )
1484{
1485
1486    return floatXEq( float32ToFloatX( a ), float32ToFloatX( b ) );
1487
1488}
1489
1490flag slow_float32_le( float32 a, float32 b )
1491{
1492    floatX ax, bx;
1493
1494    ax = float32ToFloatX( a );
1495    bx = float32ToFloatX( b );
1496    if ( ax.isNaN || bx.isNaN ) {
1497        slow_float_exception_flags |= float_flag_invalid;
1498    }
1499    return floatXLe( ax, bx );
1500
1501}
1502
1503flag slow_float32_lt( float32 a, float32 b )
1504{
1505    floatX ax, bx;
1506
1507    ax = float32ToFloatX( a );
1508    bx = float32ToFloatX( b );
1509    if ( ax.isNaN || bx.isNaN ) {
1510        slow_float_exception_flags |= float_flag_invalid;
1511    }
1512    return floatXLt( ax, bx );
1513
1514}
1515
1516flag slow_float32_eq_signaling( float32 a, float32 b )
1517{
1518    floatX ax, bx;
1519
1520    ax = float32ToFloatX( a );
1521    bx = float32ToFloatX( b );
1522    if ( ax.isNaN || bx.isNaN ) {
1523        slow_float_exception_flags |= float_flag_invalid;
1524    }
1525    return floatXEq( ax, bx );
1526
1527}
1528
1529flag slow_float32_le_quiet( float32 a, float32 b )
1530{
1531
1532    return floatXLe( float32ToFloatX( a ), float32ToFloatX( b ) );
1533
1534}
1535
1536flag slow_float32_lt_quiet( float32 a, float32 b )
1537{
1538
1539    return floatXLt( float32ToFloatX( a ), float32ToFloatX( b ) );
1540
1541}
1542
1543int32 slow_float64_to_int32( float64 a )
1544{
1545
1546    return floatXToInt32( float64ToFloatX( a ) );
1547
1548}
1549
1550int32 slow_float64_to_int32_round_to_zero( float64 a )
1551{
1552    int8 savedRoundingMode;
1553    int32 z;
1554
1555    savedRoundingMode = slow_float_rounding_mode;
1556    slow_float_rounding_mode = float_round_to_zero;
1557    z = floatXToInt32( float64ToFloatX( a ) );
1558    slow_float_rounding_mode = savedRoundingMode;
1559    return z;
1560
1561}
1562
1563int64 slow_float64_to_int64( float64 a )
1564{
1565
1566    return floatXToInt64( float64ToFloatX( a ) );
1567
1568}
1569
1570int64 slow_float64_to_int64_round_to_zero( float64 a )
1571{
1572    int8 savedRoundingMode;
1573    int64 z;
1574
1575    savedRoundingMode = slow_float_rounding_mode;
1576    slow_float_rounding_mode = float_round_to_zero;
1577    z = floatXToInt64( float64ToFloatX( a ) );
1578    slow_float_rounding_mode = savedRoundingMode;
1579    return z;
1580
1581}
1582
1583float32 slow_float64_to_float32( float64 a )
1584{
1585
1586    return floatXToFloat32( float64ToFloatX( a ) );
1587
1588}
1589
1590#ifdef FLOATX80
1591
1592floatx80 slow_float64_to_floatx80( float64 a )
1593{
1594
1595    return floatXToFloatx80( float64ToFloatX( a ) );
1596
1597}
1598
1599#endif
1600
1601#ifdef FLOAT128
1602
1603float128 slow_float64_to_float128( float64 a )
1604{
1605
1606    return floatXToFloat128( float64ToFloatX( a ) );
1607
1608}
1609
1610#endif
1611
1612float64 slow_float64_round_to_int( float64 a )
1613{
1614
1615    return floatXToFloat64( floatXRoundToInt( float64ToFloatX( a ) ) );
1616
1617}
1618
1619float64 slow_float64_add( float64 a, float64 b )
1620{
1621
1622    return
1623        floatXToFloat64(
1624            floatXAdd( float64ToFloatX( a ), float64ToFloatX( b ) ) );
1625
1626}
1627
1628float64 slow_float64_sub( float64 a, float64 b )
1629{
1630
1631    b ^= LIT64( 0x8000000000000000 );
1632    return
1633        floatXToFloat64(
1634            floatXAdd( float64ToFloatX( a ), float64ToFloatX( b ) ) );
1635
1636}
1637
1638float64 slow_float64_mul( float64 a, float64 b )
1639{
1640
1641    return
1642        floatXToFloat64(
1643            floatXMul( float64ToFloatX( a ), float64ToFloatX( b ) ) );
1644
1645}
1646
1647float64 slow_float64_div( float64 a, float64 b )
1648{
1649
1650    return
1651        floatXToFloat64(
1652            floatXDiv( float64ToFloatX( a ), float64ToFloatX( b ) ) );
1653
1654}
1655
1656float64 slow_float64_rem( float64 a, float64 b )
1657{
1658
1659    return
1660        floatXToFloat64(
1661            floatXRem( float64ToFloatX( a ), float64ToFloatX( b ) ) );
1662
1663}
1664
1665float64 slow_float64_sqrt( float64 a )
1666{
1667
1668    return floatXToFloat64( floatXSqrt( float64ToFloatX( a ) ) );
1669
1670}
1671
1672flag slow_float64_eq( float64 a, float64 b )
1673{
1674
1675    return floatXEq( float64ToFloatX( a ), float64ToFloatX( b ) );
1676
1677}
1678
1679flag slow_float64_le( float64 a, float64 b )
1680{
1681    floatX ax, bx;
1682
1683    ax = float64ToFloatX( a );
1684    bx = float64ToFloatX( b );
1685    if ( ax.isNaN || bx.isNaN ) {
1686        slow_float_exception_flags |= float_flag_invalid;
1687    }
1688    return floatXLe( ax, bx );
1689
1690}
1691
1692flag slow_float64_lt( float64 a, float64 b )
1693{
1694    floatX ax, bx;
1695
1696    ax = float64ToFloatX( a );
1697    bx = float64ToFloatX( b );
1698    if ( ax.isNaN || bx.isNaN ) {
1699        slow_float_exception_flags |= float_flag_invalid;
1700    }
1701    return floatXLt( ax, bx );
1702
1703}
1704
1705flag slow_float64_eq_signaling( float64 a, float64 b )
1706{
1707    floatX ax, bx;
1708
1709    ax = float64ToFloatX( a );
1710    bx = float64ToFloatX( b );
1711    if ( ax.isNaN || bx.isNaN ) {
1712        slow_float_exception_flags |= float_flag_invalid;
1713    }
1714    return floatXEq( ax, bx );
1715
1716}
1717
1718flag slow_float64_le_quiet( float64 a, float64 b )
1719{
1720
1721    return floatXLe( float64ToFloatX( a ), float64ToFloatX( b ) );
1722
1723}
1724
1725flag slow_float64_lt_quiet( float64 a, float64 b )
1726{
1727
1728    return floatXLt( float64ToFloatX( a ), float64ToFloatX( b ) );
1729
1730}
1731
1732#ifdef FLOATX80
1733
1734int32 slow_floatx80_to_int32( floatx80 a )
1735{
1736
1737    return floatXToInt32( floatx80ToFloatX( a ) );
1738
1739}
1740
1741int32 slow_floatx80_to_int32_round_to_zero( floatx80 a )
1742{
1743    int8 savedRoundingMode;
1744    int32 z;
1745
1746    savedRoundingMode = slow_float_rounding_mode;
1747    slow_float_rounding_mode = float_round_to_zero;
1748    z = floatXToInt32( floatx80ToFloatX( a ) );
1749    slow_float_rounding_mode = savedRoundingMode;
1750    return z;
1751
1752}
1753
1754int64 slow_floatx80_to_int64( floatx80 a )
1755{
1756
1757    return floatXToInt64( floatx80ToFloatX( a ) );
1758
1759}
1760
1761int64 slow_floatx80_to_int64_round_to_zero( floatx80 a )
1762{
1763    int8 savedRoundingMode;
1764    int64 z;
1765
1766    savedRoundingMode = slow_float_rounding_mode;
1767    slow_float_rounding_mode = float_round_to_zero;
1768    z = floatXToInt64( floatx80ToFloatX( a ) );
1769    slow_float_rounding_mode = savedRoundingMode;
1770    return z;
1771
1772}
1773
1774float32 slow_floatx80_to_float32( floatx80 a )
1775{
1776
1777    return floatXToFloat32( floatx80ToFloatX( a ) );
1778
1779}
1780
1781float64 slow_floatx80_to_float64( floatx80 a )
1782{
1783
1784    return floatXToFloat64( floatx80ToFloatX( a ) );
1785
1786}
1787
1788#ifdef FLOAT128
1789
1790float128 slow_floatx80_to_float128( floatx80 a )
1791{
1792
1793    return floatXToFloat128( floatx80ToFloatX( a ) );
1794
1795}
1796
1797#endif
1798
1799floatx80 slow_floatx80_round_to_int( floatx80 a )
1800{
1801
1802    return floatXToFloatx80( floatXRoundToInt( floatx80ToFloatX( a ) ) );
1803
1804}
1805
1806floatx80 slow_floatx80_add( floatx80 a, floatx80 b )
1807{
1808
1809    return
1810        floatXToFloatx80(
1811            floatXAdd( floatx80ToFloatX( a ), floatx80ToFloatX( b ) ) );
1812
1813}
1814
1815floatx80 slow_floatx80_sub( floatx80 a, floatx80 b )
1816{
1817
1818    b.high ^= 0x8000;
1819    return
1820        floatXToFloatx80(
1821            floatXAdd( floatx80ToFloatX( a ), floatx80ToFloatX( b ) ) );
1822
1823}
1824
1825floatx80 slow_floatx80_mul( floatx80 a, floatx80 b )
1826{
1827
1828    return
1829        floatXToFloatx80(
1830            floatXMul( floatx80ToFloatX( a ), floatx80ToFloatX( b ) ) );
1831
1832}
1833
1834floatx80 slow_floatx80_div( floatx80 a, floatx80 b )
1835{
1836
1837    return
1838        floatXToFloatx80(
1839            floatXDiv( floatx80ToFloatX( a ), floatx80ToFloatX( b ) ) );
1840
1841}
1842
1843floatx80 slow_floatx80_rem( floatx80 a, floatx80 b )
1844{
1845
1846    return
1847        floatXToFloatx80(
1848            floatXRem( floatx80ToFloatX( a ), floatx80ToFloatX( b ) ) );
1849
1850}
1851
1852floatx80 slow_floatx80_sqrt( floatx80 a )
1853{
1854
1855    return floatXToFloatx80( floatXSqrt( floatx80ToFloatX( a ) ) );
1856
1857}
1858
1859flag slow_floatx80_eq( floatx80 a, floatx80 b )
1860{
1861
1862    return floatXEq( floatx80ToFloatX( a ), floatx80ToFloatX( b ) );
1863
1864}
1865
1866flag slow_floatx80_le( floatx80 a, floatx80 b )
1867{
1868    floatX ax, bx;
1869
1870    ax = floatx80ToFloatX( a );
1871    bx = floatx80ToFloatX( b );
1872    if ( ax.isNaN || bx.isNaN ) {
1873        slow_float_exception_flags |= float_flag_invalid;
1874    }
1875    return floatXLe( ax, bx );
1876
1877}
1878
1879flag slow_floatx80_lt( floatx80 a, floatx80 b )
1880{
1881    floatX ax, bx;
1882
1883    ax = floatx80ToFloatX( a );
1884    bx = floatx80ToFloatX( b );
1885    if ( ax.isNaN || bx.isNaN ) {
1886        slow_float_exception_flags |= float_flag_invalid;
1887    }
1888    return floatXLt( ax, bx );
1889
1890}
1891
1892flag slow_floatx80_eq_signaling( floatx80 a, floatx80 b )
1893{
1894    floatX ax, bx;
1895
1896    ax = floatx80ToFloatX( a );
1897    bx = floatx80ToFloatX( b );
1898    if ( ax.isNaN || bx.isNaN ) {
1899        slow_float_exception_flags |= float_flag_invalid;
1900    }
1901    return floatXEq( ax, bx );
1902
1903}
1904
1905flag slow_floatx80_le_quiet( floatx80 a, floatx80 b )
1906{
1907
1908    return floatXLe( floatx80ToFloatX( a ), floatx80ToFloatX( b ) );
1909
1910}
1911
1912flag slow_floatx80_lt_quiet( floatx80 a, floatx80 b )
1913{
1914
1915    return floatXLt( floatx80ToFloatX( a ), floatx80ToFloatX( b ) );
1916
1917}
1918
1919#endif
1920
1921#ifdef FLOAT128
1922
1923int32 slow_float128_to_int32( float128 a )
1924{
1925
1926    return floatXToInt32( float128ToFloatX( a ) );
1927
1928}
1929
1930int32 slow_float128_to_int32_round_to_zero( float128 a )
1931{
1932    int8 savedRoundingMode;
1933    int32 z;
1934
1935    savedRoundingMode = slow_float_rounding_mode;
1936    slow_float_rounding_mode = float_round_to_zero;
1937    z = floatXToInt32( float128ToFloatX( a ) );
1938    slow_float_rounding_mode = savedRoundingMode;
1939    return z;
1940
1941}
1942
1943int64 slow_float128_to_int64( float128 a )
1944{
1945
1946    return floatXToInt64( float128ToFloatX( a ) );
1947
1948}
1949
1950int64 slow_float128_to_int64_round_to_zero( float128 a )
1951{
1952    int8 savedRoundingMode;
1953    int64 z;
1954
1955    savedRoundingMode = slow_float_rounding_mode;
1956    slow_float_rounding_mode = float_round_to_zero;
1957    z = floatXToInt64( float128ToFloatX( a ) );
1958    slow_float_rounding_mode = savedRoundingMode;
1959    return z;
1960
1961}
1962
1963float32 slow_float128_to_float32( float128 a )
1964{
1965
1966    return floatXToFloat32( float128ToFloatX( a ) );
1967
1968}
1969
1970float64 slow_float128_to_float64( float128 a )
1971{
1972
1973    return floatXToFloat64( float128ToFloatX( a ) );
1974
1975}
1976
1977#ifdef FLOATX80
1978
1979floatx80 slow_float128_to_floatx80( float128 a )
1980{
1981
1982    return floatXToFloatx80( float128ToFloatX( a ) );
1983
1984}
1985
1986#endif
1987
1988float128 slow_float128_round_to_int( float128 a )
1989{
1990
1991    return floatXToFloat128( floatXRoundToInt( float128ToFloatX( a ) ) );
1992
1993}
1994
1995float128 slow_float128_add( float128 a, float128 b )
1996{
1997
1998    return
1999        floatXToFloat128(
2000            floatXAdd( float128ToFloatX( a ), float128ToFloatX( b ) ) );
2001
2002}
2003
2004float128 slow_float128_sub( float128 a, float128 b )
2005{
2006
2007    b.high ^= LIT64( 0x8000000000000000 );
2008    return
2009        floatXToFloat128(
2010            floatXAdd( float128ToFloatX( a ), float128ToFloatX( b ) ) );
2011
2012}
2013
2014float128 slow_float128_mul( float128 a, float128 b )
2015{
2016
2017    return
2018        floatXToFloat128(
2019            floatXMul( float128ToFloatX( a ), float128ToFloatX( b ) ) );
2020
2021}
2022
2023float128 slow_float128_div( float128 a, float128 b )
2024{
2025
2026    return
2027        floatXToFloat128(
2028            floatXDiv( float128ToFloatX( a ), float128ToFloatX( b ) ) );
2029
2030}
2031
2032float128 slow_float128_rem( float128 a, float128 b )
2033{
2034
2035    return
2036        floatXToFloat128(
2037            floatXRem( float128ToFloatX( a ), float128ToFloatX( b ) ) );
2038
2039}
2040
2041float128 slow_float128_sqrt( float128 a )
2042{
2043
2044    return floatXToFloat128( floatXSqrt( float128ToFloatX( a ) ) );
2045
2046}
2047
2048flag slow_float128_eq( float128 a, float128 b )
2049{
2050
2051    return floatXEq( float128ToFloatX( a ), float128ToFloatX( b ) );
2052
2053}
2054
2055flag slow_float128_le( float128 a, float128 b )
2056{
2057    floatX ax, bx;
2058
2059    ax = float128ToFloatX( a );
2060    bx = float128ToFloatX( b );
2061    if ( ax.isNaN || bx.isNaN ) {
2062        slow_float_exception_flags |= float_flag_invalid;
2063    }
2064    return floatXLe( ax, bx );
2065
2066}
2067
2068flag slow_float128_lt( float128 a, float128 b )
2069{
2070    floatX ax, bx;
2071
2072    ax = float128ToFloatX( a );
2073    bx = float128ToFloatX( b );
2074    if ( ax.isNaN || bx.isNaN ) {
2075        slow_float_exception_flags |= float_flag_invalid;
2076    }
2077    return floatXLt( ax, bx );
2078
2079}
2080
2081flag slow_float128_eq_signaling( float128 a, float128 b )
2082{
2083    floatX ax, bx;
2084
2085    ax = float128ToFloatX( a );
2086    bx = float128ToFloatX( b );
2087    if ( ax.isNaN || bx.isNaN ) {
2088        slow_float_exception_flags |= float_flag_invalid;
2089    }
2090    return floatXEq( ax, bx );
2091
2092}
2093
2094flag slow_float128_le_quiet( float128 a, float128 b )
2095{
2096
2097    return floatXLe( float128ToFloatX( a ), float128ToFloatX( b ) );
2098
2099}
2100
2101flag slow_float128_lt_quiet( float128 a, float128 b )
2102{
2103
2104    return floatXLt( float128ToFloatX( a ), float128ToFloatX( b ) );
2105
2106}
2107
2108#endif
2109
2110