(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[glibc.git] / sysdeps / ia64 / fpu / e_exp.S
blobdb02336ecf35e57643e500ff048d80c6a54b08e1
1 .file "exp.s"
3 // Copyright (C) 2000, 2001, Intel Corporation
4 // All rights reserved.
5 // 
6 // Contributed 2/2/2000 by John Harrison, Ted Kubaska, Bob Norin, Shane Story,
7 // and Ping Tak Peter Tang of the Computational Software Lab, Intel Corporation.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are
11 // met:
13 // * Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
16 // * Redistributions in binary form must reproduce the above copyright
17 // notice, this list of conditions and the following disclaimer in the
18 // documentation and/or other materials provided with the distribution.
20 // * The name of Intel Corporation may not be used to endorse or promote
21 // products derived from this software without specific prior written
22 // permission.
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
25 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
26 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS 
28 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
30 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
31 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
32 // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING
33 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
34 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
35 // 
36 // Intel Corporation is the author of this code, and requests that all
37 // problem reports or change requests be submitted to it directly at 
38 // http://developer.intel.com/opensource.
40 // History
41 //==============================================================
42 // 2/02/00  Initial version 
43 // 3/07/00  exp(inf)  = inf but now does NOT call error support
44 //          exp(-inf) = 0   but now does NOT call error support
45 // 4/04/00  Unwind support added
46 // 8/15/00  Bundle added after call to __libm_error_support to properly
47 //          set [the previously overwritten] GR_Parameter_RESULT.
48 // 11/30/00 Reworked to shorten main path, widen main path to include all
49 //          args in normal range, and add quick exit for 0, nan, inf.
50 // 12/05/00 Loaded constants earlier with setf to save 2 cycles.
52 // API
53 //==============================================================
54 // double exp(double)
56 // Overview of operation
57 //==============================================================
58 // Take the input x. w is "how many log2/128 in x?"
59 //  w = x * 128/log2
60 //  n = int(w)
61 //  x = n log2/128 + r + delta
63 //  n = 128M + index_1 + 2^4 index_2
64 //  x = M log2 + (log2/128) index_1 + (log2/8) index_2 + r + delta
66 //  exp(x) = 2^M  2^(index_1/128)  2^(index_2/8) exp(r) exp(delta)
67 //       Construct 2^M
68 //       Get 2^(index_1/128) from table_1;
69 //       Get 2^(index_2/8)   from table_2;
70 //       Calculate exp(r) by series
71 //          r = x - n (log2/128)_high
72 //          delta = - n (log2/128)_low
73 //       Calculate exp(delta) as 1 + delta
76 // Special values 
77 //==============================================================
78 // exp(+0)    = 1.0
79 // exp(-0)    = 1.0
81 // exp(+qnan) = +qnan 
82 // exp(-qnan) = -qnan 
83 // exp(+snan) = +qnan 
84 // exp(-snan) = -qnan 
86 // exp(-inf)  = +0 
87 // exp(+inf)  = +inf
89 // Overfow and Underfow
90 //=======================
91 // exp(-x) = smallest double normal when
92 //     x = -708.396 = c086232bdd7abcd2
94 // exp(x) = largest double normal when
95 //     x = 709.7827 = 40862e42fefa39ef
99 // Registers used
100 //==============================================================
101 // Floating Point registers used: 
102 // f8, input
103 // f9 -> f15,  f32 -> f60
105 // General registers used: 
106 // r32 -> r60 
108 // Predicate registers used:
109 // p6 -> p15
111 #include "libm_support.h"
113 // Assembly macros
114 //==============================================================
116 exp_GR_rshf                   = r33
117 EXP_AD_TB1                    = r34
118 EXP_AD_TB2                    = r35
119 EXP_AD_P                      = r36
121 exp_GR_N                      = r37
122 exp_GR_index_1                = r38
123 exp_GR_index_2_16             = r39
125 exp_GR_biased_M               = r40
126 exp_GR_index_1_16             = r41
127 EXP_AD_T1                     = r42
128 EXP_AD_T2                     = r43
129 exp_GR_sig_inv_ln2            = r44
131 exp_GR_17ones                 = r45
132 exp_GR_one                    = r46
133 exp_TB1_size                  = r47
134 exp_TB2_size                  = r48
135 exp_GR_rshf_2to56             = r49
137 exp_GR_gt_ln                  = r50
138 exp_GR_exp_2tom56             = r51
140 exp_GR_17ones_m1              = r52
142 GR_SAVE_B0                    = r53
143 GR_SAVE_PFS                   = r54
144 GR_SAVE_GP                    = r55
145 GR_SAVE_SP                    = r56
147 GR_Parameter_X                = r57
148 GR_Parameter_Y                = r58
149 GR_Parameter_RESULT           = r59
150 GR_Parameter_TAG              = r60
153 FR_X             = f10
154 FR_Y             = f1
155 FR_RESULT        = f8
157 EXP_RSHF_2TO56   = f6
158 EXP_INV_LN2_2TO63 = f7
159 EXP_W_2TO56_RSH  = f9
160 EXP_2TOM56       = f11
161 exp_P4           = f12 
162 exp_P3           = f13 
163 exp_P2           = f14 
164 exp_P1           = f15 
166 exp_ln2_by_128_hi  = f33 
167 exp_ln2_by_128_lo  = f34 
169 EXP_RSHF           = f35
170 EXP_Nfloat         = f36 
171 exp_W              = f37
172 exp_r              = f38
173 exp_f              = f39
175 exp_rsq            = f40
176 exp_rcube          = f41
178 EXP_2M             = f42
179 exp_S1             = f43
180 exp_T1             = f44
182 EXP_MIN_DBL_OFLOW_ARG = f45
183 EXP_MAX_DBL_ZERO_ARG  = f46
184 EXP_MAX_DBL_NORM_ARG  = f47
185 EXP_MAX_DBL_UFLOW_ARG = f48
186 EXP_MIN_DBL_NORM_ARG  = f49
187 exp_rP4pP3         = f50
188 exp_P_lo           = f51
189 exp_P_hi           = f52
190 exp_P              = f53
191 exp_S              = f54
193 EXP_NORM_f8        = f56   
195 exp_wre_urm_f8     = f57
196 exp_ftz_urm_f8     = f57
198 exp_gt_pln         = f58
200 exp_S2             = f59
201 exp_T2             = f60
204 // Data tables
205 //==============================================================
207 #ifdef _LIBC
208 .rodata
209 #else
210 .data
211 #endif
213 .align 16
215 // ************* DO NOT CHANGE ORDER OF THESE TABLES ********************
217 // double-extended 1/ln(2)
218 // 3fff b8aa 3b29 5c17 f0bb be87fed0691d3e88
219 // 3fff b8aa 3b29 5c17 f0bc 
220 // For speed the significand will be loaded directly with a movl and setf.sig
221 //   and the exponent will be bias+63 instead of bias+0.  Thus subsequent
222 //   computations need to scale appropriately.
223 // The constant 128/ln(2) is needed for the computation of w.  This is also 
224 //   obtained by scaling the computations.
226 // Two shifting constants are loaded directly with movl and setf.d. 
227 //   1. EXP_RSHF_2TO56 = 1.1000..00 * 2^(63-7) 
228 //        This constant is added to x*1/ln2 to shift the integer part of
229 //        x*128/ln2 into the rightmost bits of the significand.
230 //        The result of this fma is EXP_W_2TO56_RSH.
231 //   2. EXP_RSHF       = 1.1000..00 * 2^(63) 
232 //        This constant is subtracted from EXP_W_2TO56_RSH * 2^(-56) to give
233 //        the integer part of w, n, as a floating-point number.
234 //        The result of this fms is EXP_Nfloat.
237 exp_table_1:
238 ASM_TYPE_DIRECTIVE(exp_table_1,@object)
239 data8 0x40862e42fefa39f0 // smallest dbl overflow arg
240 data8 0xc0874c0000000000 // approx largest arg for zero result
241 data8 0x40862e42fefa39ef // largest dbl arg to give normal dbl result
242 data8 0xc086232bdd7abcd3 // largest dbl underflow arg
243 data8 0xc086232bdd7abcd2 // smallest dbl arg to give normal dbl result
244 data8 0x0                // pad
245 data8 0xb17217f7d1cf79ab , 0x00003ff7 // ln2/128 hi
246 data8 0xc9e3b39803f2f6af , 0x00003fb7 // ln2/128 lo
248 // Table 1 is 2^(index_1/128) where
249 // index_1 goes from 0 to 15
251 data8 0x8000000000000000 , 0x00003FFF
252 data8 0x80B1ED4FD999AB6C , 0x00003FFF
253 data8 0x8164D1F3BC030773 , 0x00003FFF
254 data8 0x8218AF4373FC25EC , 0x00003FFF
255 data8 0x82CD8698AC2BA1D7 , 0x00003FFF
256 data8 0x8383594EEFB6EE37 , 0x00003FFF
257 data8 0x843A28C3ACDE4046 , 0x00003FFF
258 data8 0x84F1F656379C1A29 , 0x00003FFF
259 data8 0x85AAC367CC487B15 , 0x00003FFF
260 data8 0x8664915B923FBA04 , 0x00003FFF
261 data8 0x871F61969E8D1010 , 0x00003FFF
262 data8 0x87DB357FF698D792 , 0x00003FFF
263 data8 0x88980E8092DA8527 , 0x00003FFF
264 data8 0x8955EE03618E5FDD , 0x00003FFF
265 data8 0x8A14D575496EFD9A , 0x00003FFF
266 data8 0x8AD4C6452C728924 , 0x00003FFF
267 ASM_SIZE_DIRECTIVE(exp_table_1)
269 // Table 2 is 2^(index_1/8) where
270 // index_2 goes from 0 to 7
271 exp_table_2:
272 ASM_TYPE_DIRECTIVE(exp_table_2,@object)
273 data8 0x8000000000000000 , 0x00003FFF
274 data8 0x8B95C1E3EA8BD6E7 , 0x00003FFF
275 data8 0x9837F0518DB8A96F , 0x00003FFF
276 data8 0xA5FED6A9B15138EA , 0x00003FFF
277 data8 0xB504F333F9DE6484 , 0x00003FFF
278 data8 0xC5672A115506DADD , 0x00003FFF
279 data8 0xD744FCCAD69D6AF4 , 0x00003FFF
280 data8 0xEAC0C6E7DD24392F , 0x00003FFF
281 ASM_SIZE_DIRECTIVE (exp_table_2)
284 exp_p_table:
285 ASM_TYPE_DIRECTIVE(exp_p_table,@object)
286 data8 0x3f8111116da21757 //P_4
287 data8 0x3fa55555d787761c //P_3
288 data8 0x3fc5555555555414 //P_2
289 data8 0x3fdffffffffffd6a //P_1
290 ASM_SIZE_DIRECTIVE(exp_p_table)
293 .align 32
294 .global exp#
296 .section .text
297 .proc  exp#
298 .align 32
299 exp: 
300 #ifdef _LIBC
301 .global __ieee754_exp#
302 __ieee754_exp:
303 #endif
305 { .mlx
306       alloc      r32=ar.pfs,1,24,4,0                               
307       movl exp_GR_sig_inv_ln2 = 0xb8aa3b295c17f0bc  // significand of 1/ln2
309 { .mlx
310       addl       EXP_AD_TB1    = @ltoff(exp_table_1), gp
311       movl exp_GR_rshf_2to56 = 0x4768000000000000 ;;  // 1.10000 2^(63+56)
315 // We do this fnorm right at the beginning to take any enabled
316 // faults and to normalize any input unnormals so that SWA is not taken.
317 { .mfi
318       ld8        EXP_AD_TB1    = [EXP_AD_TB1]
319       fclass.m   p8,p0 = f8,0x07  // Test for x=0
320       mov        exp_GR_17ones = 0x1FFFF                          
322 { .mfi
323       mov        exp_TB1_size  = 0x100
324       fnorm      EXP_NORM_f8   = f8                                          
325       mov exp_GR_exp_2tom56 = 0xffff-56
329 // Form two constants we need
330 //  1/ln2 * 2^63  to compute  w = x * 1/ln2 * 128 
331 //  1.1000..000 * 2^(63+63-7) to right shift int(w) into the significand
333 { .mmf
334       setf.sig  EXP_INV_LN2_2TO63 = exp_GR_sig_inv_ln2 // form 1/ln2 * 2^63
335       setf.d  EXP_RSHF_2TO56 = exp_GR_rshf_2to56 // Form const 1.100 * 2^(63+56)
336       fclass.m   p9,p0 = f8,0x22  // Test for x=-inf
340 { .mlx
341       setf.exp EXP_2TOM56 = exp_GR_exp_2tom56 // form 2^-56 for scaling Nfloat
342       movl exp_GR_rshf = 0x43e8000000000000   // 1.10000 2^63 for right shift
344 { .mfb
345       mov        exp_TB2_size  = 0x80
346 (p8)  fma.d      f8 = f1,f1,f0           // quick exit for x=0
347 (p8)  br.ret.spnt b0
351 { .mfi
352       ldfpd      EXP_MIN_DBL_OFLOW_ARG, EXP_MAX_DBL_ZERO_ARG = [EXP_AD_TB1],16
353       fclass.m   p10,p0 = f8,0x21  // Test for x=+inf
354       nop.i 999
356 { .mfb
357       nop.m 999
358 (p9)  fma.d      f8 = f0,f0,f0           // quick exit for x=-inf
359 (p9)  br.ret.spnt b0
360 ;;                    
363 { .mmf
364       ldfpd      EXP_MAX_DBL_NORM_ARG, EXP_MAX_DBL_UFLOW_ARG = [EXP_AD_TB1],16
365       setf.d  EXP_RSHF = exp_GR_rshf // Form right shift const 1.100 * 2^63
366       fclass.m   p11,p0 = f8,0xc3  // Test for x=nan
370 { .mfb
371       ldfd      EXP_MIN_DBL_NORM_ARG = [EXP_AD_TB1],16
372       nop.f 999
373 (p10) br.ret.spnt b0               // quick exit for x=+inf
377 { .mfi
378       ldfe       exp_ln2_by_128_hi  = [EXP_AD_TB1],16
379       nop.f 999
380       nop.i 999
385 { .mfb
386       ldfe       exp_ln2_by_128_lo  = [EXP_AD_TB1],16
387 (p11) fmerge.s   f8 = EXP_NORM_f8, EXP_NORM_f8
388 (p11) br.ret.spnt b0               // quick exit for x=nan
392 // After that last load, EXP_AD_TB1 points to the beginning of table 1
394 // W = X * Inv_log2_by_128
395 // By adding 1.10...0*2^63 we shift and get round_int(W) in significand.
396 // We actually add 1.10...0*2^56 to X * Inv_log2 to do the same thing.
398 { .mfi
399       nop.m 999
400       fma.s1  EXP_W_2TO56_RSH  = EXP_NORM_f8, EXP_INV_LN2_2TO63, EXP_RSHF_2TO56
401       nop.i 999
406 // Divide arguments into the following categories:
407 //  Certain Underflow/zero  p11 - -inf < x <= MAX_DBL_ZERO_ARG 
408 //  Certain Underflow       p12 - MAX_DBL_ZERO_ARG < x <= MAX_DBL_UFLOW_ARG 
409 //  Possible Underflow      p13 - MAX_DBL_UFLOW_ARG < x < MIN_DBL_NORM_ARG
410 //  Certain Safe                - MIN_DBL_NORM_ARG <= x <= MAX_DBL_NORM_ARG
411 //  Possible Overflow       p14 - MAX_DBL_NORM_ARG < x < MIN_DBL_OFLOW_ARG
412 //  Certain Overflow        p15 - MIN_DBL_OFLOW_ARG <= x < +inf
414 // If the input is really a double arg, then there will never be "Possible
415 // Underflow" or "Possible Overflow" arguments.
418 { .mfi
419       add        EXP_AD_TB2 = exp_TB1_size, EXP_AD_TB1
420       fcmp.ge.s1  p15,p14 = EXP_NORM_f8,EXP_MIN_DBL_OFLOW_ARG
421       nop.i 999
422 ;;                        
425 { .mfi
426       add        EXP_AD_P = exp_TB2_size, EXP_AD_TB2
427       fcmp.le.s1  p11,p12 = EXP_NORM_f8,EXP_MAX_DBL_ZERO_ARG
428       nop.i 999
432 { .mfb
433       ldfpd      exp_P4, exp_P3  = [EXP_AD_P] ,16
434 (p14) fcmp.gt.unc.s1  p14,p0 = EXP_NORM_f8,EXP_MAX_DBL_NORM_ARG
435 (p15) br.cond.spnt L(EXP_CERTAIN_OVERFLOW)
440 // Nfloat = round_int(W) 
441 // The signficand of EXP_W_2TO56_RSH contains the rounded integer part of W,
442 // as a twos complement number in the lower bits (that is, it may be negative).
443 // That twos complement number (called N) is put into exp_GR_N.
445 // Since EXP_W_2TO56_RSH is scaled by 2^56, it must be multiplied by 2^-56
446 // before the shift constant 1.10000 * 2^63 is subtracted to yield EXP_Nfloat.
447 // Thus, EXP_Nfloat contains the floating point version of N
450 { .mfi
451       nop.m 999
452 (p12) fcmp.le.unc  p12,p0 = EXP_NORM_f8,EXP_MAX_DBL_UFLOW_ARG
453       nop.i 999
455 { .mfb
456       ldfpd      exp_P2, exp_P1  = [EXP_AD_P]                                  
457       fms.s1          EXP_Nfloat = EXP_W_2TO56_RSH, EXP_2TOM56, EXP_RSHF 
458 (p11) br.cond.spnt L(EXP_CERTAIN_UNDERFLOW_ZERO)
462 { .mfi
463       getf.sig        exp_GR_N        = EXP_W_2TO56_RSH
464 (p13) fcmp.lt.unc  p13,p0 = EXP_NORM_f8,EXP_MIN_DBL_NORM_ARG
465       nop.i 999
470 // exp_GR_index_1 has index_1
471 // exp_GR_index_2_16 has index_2 * 16
472 // exp_GR_biased_M has M
473 // exp_GR_index_1_16 has index_1 * 16
475 // r2 has true M
476 { .mfi
477       and            exp_GR_index_1 = 0x0f, exp_GR_N
478       fnma.s1    exp_r   = EXP_Nfloat, exp_ln2_by_128_hi, EXP_NORM_f8 
479       shr            r2 = exp_GR_N,  0x7
481 { .mfi
482       and            exp_GR_index_2_16 = 0x70, exp_GR_N
483       fnma.s1    exp_f   = EXP_Nfloat, exp_ln2_by_128_lo, f1 
484       nop.i 999
485 ;;                            
489 // EXP_AD_T1 has address of T1                           
490 // EXP_AD_T2 has address if T2                            
492 { .mmi
493       addl           exp_GR_biased_M = 0xffff, r2 
494       add            EXP_AD_T2 = EXP_AD_TB2, exp_GR_index_2_16 
495       shladd         EXP_AD_T1 = exp_GR_index_1, 4, EXP_AD_TB1
496 ;;                            
500 // Create Scale = 2^M
501 // r = x - Nfloat * ln2_by_128_hi 
502 // f = 1 - Nfloat * ln2_by_128_lo 
504 { .mmi
505       setf.exp        EXP_2M = exp_GR_biased_M                              
506       ldfe       exp_T2  = [EXP_AD_T2]                                
507       nop.i 999
511 // Load T1 and T2
512 { .mfi
513       ldfe       exp_T1  = [EXP_AD_T1]                                
514       nop.f 999
515       nop.i 999
520 { .mfi
521         nop.m 999
522         fma.s1           exp_rsq = exp_r, exp_r, f0 
523         nop.i 999
525 { .mfi
526         nop.m 999
527         fma.s1        exp_rP4pP3 = exp_r, exp_P4, exp_P3               
528         nop.i 999
534 { .mfi
535         nop.m 999
536         fma.s1           exp_rcube = exp_r, exp_rsq, f0 
537         nop.i 999 
539 { .mfi
540         nop.m 999
541         fma.s1        exp_P_lo  = exp_r, exp_rP4pP3, exp_P2            
542         nop.i 999
547 { .mfi
548         nop.m 999
549         fma.s1        exp_P_hi  = exp_rsq, exp_P1, exp_r              
550         nop.i 999
552 { .mfi
553         nop.m 999
554         fma.s1        exp_S2  = exp_f,exp_T2,f0                       
555         nop.i 999
559 { .mfi
560         nop.m 999
561         fma.s1        exp_S1  = EXP_2M,exp_T1,f0                      
562         nop.i 999
567 { .mfi
568         nop.m 999
569         fma.s1        exp_P     = exp_rcube, exp_P_lo, exp_P_hi       
570         nop.i 999
574 { .mfi
575         nop.m 999
576         fma.s1        exp_S   = exp_S1,exp_S2,f0                      
577         nop.i 999
581 { .bbb
582 (p12)   br.cond.spnt  L(EXP_CERTAIN_UNDERFLOW)
583 (p13)   br.cond.spnt  L(EXP_POSSIBLE_UNDERFLOW)
584 (p14)   br.cond.spnt  L(EXP_POSSIBLE_OVERFLOW)
589 { .mfb
590         nop.m 999
591         fma.d      f8 = exp_S, exp_P, exp_S 
592         br.ret.sptk     b0 ;;               // Normal path exit 
596 L(EXP_POSSIBLE_OVERFLOW): 
598 // We got an answer. EXP_MAX_DBL_NORM_ARG < x < EXP_MIN_DBL_OFLOW_ARG
599 // overflow is a possibility, not a certainty
601 { .mfi
602         nop.m 999
603         fsetc.s2 0x7F,0x42                                          
604         nop.i 999 ;;
607 { .mfi
608         nop.m 999
609         fma.d.s2      exp_wre_urm_f8 = exp_S, exp_P, exp_S          
610         nop.i 999 ;;
613 // We define an overflow when the answer with
614 //    WRE set
615 //    user-defined rounding mode
616 // is ldn +1
618 // Is the exponent 1 more than the largest double?
619 // If so, go to ERROR RETURN, else get the answer and 
620 // leave.
622 // Largest double is 7FE (biased double)
623 //                   7FE - 3FF + FFFF = 103FE
624 // Create + largest_double_plus_ulp
625 // Create - largest_double_plus_ulp
626 // Calculate answer with WRE set.
628 // Cases when answer is ldn+1  are as follows:
629 //  ldn                   ldn+1
630 // --+----------|----------+------------
631 //              | 
632 //    +inf          +inf      -inf
633 //                  RN         RN
634 //                             RZ 
636 { .mfi
637         nop.m 999
638         fsetc.s2 0x7F,0x40                                          
639         mov           exp_GR_gt_ln  = 0x103ff ;;                      
642 { .mfi
643         setf.exp      exp_gt_pln    = exp_GR_gt_ln                 
644         nop.f 999
645         nop.i 999 ;;
648 { .mfi
649         nop.m 999
650        fcmp.ge.unc.s1 p6, p0 =  exp_wre_urm_f8, exp_gt_pln        
651         nop.i 999 ;;
654 { .mfb
655         nop.m 999
656         nop.f 999
657 (p6)   br.cond.spnt L(EXP_CERTAIN_OVERFLOW) ;; // Branch if really overflow
660 { .mfb
661         nop.m 999
662        fma.d        f8 = exp_S, exp_P, exp_S                      
663        br.ret.sptk     b0 ;;             // Exit if really no overflow
666 L(EXP_CERTAIN_OVERFLOW):
667 { .mmi
668       sub   exp_GR_17ones_m1 = exp_GR_17ones, r0, 1 ;;
669       setf.exp     f9 = exp_GR_17ones_m1
670       nop.i 999 ;;
673 { .mfi
674       nop.m 999
675       fmerge.s FR_X = f8,f8
676       nop.i 999
678 { .mfb
679       mov        GR_Parameter_TAG = 14
680       fma.d       FR_RESULT = f9, f9, f0    // Set I,O and +INF result
681       br.cond.sptk  __libm_error_region ;;                             
684 L(EXP_POSSIBLE_UNDERFLOW): 
686 // We got an answer. EXP_MAX_DBL_UFLOW_ARG < x < EXP_MIN_DBL_NORM_ARG
687 // underflow is a possibility, not a certainty
689 // We define an underflow when the answer with
690 //    ftz set
691 // is zero (tiny numbers become zero)
693 // Notice (from below) that if we have an unlimited exponent range,
694 // then there is an extra machine number E between the largest denormal and
695 // the smallest normal.
697 // So if with unbounded exponent we round to E or below, then we are
698 // tiny and underflow has occurred.
700 // But notice that you can be in a situation where we are tiny, namely
701 // rounded to E, but when the exponent is bounded we round to smallest
702 // normal. So the answer can be the smallest normal with underflow.
704 //                           E
705 // -----+--------------------+--------------------+-----
706 //      |                    |                    |
707 //   1.1...10 2^-3fff    1.1...11 2^-3fff    1.0...00 2^-3ffe
708 //   0.1...11 2^-3ffe                                   (biased, 1)
709 //    largest dn                               smallest normal
711 { .mfi
712         nop.m 999
713        fsetc.s2 0x7F,0x41                                          
714         nop.i 999 ;;
716 { .mfi
717         nop.m 999
718        fma.d.s2      exp_ftz_urm_f8 = exp_S, exp_P, exp_S          
719         nop.i 999 ;;
721 { .mfi
722         nop.m 999
723        fsetc.s2 0x7F,0x40                                          
724         nop.i 999 ;;
726 { .mfi
727         nop.m 999
728        fcmp.eq.unc.s1 p6, p0 =  exp_ftz_urm_f8, f0                
729         nop.i 999 ;;
731 { .mfb
732         nop.m 999
733         nop.f 999
734 (p6)   br.cond.spnt L(EXP_CERTAIN_UNDERFLOW) ;; // Branch if really underflow
736 { .mfb
737         nop.m 999
738        fma.d        f8 = exp_S, exp_P, exp_S                      
739        br.ret.sptk     b0 ;;                // Exit if really no underflow
742 L(EXP_CERTAIN_UNDERFLOW):
743 { .mfi
744       nop.m 999
745       fmerge.s FR_X = f8,f8
746       nop.i 999
748 { .mfb
749       mov        GR_Parameter_TAG = 15
750       fma.d       FR_RESULT  = exp_S, exp_P, exp_S // Set I,U and tiny result
751       br.cond.sptk  __libm_error_region ;;                             
754 L(EXP_CERTAIN_UNDERFLOW_ZERO):
755 { .mmi
756       mov   exp_GR_one = 1 ;;
757       setf.exp     f9 = exp_GR_one
758       nop.i 999 ;;
761 { .mfi
762       nop.m 999
763       fmerge.s FR_X = f8,f8
764       nop.i 999
766 { .mfb
767       mov        GR_Parameter_TAG = 15
768       fma.d       FR_RESULT = f9, f9, f0    // Set I,U and tiny (+0.0) result
769       br.cond.sptk  __libm_error_region ;;                             
772 .endp exp
773 ASM_SIZE_DIRECTIVE(exp)
776 .proc __libm_error_region
777 __libm_error_region:
778 .prologue
779 { .mfi
780         add   GR_Parameter_Y=-32,sp             // Parameter 2 value
781         nop.f 0
782 .save   ar.pfs,GR_SAVE_PFS
783         mov  GR_SAVE_PFS=ar.pfs                 // Save ar.pfs 
785 { .mfi
786 .fframe 64 
787         add sp=-64,sp                           // Create new stack
788         nop.f 0
789         mov GR_SAVE_GP=gp                       // Save gp
791 { .mmi
792         stfd [GR_Parameter_Y] = FR_Y,16         // STORE Parameter 2 on stack
793         add GR_Parameter_X = 16,sp              // Parameter 1 address
794 .save   b0, GR_SAVE_B0                      
795         mov GR_SAVE_B0=b0                       // Save b0 
797 .body
798 { .mib
799         stfd [GR_Parameter_X] = FR_X                  // STORE Parameter 1 on stack 
800         add   GR_Parameter_RESULT = 0,GR_Parameter_Y  // Parameter 3 address 
801         nop.b 0                                      
803 { .mib
804         stfd [GR_Parameter_Y] = FR_RESULT             // STORE Parameter 3 on stack
805         add   GR_Parameter_Y = -16,GR_Parameter_Y  
806         br.call.sptk b0=__libm_error_support#         // Call error handling function
808 { .mmi
809         nop.m 0
810         nop.m 0
811         add   GR_Parameter_RESULT = 48,sp
813 { .mmi
814         ldfd  f8 = [GR_Parameter_RESULT]       // Get return result off stack
815 .restore sp
816         add   sp = 64,sp                       // Restore stack pointer
817         mov   b0 = GR_SAVE_B0                  // Restore return address
819 { .mib
820         mov   gp = GR_SAVE_GP                  // Restore gp 
821         mov   ar.pfs = GR_SAVE_PFS             // Restore ar.pfs
822         br.ret.sptk     b0                     // Return
823 };; 
825 .endp __libm_error_region
826 ASM_SIZE_DIRECTIVE(__libm_error_region)
827 .type   __libm_error_support#,@function
828 .global __libm_error_support#