]>
Commit | Line | Data |
---|---|---|
f964490f RM |
1 | /* s_ceill.S IBM extended format long double version. |
2 | Copyright (C) 2004, 2006 Free Software Foundation, Inc. | |
3 | This file is part of the GNU C Library. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
19 | ||
20 | #include <sysdep.h> | |
21 | #include <math_ldbl_opt.h> | |
22 | ||
23 | .section ".toc","aw" | |
24 | .LC0: /* 2**52 */ | |
25 | .tc FD_43300000_0[TC],0x4330000000000000 | |
26 | ||
27 | .section ".text" | |
28 | ||
29 | /* long double [fp1,fp2] ceill (long double x [fp1,fp2]) | |
30 | IEEE 1003.1 ceil function. | |
31 | ||
32 | PowerPC64 long double uses the IBM extended format which is | |
33 | represented two 64-floating point double values. The values are | |
34 | non-overlapping giving an effective precision of 106 bits. The first | |
35 | double contains the high order bits of mantisa and is always ceiled | |
36 | to represent a normal ceiling of long double to double. Since the | |
37 | long double value is sum of the high and low values, the low double | |
38 | normally has the opposite sign to compensate for the this ceiling. | |
39 | ||
40 | For long double there are two cases: | |
41 | 1) |x| < 2**52, all the integer bits are in the high double. | |
42 | ceil the high double and set the low double to -0.0. | |
43 | 2) |x| >= 2**52, ceiling involves both doubles. | |
44 | See the comment before lable .L2 for details. | |
45 | */ | |
46 | ||
47 | ENTRY (__ceill) | |
48 | mffs fp11 /* Save current FPU rounding mode. */ | |
49 | lfd fp13,.LC0@toc(2) | |
50 | fabs fp0,fp1 | |
51 | fabs fp9,fp2 | |
52 | fsub fp12,fp13,fp13 /* generate 0.0 */ | |
53 | fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO52) */ | |
54 | fcmpo cr6,fp1,fp12 /* if (x > 0.0) */ | |
55 | bnl- cr7,.L2 | |
56 | mtfsfi 7,2 /* Set rounding mode toward +inf. */ | |
57 | fneg fp2,fp12 | |
58 | ble- cr6,.L1 | |
59 | fadd fp1,fp1,fp13 /* x+= TWO52; */ | |
60 | fsub fp1,fp1,fp13 /* x-= TWO52; */ | |
61 | fabs fp1,fp1 /* if (x == 0.0) */ | |
62 | .L0: | |
63 | mtfsf 0x01,fp11 /* restore previous rounding mode. */ | |
64 | blr /* x = 0.0; */ | |
65 | .L1: | |
66 | bge- cr6,.L0 /* if (x < 0.0) */ | |
67 | fsub fp1,fp1,fp13 /* x-= TWO52; */ | |
68 | fadd fp1,fp1,fp13 /* x+= TWO52; */ | |
69 | fcmpu cr5,fp1,fp12 /* if (x > 0.0) */ | |
70 | mtfsf 0x01,fp11 /* restore previous rounding mode. */ | |
71 | fnabs fp1,fp1 /* if (x == 0.0) */ | |
72 | blr /* x = -0.0; */ | |
73 | ||
74 | /* The high double is > TWO52 so we need to round the low double and | |
75 | perhaps the high double. In this case we have to round the low | |
76 | double and handle any adjustment to the high double that may be | |
77 | caused by rounding (up). This is complicated by the fact that the | |
78 | high double may already be rounded and the low double may have the | |
79 | opposite sign to compensate.This gets a bit tricky so we use the | |
80 | following algorithm: | |
81 | ||
82 | tau = floor(x_high/TWO52); | |
83 | x0 = x_high - tau; | |
84 | x1 = x_low + tau; | |
85 | r1 = rint(x1); | |
86 | y_high = x0 + r1; | |
87 | y_low = x0 - y_high + r1; | |
88 | return y; */ | |
89 | .L2: | |
90 | fcmpu cr7,fp9,fp13 /* if (|x_low| > TWO52) */ | |
91 | fcmpu cr0,fp9,fp12 /* || (|x_low| == 0.0) */ | |
92 | fcmpu cr5,fp2,fp12 /* if (x_low > 0.0) */ | |
93 | bgelr- cr7 /* return x; */ | |
94 | beqlr- cr0 | |
95 | mtfsfi 7,2 /* Set rounding mode toward +inf. */ | |
96 | fdiv fp8,fp1,fp13 /* x_high/TWO52 */ | |
97 | ||
98 | bng- cr6,.L6 /* if (x > 0.0) */ | |
99 | fctidz fp0,fp8 | |
100 | fcfid fp8,fp0 /* tau = floor(x_high/TWO52); */ | |
101 | bng cr5,.L4 /* if (x_low > 0.0) */ | |
102 | fmr fp3,fp1 | |
103 | fmr fp4,fp2 | |
104 | b .L5 | |
105 | .L4: /* if (x_low < 0.0) */ | |
106 | fsub fp3,fp1,fp8 /* x0 = x_high - tau; */ | |
107 | fadd fp4,fp2,fp8 /* x1 = x_low + tau; */ | |
108 | .L5: | |
109 | fadd fp5,fp4,fp13 /* r1 = r1 + TWO52; */ | |
110 | fsub fp5,fp5,fp13 /* r1 = r1 - TWO52; */ | |
111 | b .L9 | |
112 | .L6: /* if (x < 0.0) */ | |
113 | fctidz fp0,fp8 | |
114 | fcfid fp8,fp0 /* tau = floor(x_high/TWO52); */ | |
115 | bnl cr5,.L7 /* if (x_low < 0.0) */ | |
116 | fmr fp3,fp1 | |
117 | fmr fp4,fp2 | |
118 | b .L8 | |
119 | .L7: /* if (x_low > 0.0) */ | |
120 | fsub fp3,fp1,fp8 /* x0 = x_high - tau; */ | |
121 | fadd fp4,fp2,fp8 /* x1 = x_low + tau; */ | |
122 | .L8: | |
123 | fsub fp5,fp4,fp13 /* r1-= TWO52; */ | |
124 | fadd fp5,fp5,fp13 /* r1+= TWO52; */ | |
125 | .L9: | |
126 | mtfsf 0x01,fp11 /* restore previous rounding mode. */ | |
127 | fadd fp1,fp3,fp5 /* y_high = x0 + r1; */ | |
128 | fsub fp2,fp3,fp1 /* y_low = x0 - y_high + r1; */ | |
129 | fadd fp2,fp2,fp5 | |
130 | blr | |
131 | END (__ceill) | |
132 | ||
133 | long_double_symbol (libm, __ceill, ceill) |