annotate libgcc/config/cris/arit.c @ 120:f93fa5091070

fix conv1.c
author mir3636
date Thu, 08 Mar 2018 14:53:42 +0900
parents 04ced10e8804
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Signed and unsigned multiplication and division and modulus for CRIS.
kono
parents:
diff changeset
2 Contributed by Axis Communications.
kono
parents:
diff changeset
3 Written by Hans-Peter Nilsson <hp@axis.se>, c:a 1992.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 Copyright (C) 1998-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 This file is part of GCC.
kono
parents:
diff changeset
8
kono
parents:
diff changeset
9 GCC is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
10 under the terms of the GNU General Public License as published by the
kono
parents:
diff changeset
11 Free Software Foundation; either version 3, or (at your option) any
kono
parents:
diff changeset
12 later version.
kono
parents:
diff changeset
13
kono
parents:
diff changeset
14 This file is distributed in the hope that it will be useful, but
kono
parents:
diff changeset
15 WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kono
parents:
diff changeset
17 General Public License for more details.
kono
parents:
diff changeset
18
kono
parents:
diff changeset
19 Under Section 7 of GPL version 3, you are granted additional
kono
parents:
diff changeset
20 permissions described in the GCC Runtime Library Exception, version
kono
parents:
diff changeset
21 3.1, as published by the Free Software Foundation.
kono
parents:
diff changeset
22
kono
parents:
diff changeset
23 You should have received a copy of the GNU General Public License and
kono
parents:
diff changeset
24 a copy of the GCC Runtime Library Exception along with this program;
kono
parents:
diff changeset
25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
kono
parents:
diff changeset
26 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 /* Note that we provide prototypes for all "const" functions, to attach
kono
parents:
diff changeset
30 the const attribute. This is necessary in 2.7.2 - adding the
kono
parents:
diff changeset
31 attribute to the function *definition* is a syntax error.
kono
parents:
diff changeset
32 This did not work with e.g. 2.1; back then, the return type had to
kono
parents:
diff changeset
33 be "const". */
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 #include "config.h"
kono
parents:
diff changeset
36
kono
parents:
diff changeset
37 #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 3
kono
parents:
diff changeset
38 #define LZ(v) __builtin_clz (v)
kono
parents:
diff changeset
39 #endif
kono
parents:
diff changeset
40
kono
parents:
diff changeset
41 /* In (at least) the 4.7 series, GCC doesn't automatically choose the
kono
parents:
diff changeset
42 most optimal strategy, possibly related to insufficient modelling of
kono
parents:
diff changeset
43 delay-slot costs. */
kono
parents:
diff changeset
44 #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10
kono
parents:
diff changeset
45 #define SIGNMULT(s, a) ((s) * (a)) /* Cheap multiplication, better than branch. */
kono
parents:
diff changeset
46 #else
kono
parents:
diff changeset
47 #define SIGNMULT(s, a) ((s) < 0 ? -(a) : (a)) /* Branches are still better. */
kono
parents:
diff changeset
48 #endif
kono
parents:
diff changeset
49
kono
parents:
diff changeset
50 #if defined (L_udivsi3) || defined (L_divsi3) || defined (L_umodsi3) \
kono
parents:
diff changeset
51 || defined (L_modsi3)
kono
parents:
diff changeset
52 /* Result type of divmod worker function. */
kono
parents:
diff changeset
53 struct quot_rem
kono
parents:
diff changeset
54 {
kono
parents:
diff changeset
55 long quot;
kono
parents:
diff changeset
56 long rem;
kono
parents:
diff changeset
57 };
kono
parents:
diff changeset
58
kono
parents:
diff changeset
59 /* This is the worker function for div and mod. It is inlined into the
kono
parents:
diff changeset
60 respective library function. Parameter A must have bit 31 == 0. */
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 static __inline__ struct quot_rem
kono
parents:
diff changeset
63 do_31div (unsigned long a, unsigned long b)
kono
parents:
diff changeset
64 __attribute__ ((__const__, __always_inline__));
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 static __inline__ struct quot_rem
kono
parents:
diff changeset
67 do_31div (unsigned long a, unsigned long b)
kono
parents:
diff changeset
68 {
kono
parents:
diff changeset
69 /* Adjust operands and result if a is 31 bits. */
kono
parents:
diff changeset
70 long extra = 0;
kono
parents:
diff changeset
71 int quot_digits = 0;
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 if (b == 0)
kono
parents:
diff changeset
74 {
kono
parents:
diff changeset
75 struct quot_rem ret;
kono
parents:
diff changeset
76 ret.quot = 0xffffffff;
kono
parents:
diff changeset
77 ret.rem = 0xffffffff;
kono
parents:
diff changeset
78 return ret;
kono
parents:
diff changeset
79 }
kono
parents:
diff changeset
80
kono
parents:
diff changeset
81 if (a < b)
kono
parents:
diff changeset
82 return (struct quot_rem) { 0, a };
kono
parents:
diff changeset
83
kono
parents:
diff changeset
84 #ifdef LZ
kono
parents:
diff changeset
85 if (b <= a)
kono
parents:
diff changeset
86 {
kono
parents:
diff changeset
87 quot_digits = LZ (b) - LZ (a);
kono
parents:
diff changeset
88 quot_digits += (a >= (b << quot_digits));
kono
parents:
diff changeset
89 b <<= quot_digits;
kono
parents:
diff changeset
90 }
kono
parents:
diff changeset
91 #else
kono
parents:
diff changeset
92 while (b <= a)
kono
parents:
diff changeset
93 {
kono
parents:
diff changeset
94 b <<= 1;
kono
parents:
diff changeset
95 quot_digits++;
kono
parents:
diff changeset
96 }
kono
parents:
diff changeset
97 #endif
kono
parents:
diff changeset
98
kono
parents:
diff changeset
99 /* Is a 31 bits? Note that bit 31 is handled by the caller. */
kono
parents:
diff changeset
100 if (a & 0x40000000)
kono
parents:
diff changeset
101 {
kono
parents:
diff changeset
102 /* Then make b:s highest bit max 0x40000000, because it must have
kono
parents:
diff changeset
103 been 0x80000000 to be 1 bit higher than a. */
kono
parents:
diff changeset
104 b >>= 1;
kono
parents:
diff changeset
105
kono
parents:
diff changeset
106 /* Adjust a to be maximum 0x3fffffff, i.e. two upper bits zero. */
kono
parents:
diff changeset
107 if (a >= b)
kono
parents:
diff changeset
108 {
kono
parents:
diff changeset
109 a -= b;
kono
parents:
diff changeset
110 extra = 1 << (quot_digits - 1);
kono
parents:
diff changeset
111 }
kono
parents:
diff changeset
112 else
kono
parents:
diff changeset
113 {
kono
parents:
diff changeset
114 a -= b >> 1;
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 /* Remember that we adjusted a by subtracting b * 2 ** Something. */
kono
parents:
diff changeset
117 extra = 1 << quot_digits;
kono
parents:
diff changeset
118 }
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 /* The number of quotient digits will be one less, because
kono
parents:
diff changeset
121 we just adjusted b. */
kono
parents:
diff changeset
122 quot_digits--;
kono
parents:
diff changeset
123 }
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 /* Now do the division part. */
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 /* Subtract b and add ones to the right when a >= b
kono
parents:
diff changeset
128 i.e. "a - (b - 1) == (a - b) + 1". */
kono
parents:
diff changeset
129 b--;
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 #define DS __asm__ ("dstep %2,%0" : "=r" (a) : "0" (a), "r" (b))
kono
parents:
diff changeset
132
kono
parents:
diff changeset
133 switch (quot_digits)
kono
parents:
diff changeset
134 {
kono
parents:
diff changeset
135 case 32: DS; case 31: DS; case 30: DS; case 29: DS;
kono
parents:
diff changeset
136 case 28: DS; case 27: DS; case 26: DS; case 25: DS;
kono
parents:
diff changeset
137 case 24: DS; case 23: DS; case 22: DS; case 21: DS;
kono
parents:
diff changeset
138 case 20: DS; case 19: DS; case 18: DS; case 17: DS;
kono
parents:
diff changeset
139 case 16: DS; case 15: DS; case 14: DS; case 13: DS;
kono
parents:
diff changeset
140 case 12: DS; case 11: DS; case 10: DS; case 9: DS;
kono
parents:
diff changeset
141 case 8: DS; case 7: DS; case 6: DS; case 5: DS;
kono
parents:
diff changeset
142 case 4: DS; case 3: DS; case 2: DS; case 1: DS;
kono
parents:
diff changeset
143 case 0:;
kono
parents:
diff changeset
144 }
kono
parents:
diff changeset
145
kono
parents:
diff changeset
146 {
kono
parents:
diff changeset
147 struct quot_rem ret;
kono
parents:
diff changeset
148 ret.quot = (a & ((1 << quot_digits) - 1)) + extra;
kono
parents:
diff changeset
149 ret.rem = a >> quot_digits;
kono
parents:
diff changeset
150 return ret;
kono
parents:
diff changeset
151 }
kono
parents:
diff changeset
152 }
kono
parents:
diff changeset
153
kono
parents:
diff changeset
154 #ifdef L_udivsi3
kono
parents:
diff changeset
155 unsigned long
kono
parents:
diff changeset
156 __Udiv (unsigned long a, unsigned long b) __attribute__ ((__const__));
kono
parents:
diff changeset
157
kono
parents:
diff changeset
158 unsigned long
kono
parents:
diff changeset
159 __Udiv (unsigned long a, unsigned long b)
kono
parents:
diff changeset
160 {
kono
parents:
diff changeset
161 long extra = 0;
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 /* Adjust operands and result, if a and/or b is 32 bits. */
kono
parents:
diff changeset
164 /* Effectively: b & 0x80000000. */
kono
parents:
diff changeset
165 if ((long) b < 0)
kono
parents:
diff changeset
166 return a >= b;
kono
parents:
diff changeset
167
kono
parents:
diff changeset
168 /* Effectively: a & 0x80000000. */
kono
parents:
diff changeset
169 if ((long) a < 0)
kono
parents:
diff changeset
170 {
kono
parents:
diff changeset
171 int tmp = 0;
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 if (b == 0)
kono
parents:
diff changeset
174 return 0xffffffff;
kono
parents:
diff changeset
175 #ifdef LZ
kono
parents:
diff changeset
176 tmp = LZ (b);
kono
parents:
diff changeset
177 #else
kono
parents:
diff changeset
178 for (tmp = 31; (((long) b & (1 << tmp)) == 0); tmp--)
kono
parents:
diff changeset
179 ;
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 tmp = 31 - tmp;
kono
parents:
diff changeset
182 #endif
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 if ((b << tmp) > a)
kono
parents:
diff changeset
185 {
kono
parents:
diff changeset
186 extra = 1 << (tmp-1);
kono
parents:
diff changeset
187 a -= b << (tmp - 1);
kono
parents:
diff changeset
188 }
kono
parents:
diff changeset
189 else
kono
parents:
diff changeset
190 {
kono
parents:
diff changeset
191 extra = 1 << tmp;
kono
parents:
diff changeset
192 a -= b << tmp;
kono
parents:
diff changeset
193 }
kono
parents:
diff changeset
194 }
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 return do_31div (a, b).quot+extra;
kono
parents:
diff changeset
197 }
kono
parents:
diff changeset
198 #endif /* L_udivsi3 */
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 #ifdef L_divsi3
kono
parents:
diff changeset
201 long
kono
parents:
diff changeset
202 __Div (long a, long b) __attribute__ ((__const__));
kono
parents:
diff changeset
203
kono
parents:
diff changeset
204 long
kono
parents:
diff changeset
205 __Div (long a, long b)
kono
parents:
diff changeset
206 {
kono
parents:
diff changeset
207 long extra = 0;
kono
parents:
diff changeset
208 long sign = (b < 0) ? -1 : 1;
kono
parents:
diff changeset
209 long res;
kono
parents:
diff changeset
210
kono
parents:
diff changeset
211 /* We need to handle a == -2147483648 as expected and must while
kono
parents:
diff changeset
212 doing that avoid producing a sequence like "abs (a) < 0" as GCC
kono
parents:
diff changeset
213 may optimize out the test. That sequence may not be obvious as
kono
parents:
diff changeset
214 we call inline functions. Testing for a being negative and
kono
parents:
diff changeset
215 handling (presumably much rarer than positive) enables us to get
kono
parents:
diff changeset
216 a bit of optimization for an (accumulated) reduction of the
kono
parents:
diff changeset
217 penalty of the 0x80000000 special-case. */
kono
parents:
diff changeset
218 if (a < 0)
kono
parents:
diff changeset
219 {
kono
parents:
diff changeset
220 sign = -sign;
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 if ((a & 0x7fffffff) == 0)
kono
parents:
diff changeset
223 {
kono
parents:
diff changeset
224 /* We're at 0x80000000. Tread carefully. */
kono
parents:
diff changeset
225 a -= SIGNMULT (sign, b);
kono
parents:
diff changeset
226 extra = sign;
kono
parents:
diff changeset
227 }
kono
parents:
diff changeset
228 a = -a;
kono
parents:
diff changeset
229 }
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 res = do_31div (a, __builtin_labs (b)).quot;
kono
parents:
diff changeset
232 return SIGNMULT (sign, res) + extra;
kono
parents:
diff changeset
233 }
kono
parents:
diff changeset
234 #endif /* L_divsi3 */
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236
kono
parents:
diff changeset
237 #ifdef L_umodsi3
kono
parents:
diff changeset
238 unsigned long
kono
parents:
diff changeset
239 __Umod (unsigned long a, unsigned long b) __attribute__ ((__const__));
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 unsigned long
kono
parents:
diff changeset
242 __Umod (unsigned long a, unsigned long b)
kono
parents:
diff changeset
243 {
kono
parents:
diff changeset
244 /* Adjust operands and result if a and/or b is 32 bits. */
kono
parents:
diff changeset
245 if ((long) b < 0)
kono
parents:
diff changeset
246 return a >= b ? a - b : a;
kono
parents:
diff changeset
247
kono
parents:
diff changeset
248 if ((long) a < 0)
kono
parents:
diff changeset
249 {
kono
parents:
diff changeset
250 int tmp = 0;
kono
parents:
diff changeset
251
kono
parents:
diff changeset
252 if (b == 0)
kono
parents:
diff changeset
253 return a;
kono
parents:
diff changeset
254 #ifdef LZ
kono
parents:
diff changeset
255 tmp = LZ (b);
kono
parents:
diff changeset
256 #else
kono
parents:
diff changeset
257 for (tmp = 31; (((long) b & (1 << tmp)) == 0); tmp--)
kono
parents:
diff changeset
258 ;
kono
parents:
diff changeset
259 tmp = 31 - tmp;
kono
parents:
diff changeset
260 #endif
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 if ((b << tmp) > a)
kono
parents:
diff changeset
263 {
kono
parents:
diff changeset
264 a -= b << (tmp - 1);
kono
parents:
diff changeset
265 }
kono
parents:
diff changeset
266 else
kono
parents:
diff changeset
267 {
kono
parents:
diff changeset
268 a -= b << tmp;
kono
parents:
diff changeset
269 }
kono
parents:
diff changeset
270 }
kono
parents:
diff changeset
271
kono
parents:
diff changeset
272 return do_31div (a, b).rem;
kono
parents:
diff changeset
273 }
kono
parents:
diff changeset
274 #endif /* L_umodsi3 */
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 #ifdef L_modsi3
kono
parents:
diff changeset
277 long
kono
parents:
diff changeset
278 __Mod (long a, long b) __attribute__ ((__const__));
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 long
kono
parents:
diff changeset
281 __Mod (long a, long b)
kono
parents:
diff changeset
282 {
kono
parents:
diff changeset
283 long sign = 1;
kono
parents:
diff changeset
284 long res;
kono
parents:
diff changeset
285
kono
parents:
diff changeset
286 /* We need to handle a == -2147483648 as expected and must while
kono
parents:
diff changeset
287 doing that avoid producing a sequence like "abs (a) < 0" as GCC
kono
parents:
diff changeset
288 may optimize out the test. That sequence may not be obvious as
kono
parents:
diff changeset
289 we call inline functions. Testing for a being negative and
kono
parents:
diff changeset
290 handling (presumably much rarer than positive) enables us to get
kono
parents:
diff changeset
291 a bit of optimization for an (accumulated) reduction of the
kono
parents:
diff changeset
292 penalty of the 0x80000000 special-case. */
kono
parents:
diff changeset
293 if (a < 0)
kono
parents:
diff changeset
294 {
kono
parents:
diff changeset
295 sign = -1;
kono
parents:
diff changeset
296 if ((a & 0x7fffffff) == 0)
kono
parents:
diff changeset
297 /* We're at 0x80000000. Tread carefully. */
kono
parents:
diff changeset
298 a += __builtin_labs (b);
kono
parents:
diff changeset
299 a = -a;
kono
parents:
diff changeset
300 }
kono
parents:
diff changeset
301
kono
parents:
diff changeset
302 res = do_31div (a, __builtin_labs (b)).rem;
kono
parents:
diff changeset
303 return SIGNMULT (sign, res);
kono
parents:
diff changeset
304 }
kono
parents:
diff changeset
305 #endif /* L_modsi3 */
kono
parents:
diff changeset
306 #endif /* L_udivsi3 || L_divsi3 || L_umodsi3 || L_modsi3 */
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 /*
kono
parents:
diff changeset
309 * Local variables:
kono
parents:
diff changeset
310 * eval: (c-set-style "gnu")
kono
parents:
diff changeset
311 * indent-tabs-mode: t
kono
parents:
diff changeset
312 * End:
kono
parents:
diff changeset
313 */