a68e82d2c149d97040a1fb2753767221fb52d36d
[jlayton/glibc.git] / sysdeps / ia64 / fpu / s_scalbnf.S
1 //.file "scalbnf.s"
2
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 // WARRANTY DISCLAIMER
10 // 
11 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
12 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
13 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
14 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS 
15 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
17 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
18 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
19 // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING
20 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
21 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
22 // 
23 // Intel Corporation is the author of this code, and requests that all
24 // problem reports or change requests be submitted to it directly at 
25 // http://developer.intel.com/opensource.
26 //
27 // History
28 //==============================================================
29 // 2/02/00  Initial version
30 // 1/26/01  scalbnf completely reworked and now standalone version 
31 //
32 // API
33 //==============================================================
34 // float = scalbnf  (float x, int n) 
35 // input  floating point f8 and int n (r33) 
36 // output floating point f8
37 //
38 // Returns x* 2**n using an fma and detects overflow
39 // and underflow.   
40 //
41 //
42
43 #include "libm_support.h"
44
45 FR_Big         = f6
46 FR_NBig        = f7
47 FR_Floating_X  = f8
48 FR_Result      = f8
49 FR_Result2     = f9
50 FR_Result3     = f11
51 FR_Norm_X      = f12
52 FR_Two_N       = f14
53 FR_Two_to_Big  = f15
54
55 GR_N_Biased    = r15
56 GR_Big         = r16
57 GR_NBig        = r17
58 GR_Scratch     = r18
59 GR_Scratch1    = r19
60 GR_Bias        = r20
61 GR_N_as_int    = r21
62
63 GR_SAVE_B0          = r32
64 GR_SAVE_GP          = r33
65 GR_SAVE_PFS         = r34
66 GR_Parameter_X      = r35
67 GR_Parameter_Y      = r36
68 GR_Parameter_RESULT = r37
69 GR_Tag              = r38
70
71 .align 32
72 .global scalbnf
73
74 .section .text
75 .proc  scalbnf
76 .align 32
77
78 scalbnf: 
79
80 //
81 //   Is x NAN, INF, ZERO, +-?
82 //   Build the exponent Bias
83 //
84 {    .mfi
85      alloc         r32=ar.pfs,1,2,4,0
86      fclass.m.unc  p7,p0 = FR_Floating_X, 0xe7 //@snan | @qnan | @inf | @zero
87      addl          GR_Bias = 0x0FFFF,r0
88 }
89
90 //
91 //   Sign extend input
92 //   Is N zero?
93 //   Normalize x
94 //
95 {    .mfi
96      cmp.eq.unc    p6,p0 = r33,r0  
97      fnorm.s1      FR_Norm_X  =   FR_Floating_X 
98      sxt4          GR_N_as_int = r33
99 }
100 ;;
101
102 //
103 //   Normalize x
104 //   Branch and return special values.
105 //   Create -35000
106 //   Create 35000
107 //
108 {    .mfi
109      addl          GR_Big = 35000,r0
110      nop.f         0
111      add           GR_N_Biased = GR_Bias,GR_N_as_int
112 }
113 {    .mfb
114      addl          GR_NBig = -35000,r0
115 (p7) fma.s.s0      FR_Result = FR_Floating_X,f1, f0 
116 (p7) br.ret.spnt   b0  
117 };;
118
119 //
120 //   Build the exponent Bias
121 //   Return x when N = 0
122 //
123 {    .mfi
124      setf.exp      FR_Two_N = GR_N_Biased                   
125      nop.f         0
126      addl          GR_Scratch1  = 0x063BF,r0 
127 }
128 {    .mfb
129      addl          GR_Scratch  = 0x019C3F,r0 
130 (p6) fma.s.s0      FR_Result = FR_Floating_X,f1, f0 
131 (p6) br.ret.spnt   b0  
132 };;
133
134 //
135 //   Create 2*big
136 //   Create 2**-big 
137 //   Is N > 35000     
138 //   Is N < -35000     
139 //   Raise Denormal operand flag with compare
140 //   Main path, create 2**N
141 //
142 {    .mfi
143      setf.exp      FR_NBig = GR_Scratch1                  
144      nop.f         0
145      cmp.ge.unc    p6, p0 = GR_N_as_int, GR_Big
146 }
147 {    .mfi
148      setf.exp      FR_Big = GR_Scratch                  
149      fcmp.ge.s0    p0,p11 = FR_Floating_X,f0
150      cmp.le.unc    p8, p0 = GR_N_as_int, GR_NBig
151 };;
152
153 //
154 //   Adjust 2**N if N was very small or very large
155 //
156 {    .mfi
157      nop.m 0
158 (p6) fma.s1        FR_Two_N = FR_Big,f1,f0
159      nop.i 0
160 }
161 { .mlx
162      nop.m 999
163 (p0) movl          GR_Scratch = 0x000000000003007F 
164 };;
165
166
167 {    .mfi
168      nop.m 0
169 (p8) fma.s1        FR_Two_N = FR_NBig,f1,f0
170      nop.i 0
171 }
172 {    .mlx
173      nop.m 999
174 (p0) movl          GR_Scratch1= 0x000000000001007F 
175 };;
176
177 //   Set up necessary status fields 
178 //
179 //   S0 user supplied status
180 //   S2 user supplied status + WRE + TD  (Overflows)
181 //   S3 user supplied status + FZ + TD   (Underflows)
182 //
183 {    .mfi
184      nop.m 999
185 (p0) fsetc.s3      0x7F,0x41
186      nop.i 999
187 }
188 {    .mfi
189      nop.m 999
190 (p0) fsetc.s2      0x7F,0x42
191      nop.i 999
192 };;
193
194 //
195 //   Do final operation
196 //
197 {    .mfi
198      setf.exp      FR_NBig = GR_Scratch
199      fma.s.s0      FR_Result = FR_Two_N,FR_Norm_X,f0 
200      nop.i         999
201 }
202 {    .mfi
203      nop.m         999
204      fma.s.s3      FR_Result3 = FR_Two_N,FR_Norm_X,f0 
205      nop.i         999
206 };;
207 {    .mfi
208      setf.exp      FR_Big = GR_Scratch1
209      fma.s.s2      FR_Result2 = FR_Two_N,FR_Norm_X,f0 
210      nop.i         999
211 };;
212
213 //   Check for overflow or underflow.
214 //   Restore s3
215 //   Restore s2
216 //
217 {    .mfi
218      nop.m 0
219      fsetc.s3      0x7F,0x40
220      nop.i 999 
221 }
222 {    .mfi
223      nop.m 0
224      fsetc.s2      0x7F,0x40
225      nop.i 999
226 };;
227
228 //
229 //   Is the result zero?
230 //
231 {    .mfi
232      nop.m 999
233      fclass.m.unc  p6, p0 =  FR_Result3, 0x007
234      nop.i 999 
235
236 {    .mfi
237      addl          GR_Tag = 178, r0
238      fcmp.ge.unc.s1 p7, p8 = FR_Result2 , FR_Big
239      nop.i 0
240 };;
241
242 //
243 //   Detect masked underflow - Tiny + Inexact Only
244 //
245 {    .mfi
246      nop.m 999
247 (p6) fcmp.neq.unc.s1 p6, p0 = FR_Result , FR_Result2
248      nop.i 999 
249 };; 
250
251 //
252 //   Is result bigger the allowed range?
253 //   Branch out for underflow
254 //
255 {    .mfb
256 (p6) addl           GR_Tag = 179, r0
257 (p8) fcmp.le.unc.s1 p9, p10 = FR_Result2 , FR_NBig
258 (p6) br.cond.spnt   L(scalbnf_UNDERFLOW) 
259 };;
260
261 //
262 //   Branch out for overflow
263 //
264 { .mbb
265      nop.m 0
266 (p7) br.cond.spnt   L(scalbnf_OVERFLOW) 
267 (p9) br.cond.spnt   L(scalbnf_OVERFLOW) 
268 };;
269
270 //
271 //   Return from main path.
272 //
273 {    .mfb
274      nop.m 999
275      nop.f 0
276      br.ret.sptk     b0;;                   
277 }
278
279 .endp scalbnf
280 ASM_SIZE_DIRECTIVE(scalbnf)
281 .proc __libm_error_region
282 __libm_error_region:
283
284 L(scalbnf_OVERFLOW): 
285 L(scalbnf_UNDERFLOW): 
286
287 //
288 // Get stack address of N
289 //
290 .prologue
291 { .mfi
292     add   GR_Parameter_Y=-32,sp         
293     nop.f 0
294 .save   ar.pfs,GR_SAVE_PFS
295     mov  GR_SAVE_PFS=ar.pfs              
296 }
297 //
298 // Adjust sp 
299 //
300 { .mfi
301 .fframe 64
302    add sp=-64,sp                         
303    nop.f 0
304    mov GR_SAVE_GP=gp       
305 };;
306
307 //
308 //  Store N on stack in correct position 
309 //  Locate the address of x on stack
310 //
311 { .mmi
312    st8 [GR_Parameter_Y] =  GR_N_as_int,16       
313    add GR_Parameter_X = 16,sp          
314 .save   b0, GR_SAVE_B0
315    mov GR_SAVE_B0=b0                  
316 };;
317
318 //
319 // Store x on the stack.
320 // Get address for result on stack.
321 //
322 .body
323 { .mib
324    stfs [GR_Parameter_X] = FR_Norm_X 
325    add   GR_Parameter_RESULT = 0,GR_Parameter_Y   
326    nop.b 0
327 }
328 { .mib
329    stfs [GR_Parameter_Y] = FR_Result                 
330    add   GR_Parameter_Y = -16,GR_Parameter_Y
331    br.call.sptk b0=__libm_error_support#   
332 };;
333
334 //
335 //  Get location of result on stack
336 //
337 { .mmi
338    nop.m 0
339    nop.m 0
340    add   GR_Parameter_RESULT = 48,sp    
341 };;
342
343 //
344 //  Get the new result 
345 //
346 { .mmi
347    ldfs  FR_Result = [GR_Parameter_RESULT]      
348 .restore sp
349    add   sp = 64,sp                       
350    mov   b0 = GR_SAVE_B0                  
351 };;
352
353 //
354 //  Restore gp, ar.pfs and return
355 //
356 { .mib
357    mov   gp = GR_SAVE_GP                  
358    mov   ar.pfs = GR_SAVE_PFS             
359    br.ret.sptk     b0                  
360 };;
361
362 .endp __libm_error_region
363 ASM_SIZE_DIRECTIVE(__libm_error_region)
364
365 .type   __libm_error_support#,@function
366 .global __libm_error_support#