annotate gcc/wide-int.cc @ 130:e108057fa461

merge
author mir3636
date Thu, 25 Oct 2018 08:08:40 +0900
parents 04ced10e8804
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Operations with very long integers.
kono
parents:
diff changeset
2 Copyright (C) 2012-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
8 under the terms of the GNU General Public License as published by the
kono
parents:
diff changeset
9 Free Software Foundation; either version 3, or (at your option) any
kono
parents:
diff changeset
10 later version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but WITHOUT
kono
parents:
diff changeset
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
15 for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 #include "config.h"
kono
parents:
diff changeset
22 #include "system.h"
kono
parents:
diff changeset
23 #include "coretypes.h"
kono
parents:
diff changeset
24 #include "tm.h"
kono
parents:
diff changeset
25 #include "tree.h"
kono
parents:
diff changeset
26 #include "selftest.h"
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 #define HOST_BITS_PER_HALF_WIDE_INT 32
kono
parents:
diff changeset
30 #if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG
kono
parents:
diff changeset
31 # define HOST_HALF_WIDE_INT long
kono
parents:
diff changeset
32 #elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT
kono
parents:
diff changeset
33 # define HOST_HALF_WIDE_INT int
kono
parents:
diff changeset
34 #else
kono
parents:
diff changeset
35 #error Please add support for HOST_HALF_WIDE_INT
kono
parents:
diff changeset
36 #endif
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 #define W_TYPE_SIZE HOST_BITS_PER_WIDE_INT
kono
parents:
diff changeset
39 /* Do not include longlong.h when compiler is clang-based. See PR61146. */
kono
parents:
diff changeset
40 #if GCC_VERSION >= 3000 && (W_TYPE_SIZE == 32 || defined (__SIZEOF_INT128__)) && !defined(__clang__)
kono
parents:
diff changeset
41 typedef unsigned HOST_HALF_WIDE_INT UHWtype;
kono
parents:
diff changeset
42 typedef unsigned HOST_WIDE_INT UWtype;
kono
parents:
diff changeset
43 typedef unsigned int UQItype __attribute__ ((mode (QI)));
kono
parents:
diff changeset
44 typedef unsigned int USItype __attribute__ ((mode (SI)));
kono
parents:
diff changeset
45 typedef unsigned int UDItype __attribute__ ((mode (DI)));
kono
parents:
diff changeset
46 #if W_TYPE_SIZE == 32
kono
parents:
diff changeset
47 typedef unsigned int UDWtype __attribute__ ((mode (DI)));
kono
parents:
diff changeset
48 #else
kono
parents:
diff changeset
49 typedef unsigned int UDWtype __attribute__ ((mode (TI)));
kono
parents:
diff changeset
50 #endif
kono
parents:
diff changeset
51 #include "longlong.h"
kono
parents:
diff changeset
52 #endif
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 static const HOST_WIDE_INT zeros[WIDE_INT_MAX_ELTS] = {};
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 /*
kono
parents:
diff changeset
57 * Internal utilities.
kono
parents:
diff changeset
58 */
kono
parents:
diff changeset
59
kono
parents:
diff changeset
60 /* Quantities to deal with values that hold half of a wide int. Used
kono
parents:
diff changeset
61 in multiply and divide. */
kono
parents:
diff changeset
62 #define HALF_INT_MASK ((HOST_WIDE_INT_1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 #define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
kono
parents:
diff changeset
65 #define BLOCKS_NEEDED(PREC) \
kono
parents:
diff changeset
66 (PREC ? (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT) : 1)
kono
parents:
diff changeset
67 #define SIGN_MASK(X) ((HOST_WIDE_INT) (X) < 0 ? -1 : 0)
kono
parents:
diff changeset
68
kono
parents:
diff changeset
69 /* Return the value a VAL[I] if I < LEN, otherwise, return 0 or -1
kono
parents:
diff changeset
70 based on the top existing bit of VAL. */
kono
parents:
diff changeset
71
kono
parents:
diff changeset
72 static unsigned HOST_WIDE_INT
kono
parents:
diff changeset
73 safe_uhwi (const HOST_WIDE_INT *val, unsigned int len, unsigned int i)
kono
parents:
diff changeset
74 {
kono
parents:
diff changeset
75 return i < len ? val[i] : val[len - 1] < 0 ? HOST_WIDE_INT_M1 : 0;
kono
parents:
diff changeset
76 }
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 /* Convert the integer in VAL to canonical form, returning its new length.
kono
parents:
diff changeset
79 LEN is the number of blocks currently in VAL and PRECISION is the number
kono
parents:
diff changeset
80 of bits in the integer it represents.
kono
parents:
diff changeset
81
kono
parents:
diff changeset
82 This function only changes the representation, not the value. */
kono
parents:
diff changeset
83 static unsigned int
kono
parents:
diff changeset
84 canonize (HOST_WIDE_INT *val, unsigned int len, unsigned int precision)
kono
parents:
diff changeset
85 {
kono
parents:
diff changeset
86 unsigned int blocks_needed = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
87 HOST_WIDE_INT top;
kono
parents:
diff changeset
88 int i;
kono
parents:
diff changeset
89
kono
parents:
diff changeset
90 if (len > blocks_needed)
kono
parents:
diff changeset
91 len = blocks_needed;
kono
parents:
diff changeset
92
kono
parents:
diff changeset
93 if (len == 1)
kono
parents:
diff changeset
94 return len;
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 top = val[len - 1];
kono
parents:
diff changeset
97 if (len * HOST_BITS_PER_WIDE_INT > precision)
kono
parents:
diff changeset
98 val[len - 1] = top = sext_hwi (top, precision % HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
99 if (top != 0 && top != (HOST_WIDE_INT)-1)
kono
parents:
diff changeset
100 return len;
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 /* At this point we know that the top is either 0 or -1. Find the
kono
parents:
diff changeset
103 first block that is not a copy of this. */
kono
parents:
diff changeset
104 for (i = len - 2; i >= 0; i--)
kono
parents:
diff changeset
105 {
kono
parents:
diff changeset
106 HOST_WIDE_INT x = val[i];
kono
parents:
diff changeset
107 if (x != top)
kono
parents:
diff changeset
108 {
kono
parents:
diff changeset
109 if (SIGN_MASK (x) == top)
kono
parents:
diff changeset
110 return i + 1;
kono
parents:
diff changeset
111
kono
parents:
diff changeset
112 /* We need an extra block because the top bit block i does
kono
parents:
diff changeset
113 not match the extension. */
kono
parents:
diff changeset
114 return i + 2;
kono
parents:
diff changeset
115 }
kono
parents:
diff changeset
116 }
kono
parents:
diff changeset
117
kono
parents:
diff changeset
118 /* The number is 0 or -1. */
kono
parents:
diff changeset
119 return 1;
kono
parents:
diff changeset
120 }
kono
parents:
diff changeset
121
kono
parents:
diff changeset
122 /* VAL[0] is the unsigned result of an operation. Canonize it by adding
kono
parents:
diff changeset
123 another 0 block if needed, and return number of blocks needed. */
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 static inline unsigned int
kono
parents:
diff changeset
126 canonize_uhwi (HOST_WIDE_INT *val, unsigned int precision)
kono
parents:
diff changeset
127 {
kono
parents:
diff changeset
128 if (val[0] < 0 && precision > HOST_BITS_PER_WIDE_INT)
kono
parents:
diff changeset
129 {
kono
parents:
diff changeset
130 val[1] = 0;
kono
parents:
diff changeset
131 return 2;
kono
parents:
diff changeset
132 }
kono
parents:
diff changeset
133 return 1;
kono
parents:
diff changeset
134 }
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 /*
kono
parents:
diff changeset
137 * Conversion routines in and out of wide_int.
kono
parents:
diff changeset
138 */
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 /* Copy XLEN elements from XVAL to VAL. If NEED_CANON, canonize the
kono
parents:
diff changeset
141 result for an integer with precision PRECISION. Return the length
kono
parents:
diff changeset
142 of VAL (after any canonization. */
kono
parents:
diff changeset
143 unsigned int
kono
parents:
diff changeset
144 wi::from_array (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
145 unsigned int xlen, unsigned int precision, bool need_canon)
kono
parents:
diff changeset
146 {
kono
parents:
diff changeset
147 for (unsigned i = 0; i < xlen; i++)
kono
parents:
diff changeset
148 val[i] = xval[i];
kono
parents:
diff changeset
149 return need_canon ? canonize (val, xlen, precision) : xlen;
kono
parents:
diff changeset
150 }
kono
parents:
diff changeset
151
kono
parents:
diff changeset
152 /* Construct a wide int from a buffer of length LEN. BUFFER will be
kono
parents:
diff changeset
153 read according to byte endianness and word endianness of the target.
kono
parents:
diff changeset
154 Only the lower BUFFER_LEN bytes of the result are set; the remaining
kono
parents:
diff changeset
155 high bytes are cleared. */
kono
parents:
diff changeset
156 wide_int
kono
parents:
diff changeset
157 wi::from_buffer (const unsigned char *buffer, unsigned int buffer_len)
kono
parents:
diff changeset
158 {
kono
parents:
diff changeset
159 unsigned int precision = buffer_len * BITS_PER_UNIT;
kono
parents:
diff changeset
160 wide_int result = wide_int::create (precision);
kono
parents:
diff changeset
161 unsigned int words = buffer_len / UNITS_PER_WORD;
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 /* We have to clear all the bits ourself, as we merely or in values
kono
parents:
diff changeset
164 below. */
kono
parents:
diff changeset
165 unsigned int len = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
166 HOST_WIDE_INT *val = result.write_val ();
kono
parents:
diff changeset
167 for (unsigned int i = 0; i < len; ++i)
kono
parents:
diff changeset
168 val[i] = 0;
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 for (unsigned int byte = 0; byte < buffer_len; byte++)
kono
parents:
diff changeset
171 {
kono
parents:
diff changeset
172 unsigned int offset;
kono
parents:
diff changeset
173 unsigned int index;
kono
parents:
diff changeset
174 unsigned int bitpos = byte * BITS_PER_UNIT;
kono
parents:
diff changeset
175 unsigned HOST_WIDE_INT value;
kono
parents:
diff changeset
176
kono
parents:
diff changeset
177 if (buffer_len > UNITS_PER_WORD)
kono
parents:
diff changeset
178 {
kono
parents:
diff changeset
179 unsigned int word = byte / UNITS_PER_WORD;
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 if (WORDS_BIG_ENDIAN)
kono
parents:
diff changeset
182 word = (words - 1) - word;
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 offset = word * UNITS_PER_WORD;
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 if (BYTES_BIG_ENDIAN)
kono
parents:
diff changeset
187 offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
kono
parents:
diff changeset
188 else
kono
parents:
diff changeset
189 offset += byte % UNITS_PER_WORD;
kono
parents:
diff changeset
190 }
kono
parents:
diff changeset
191 else
kono
parents:
diff changeset
192 offset = BYTES_BIG_ENDIAN ? (buffer_len - 1) - byte : byte;
kono
parents:
diff changeset
193
kono
parents:
diff changeset
194 value = (unsigned HOST_WIDE_INT) buffer[offset];
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 index = bitpos / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
197 val[index] |= value << (bitpos % HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
198 }
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 result.set_len (canonize (val, len, precision));
kono
parents:
diff changeset
201
kono
parents:
diff changeset
202 return result;
kono
parents:
diff changeset
203 }
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 /* Sets RESULT from X, the sign is taken according to SGN. */
kono
parents:
diff changeset
206 void
kono
parents:
diff changeset
207 wi::to_mpz (const wide_int_ref &x, mpz_t result, signop sgn)
kono
parents:
diff changeset
208 {
kono
parents:
diff changeset
209 int len = x.get_len ();
kono
parents:
diff changeset
210 const HOST_WIDE_INT *v = x.get_val ();
kono
parents:
diff changeset
211 int excess = len * HOST_BITS_PER_WIDE_INT - x.get_precision ();
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 if (wi::neg_p (x, sgn))
kono
parents:
diff changeset
214 {
kono
parents:
diff changeset
215 /* We use ones complement to avoid -x80..0 edge case that -
kono
parents:
diff changeset
216 won't work on. */
kono
parents:
diff changeset
217 HOST_WIDE_INT *t = XALLOCAVEC (HOST_WIDE_INT, len);
kono
parents:
diff changeset
218 for (int i = 0; i < len; i++)
kono
parents:
diff changeset
219 t[i] = ~v[i];
kono
parents:
diff changeset
220 if (excess > 0)
kono
parents:
diff changeset
221 t[len - 1] = (unsigned HOST_WIDE_INT) t[len - 1] << excess >> excess;
kono
parents:
diff changeset
222 mpz_import (result, len, -1, sizeof (HOST_WIDE_INT), 0, 0, t);
kono
parents:
diff changeset
223 mpz_com (result, result);
kono
parents:
diff changeset
224 }
kono
parents:
diff changeset
225 else if (excess > 0)
kono
parents:
diff changeset
226 {
kono
parents:
diff changeset
227 HOST_WIDE_INT *t = XALLOCAVEC (HOST_WIDE_INT, len);
kono
parents:
diff changeset
228 for (int i = 0; i < len - 1; i++)
kono
parents:
diff changeset
229 t[i] = v[i];
kono
parents:
diff changeset
230 t[len - 1] = (unsigned HOST_WIDE_INT) v[len - 1] << excess >> excess;
kono
parents:
diff changeset
231 mpz_import (result, len, -1, sizeof (HOST_WIDE_INT), 0, 0, t);
kono
parents:
diff changeset
232 }
kono
parents:
diff changeset
233 else
kono
parents:
diff changeset
234 mpz_import (result, len, -1, sizeof (HOST_WIDE_INT), 0, 0, v);
kono
parents:
diff changeset
235 }
kono
parents:
diff changeset
236
kono
parents:
diff changeset
237 /* Returns X converted to TYPE. If WRAP is true, then out-of-range
kono
parents:
diff changeset
238 values of VAL will be wrapped; otherwise, they will be set to the
kono
parents:
diff changeset
239 appropriate minimum or maximum TYPE bound. */
kono
parents:
diff changeset
240 wide_int
kono
parents:
diff changeset
241 wi::from_mpz (const_tree type, mpz_t x, bool wrap)
kono
parents:
diff changeset
242 {
kono
parents:
diff changeset
243 size_t count, numb;
kono
parents:
diff changeset
244 unsigned int prec = TYPE_PRECISION (type);
kono
parents:
diff changeset
245 wide_int res = wide_int::create (prec);
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 if (!wrap)
kono
parents:
diff changeset
248 {
kono
parents:
diff changeset
249 mpz_t min, max;
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 mpz_init (min);
kono
parents:
diff changeset
252 mpz_init (max);
kono
parents:
diff changeset
253 get_type_static_bounds (type, min, max);
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 if (mpz_cmp (x, min) < 0)
kono
parents:
diff changeset
256 mpz_set (x, min);
kono
parents:
diff changeset
257 else if (mpz_cmp (x, max) > 0)
kono
parents:
diff changeset
258 mpz_set (x, max);
kono
parents:
diff changeset
259
kono
parents:
diff changeset
260 mpz_clear (min);
kono
parents:
diff changeset
261 mpz_clear (max);
kono
parents:
diff changeset
262 }
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 /* Determine the number of unsigned HOST_WIDE_INTs that are required
kono
parents:
diff changeset
265 for representing the absolute value. The code to calculate count is
kono
parents:
diff changeset
266 extracted from the GMP manual, section "Integer Import and Export":
kono
parents:
diff changeset
267 http://gmplib.org/manual/Integer-Import-and-Export.html */
kono
parents:
diff changeset
268 numb = CHAR_BIT * sizeof (HOST_WIDE_INT);
kono
parents:
diff changeset
269 count = (mpz_sizeinbase (x, 2) + numb - 1) / numb;
kono
parents:
diff changeset
270 HOST_WIDE_INT *val = res.write_val ();
kono
parents:
diff changeset
271 /* Read the absolute value.
kono
parents:
diff changeset
272
kono
parents:
diff changeset
273 Write directly to the wide_int storage if possible, otherwise leave
kono
parents:
diff changeset
274 GMP to allocate the memory for us. It might be slightly more efficient
kono
parents:
diff changeset
275 to use mpz_tdiv_r_2exp for the latter case, but the situation is
kono
parents:
diff changeset
276 pathological and it seems safer to operate on the original mpz value
kono
parents:
diff changeset
277 in all cases. */
kono
parents:
diff changeset
278 void *valres = mpz_export (count <= WIDE_INT_MAX_ELTS ? val : 0,
kono
parents:
diff changeset
279 &count, -1, sizeof (HOST_WIDE_INT), 0, 0, x);
kono
parents:
diff changeset
280 if (count < 1)
kono
parents:
diff changeset
281 {
kono
parents:
diff changeset
282 val[0] = 0;
kono
parents:
diff changeset
283 count = 1;
kono
parents:
diff changeset
284 }
kono
parents:
diff changeset
285 count = MIN (count, BLOCKS_NEEDED (prec));
kono
parents:
diff changeset
286 if (valres != val)
kono
parents:
diff changeset
287 {
kono
parents:
diff changeset
288 memcpy (val, valres, count * sizeof (HOST_WIDE_INT));
kono
parents:
diff changeset
289 free (valres);
kono
parents:
diff changeset
290 }
kono
parents:
diff changeset
291 /* Zero-extend the absolute value to PREC bits. */
kono
parents:
diff changeset
292 if (count < BLOCKS_NEEDED (prec) && val[count - 1] < 0)
kono
parents:
diff changeset
293 val[count++] = 0;
kono
parents:
diff changeset
294 else
kono
parents:
diff changeset
295 count = canonize (val, count, prec);
kono
parents:
diff changeset
296 res.set_len (count);
kono
parents:
diff changeset
297
kono
parents:
diff changeset
298 if (mpz_sgn (x) < 0)
kono
parents:
diff changeset
299 res = -res;
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 return res;
kono
parents:
diff changeset
302 }
kono
parents:
diff changeset
303
kono
parents:
diff changeset
304 /*
kono
parents:
diff changeset
305 * Largest and smallest values in a mode.
kono
parents:
diff changeset
306 */
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 /* Return the largest SGNed number that is representable in PRECISION bits.
kono
parents:
diff changeset
309
kono
parents:
diff changeset
310 TODO: There is still code from the double_int era that trys to
kono
parents:
diff changeset
311 make up for the fact that double int's could not represent the
kono
parents:
diff changeset
312 min and max values of all types. This code should be removed
kono
parents:
diff changeset
313 because the min and max values can always be represented in
kono
parents:
diff changeset
314 wide_ints and int-csts. */
kono
parents:
diff changeset
315 wide_int
kono
parents:
diff changeset
316 wi::max_value (unsigned int precision, signop sgn)
kono
parents:
diff changeset
317 {
kono
parents:
diff changeset
318 gcc_checking_assert (precision != 0);
kono
parents:
diff changeset
319 if (sgn == UNSIGNED)
kono
parents:
diff changeset
320 /* The unsigned max is just all ones. */
kono
parents:
diff changeset
321 return shwi (-1, precision);
kono
parents:
diff changeset
322 else
kono
parents:
diff changeset
323 /* The signed max is all ones except the top bit. This must be
kono
parents:
diff changeset
324 explicitly represented. */
kono
parents:
diff changeset
325 return mask (precision - 1, false, precision);
kono
parents:
diff changeset
326 }
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 /* Return the largest SGNed number that is representable in PRECISION bits. */
kono
parents:
diff changeset
329 wide_int
kono
parents:
diff changeset
330 wi::min_value (unsigned int precision, signop sgn)
kono
parents:
diff changeset
331 {
kono
parents:
diff changeset
332 gcc_checking_assert (precision != 0);
kono
parents:
diff changeset
333 if (sgn == UNSIGNED)
kono
parents:
diff changeset
334 return uhwi (0, precision);
kono
parents:
diff changeset
335 else
kono
parents:
diff changeset
336 /* The signed min is all zeros except the top bit. This must be
kono
parents:
diff changeset
337 explicitly represented. */
kono
parents:
diff changeset
338 return wi::set_bit_in_zero (precision - 1, precision);
kono
parents:
diff changeset
339 }
kono
parents:
diff changeset
340
kono
parents:
diff changeset
341 /*
kono
parents:
diff changeset
342 * Public utilities.
kono
parents:
diff changeset
343 */
kono
parents:
diff changeset
344
kono
parents:
diff changeset
345 /* Convert the number represented by XVAL, XLEN and XPRECISION, which has
kono
parents:
diff changeset
346 signedness SGN, to an integer that has PRECISION bits. Store the blocks
kono
parents:
diff changeset
347 in VAL and return the number of blocks used.
kono
parents:
diff changeset
348
kono
parents:
diff changeset
349 This function can handle both extension (PRECISION > XPRECISION)
kono
parents:
diff changeset
350 and truncation (PRECISION < XPRECISION). */
kono
parents:
diff changeset
351 unsigned int
kono
parents:
diff changeset
352 wi::force_to_size (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
353 unsigned int xlen, unsigned int xprecision,
kono
parents:
diff changeset
354 unsigned int precision, signop sgn)
kono
parents:
diff changeset
355 {
kono
parents:
diff changeset
356 unsigned int blocks_needed = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
357 unsigned int len = blocks_needed < xlen ? blocks_needed : xlen;
kono
parents:
diff changeset
358 for (unsigned i = 0; i < len; i++)
kono
parents:
diff changeset
359 val[i] = xval[i];
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 if (precision > xprecision)
kono
parents:
diff changeset
362 {
kono
parents:
diff changeset
363 unsigned int small_xprecision = xprecision % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
364
kono
parents:
diff changeset
365 /* Expanding. */
kono
parents:
diff changeset
366 if (sgn == UNSIGNED)
kono
parents:
diff changeset
367 {
kono
parents:
diff changeset
368 if (small_xprecision && len == BLOCKS_NEEDED (xprecision))
kono
parents:
diff changeset
369 val[len - 1] = zext_hwi (val[len - 1], small_xprecision);
kono
parents:
diff changeset
370 else if (val[len - 1] < 0)
kono
parents:
diff changeset
371 {
kono
parents:
diff changeset
372 while (len < BLOCKS_NEEDED (xprecision))
kono
parents:
diff changeset
373 val[len++] = -1;
kono
parents:
diff changeset
374 if (small_xprecision)
kono
parents:
diff changeset
375 val[len - 1] = zext_hwi (val[len - 1], small_xprecision);
kono
parents:
diff changeset
376 else
kono
parents:
diff changeset
377 val[len++] = 0;
kono
parents:
diff changeset
378 }
kono
parents:
diff changeset
379 }
kono
parents:
diff changeset
380 else
kono
parents:
diff changeset
381 {
kono
parents:
diff changeset
382 if (small_xprecision && len == BLOCKS_NEEDED (xprecision))
kono
parents:
diff changeset
383 val[len - 1] = sext_hwi (val[len - 1], small_xprecision);
kono
parents:
diff changeset
384 }
kono
parents:
diff changeset
385 }
kono
parents:
diff changeset
386 len = canonize (val, len, precision);
kono
parents:
diff changeset
387
kono
parents:
diff changeset
388 return len;
kono
parents:
diff changeset
389 }
kono
parents:
diff changeset
390
kono
parents:
diff changeset
391 /* This function hides the fact that we cannot rely on the bits beyond
kono
parents:
diff changeset
392 the precision. This issue comes up in the relational comparisions
kono
parents:
diff changeset
393 where we do allow comparisons of values of different precisions. */
kono
parents:
diff changeset
394 static inline HOST_WIDE_INT
kono
parents:
diff changeset
395 selt (const HOST_WIDE_INT *a, unsigned int len,
kono
parents:
diff changeset
396 unsigned int blocks_needed, unsigned int small_prec,
kono
parents:
diff changeset
397 unsigned int index, signop sgn)
kono
parents:
diff changeset
398 {
kono
parents:
diff changeset
399 HOST_WIDE_INT val;
kono
parents:
diff changeset
400 if (index < len)
kono
parents:
diff changeset
401 val = a[index];
kono
parents:
diff changeset
402 else if (index < blocks_needed || sgn == SIGNED)
kono
parents:
diff changeset
403 /* Signed or within the precision. */
kono
parents:
diff changeset
404 val = SIGN_MASK (a[len - 1]);
kono
parents:
diff changeset
405 else
kono
parents:
diff changeset
406 /* Unsigned extension beyond the precision. */
kono
parents:
diff changeset
407 val = 0;
kono
parents:
diff changeset
408
kono
parents:
diff changeset
409 if (small_prec && index == blocks_needed - 1)
kono
parents:
diff changeset
410 return (sgn == SIGNED
kono
parents:
diff changeset
411 ? sext_hwi (val, small_prec)
kono
parents:
diff changeset
412 : zext_hwi (val, small_prec));
kono
parents:
diff changeset
413 else
kono
parents:
diff changeset
414 return val;
kono
parents:
diff changeset
415 }
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417 /* Find the highest bit represented in a wide int. This will in
kono
parents:
diff changeset
418 general have the same value as the sign bit. */
kono
parents:
diff changeset
419 static inline HOST_WIDE_INT
kono
parents:
diff changeset
420 top_bit_of (const HOST_WIDE_INT *a, unsigned int len, unsigned int prec)
kono
parents:
diff changeset
421 {
kono
parents:
diff changeset
422 int excess = len * HOST_BITS_PER_WIDE_INT - prec;
kono
parents:
diff changeset
423 unsigned HOST_WIDE_INT val = a[len - 1];
kono
parents:
diff changeset
424 if (excess > 0)
kono
parents:
diff changeset
425 val <<= excess;
kono
parents:
diff changeset
426 return val >> (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
427 }
kono
parents:
diff changeset
428
kono
parents:
diff changeset
429 /*
kono
parents:
diff changeset
430 * Comparisons, note that only equality is an operator. The other
kono
parents:
diff changeset
431 * comparisons cannot be operators since they are inherently signed or
kono
parents:
diff changeset
432 * unsigned and C++ has no such operators.
kono
parents:
diff changeset
433 */
kono
parents:
diff changeset
434
kono
parents:
diff changeset
435 /* Return true if OP0 == OP1. */
kono
parents:
diff changeset
436 bool
kono
parents:
diff changeset
437 wi::eq_p_large (const HOST_WIDE_INT *op0, unsigned int op0len,
kono
parents:
diff changeset
438 const HOST_WIDE_INT *op1, unsigned int op1len,
kono
parents:
diff changeset
439 unsigned int prec)
kono
parents:
diff changeset
440 {
kono
parents:
diff changeset
441 int l0 = op0len - 1;
kono
parents:
diff changeset
442 unsigned int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
443
kono
parents:
diff changeset
444 if (op0len != op1len)
kono
parents:
diff changeset
445 return false;
kono
parents:
diff changeset
446
kono
parents:
diff changeset
447 if (op0len == BLOCKS_NEEDED (prec) && small_prec)
kono
parents:
diff changeset
448 {
kono
parents:
diff changeset
449 /* It does not matter if we zext or sext here, we just have to
kono
parents:
diff changeset
450 do both the same way. */
kono
parents:
diff changeset
451 if (zext_hwi (op0 [l0], small_prec) != zext_hwi (op1 [l0], small_prec))
kono
parents:
diff changeset
452 return false;
kono
parents:
diff changeset
453 l0--;
kono
parents:
diff changeset
454 }
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 while (l0 >= 0)
kono
parents:
diff changeset
457 if (op0[l0] != op1[l0])
kono
parents:
diff changeset
458 return false;
kono
parents:
diff changeset
459 else
kono
parents:
diff changeset
460 l0--;
kono
parents:
diff changeset
461
kono
parents:
diff changeset
462 return true;
kono
parents:
diff changeset
463 }
kono
parents:
diff changeset
464
kono
parents:
diff changeset
465 /* Return true if OP0 < OP1 using signed comparisons. */
kono
parents:
diff changeset
466 bool
kono
parents:
diff changeset
467 wi::lts_p_large (const HOST_WIDE_INT *op0, unsigned int op0len,
kono
parents:
diff changeset
468 unsigned int precision,
kono
parents:
diff changeset
469 const HOST_WIDE_INT *op1, unsigned int op1len)
kono
parents:
diff changeset
470 {
kono
parents:
diff changeset
471 HOST_WIDE_INT s0, s1;
kono
parents:
diff changeset
472 unsigned HOST_WIDE_INT u0, u1;
kono
parents:
diff changeset
473 unsigned int blocks_needed = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
474 unsigned int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
475 int l = MAX (op0len - 1, op1len - 1);
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 /* Only the top block is compared as signed. The rest are unsigned
kono
parents:
diff changeset
478 comparisons. */
kono
parents:
diff changeset
479 s0 = selt (op0, op0len, blocks_needed, small_prec, l, SIGNED);
kono
parents:
diff changeset
480 s1 = selt (op1, op1len, blocks_needed, small_prec, l, SIGNED);
kono
parents:
diff changeset
481 if (s0 < s1)
kono
parents:
diff changeset
482 return true;
kono
parents:
diff changeset
483 if (s0 > s1)
kono
parents:
diff changeset
484 return false;
kono
parents:
diff changeset
485
kono
parents:
diff changeset
486 l--;
kono
parents:
diff changeset
487 while (l >= 0)
kono
parents:
diff changeset
488 {
kono
parents:
diff changeset
489 u0 = selt (op0, op0len, blocks_needed, small_prec, l, SIGNED);
kono
parents:
diff changeset
490 u1 = selt (op1, op1len, blocks_needed, small_prec, l, SIGNED);
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 if (u0 < u1)
kono
parents:
diff changeset
493 return true;
kono
parents:
diff changeset
494 if (u0 > u1)
kono
parents:
diff changeset
495 return false;
kono
parents:
diff changeset
496 l--;
kono
parents:
diff changeset
497 }
kono
parents:
diff changeset
498
kono
parents:
diff changeset
499 return false;
kono
parents:
diff changeset
500 }
kono
parents:
diff changeset
501
kono
parents:
diff changeset
502 /* Returns -1 if OP0 < OP1, 0 if OP0 == OP1 and 1 if OP0 > OP1 using
kono
parents:
diff changeset
503 signed compares. */
kono
parents:
diff changeset
504 int
kono
parents:
diff changeset
505 wi::cmps_large (const HOST_WIDE_INT *op0, unsigned int op0len,
kono
parents:
diff changeset
506 unsigned int precision,
kono
parents:
diff changeset
507 const HOST_WIDE_INT *op1, unsigned int op1len)
kono
parents:
diff changeset
508 {
kono
parents:
diff changeset
509 HOST_WIDE_INT s0, s1;
kono
parents:
diff changeset
510 unsigned HOST_WIDE_INT u0, u1;
kono
parents:
diff changeset
511 unsigned int blocks_needed = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
512 unsigned int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
513 int l = MAX (op0len - 1, op1len - 1);
kono
parents:
diff changeset
514
kono
parents:
diff changeset
515 /* Only the top block is compared as signed. The rest are unsigned
kono
parents:
diff changeset
516 comparisons. */
kono
parents:
diff changeset
517 s0 = selt (op0, op0len, blocks_needed, small_prec, l, SIGNED);
kono
parents:
diff changeset
518 s1 = selt (op1, op1len, blocks_needed, small_prec, l, SIGNED);
kono
parents:
diff changeset
519 if (s0 < s1)
kono
parents:
diff changeset
520 return -1;
kono
parents:
diff changeset
521 if (s0 > s1)
kono
parents:
diff changeset
522 return 1;
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 l--;
kono
parents:
diff changeset
525 while (l >= 0)
kono
parents:
diff changeset
526 {
kono
parents:
diff changeset
527 u0 = selt (op0, op0len, blocks_needed, small_prec, l, SIGNED);
kono
parents:
diff changeset
528 u1 = selt (op1, op1len, blocks_needed, small_prec, l, SIGNED);
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 if (u0 < u1)
kono
parents:
diff changeset
531 return -1;
kono
parents:
diff changeset
532 if (u0 > u1)
kono
parents:
diff changeset
533 return 1;
kono
parents:
diff changeset
534 l--;
kono
parents:
diff changeset
535 }
kono
parents:
diff changeset
536
kono
parents:
diff changeset
537 return 0;
kono
parents:
diff changeset
538 }
kono
parents:
diff changeset
539
kono
parents:
diff changeset
540 /* Return true if OP0 < OP1 using unsigned comparisons. */
kono
parents:
diff changeset
541 bool
kono
parents:
diff changeset
542 wi::ltu_p_large (const HOST_WIDE_INT *op0, unsigned int op0len,
kono
parents:
diff changeset
543 unsigned int precision,
kono
parents:
diff changeset
544 const HOST_WIDE_INT *op1, unsigned int op1len)
kono
parents:
diff changeset
545 {
kono
parents:
diff changeset
546 unsigned HOST_WIDE_INT x0;
kono
parents:
diff changeset
547 unsigned HOST_WIDE_INT x1;
kono
parents:
diff changeset
548 unsigned int blocks_needed = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
549 unsigned int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
550 int l = MAX (op0len - 1, op1len - 1);
kono
parents:
diff changeset
551
kono
parents:
diff changeset
552 while (l >= 0)
kono
parents:
diff changeset
553 {
kono
parents:
diff changeset
554 x0 = selt (op0, op0len, blocks_needed, small_prec, l, UNSIGNED);
kono
parents:
diff changeset
555 x1 = selt (op1, op1len, blocks_needed, small_prec, l, UNSIGNED);
kono
parents:
diff changeset
556 if (x0 < x1)
kono
parents:
diff changeset
557 return true;
kono
parents:
diff changeset
558 if (x0 > x1)
kono
parents:
diff changeset
559 return false;
kono
parents:
diff changeset
560 l--;
kono
parents:
diff changeset
561 }
kono
parents:
diff changeset
562
kono
parents:
diff changeset
563 return false;
kono
parents:
diff changeset
564 }
kono
parents:
diff changeset
565
kono
parents:
diff changeset
566 /* Returns -1 if OP0 < OP1, 0 if OP0 == OP1 and 1 if OP0 > OP1 using
kono
parents:
diff changeset
567 unsigned compares. */
kono
parents:
diff changeset
568 int
kono
parents:
diff changeset
569 wi::cmpu_large (const HOST_WIDE_INT *op0, unsigned int op0len,
kono
parents:
diff changeset
570 unsigned int precision,
kono
parents:
diff changeset
571 const HOST_WIDE_INT *op1, unsigned int op1len)
kono
parents:
diff changeset
572 {
kono
parents:
diff changeset
573 unsigned HOST_WIDE_INT x0;
kono
parents:
diff changeset
574 unsigned HOST_WIDE_INT x1;
kono
parents:
diff changeset
575 unsigned int blocks_needed = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
576 unsigned int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
577 int l = MAX (op0len - 1, op1len - 1);
kono
parents:
diff changeset
578
kono
parents:
diff changeset
579 while (l >= 0)
kono
parents:
diff changeset
580 {
kono
parents:
diff changeset
581 x0 = selt (op0, op0len, blocks_needed, small_prec, l, UNSIGNED);
kono
parents:
diff changeset
582 x1 = selt (op1, op1len, blocks_needed, small_prec, l, UNSIGNED);
kono
parents:
diff changeset
583 if (x0 < x1)
kono
parents:
diff changeset
584 return -1;
kono
parents:
diff changeset
585 if (x0 > x1)
kono
parents:
diff changeset
586 return 1;
kono
parents:
diff changeset
587 l--;
kono
parents:
diff changeset
588 }
kono
parents:
diff changeset
589
kono
parents:
diff changeset
590 return 0;
kono
parents:
diff changeset
591 }
kono
parents:
diff changeset
592
kono
parents:
diff changeset
593 /*
kono
parents:
diff changeset
594 * Extension.
kono
parents:
diff changeset
595 */
kono
parents:
diff changeset
596
kono
parents:
diff changeset
597 /* Sign-extend the number represented by XVAL and XLEN into VAL,
kono
parents:
diff changeset
598 starting at OFFSET. Return the number of blocks in VAL. Both XVAL
kono
parents:
diff changeset
599 and VAL have PRECISION bits. */
kono
parents:
diff changeset
600 unsigned int
kono
parents:
diff changeset
601 wi::sext_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
602 unsigned int xlen, unsigned int precision, unsigned int offset)
kono
parents:
diff changeset
603 {
kono
parents:
diff changeset
604 unsigned int len = offset / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
605 /* Extending beyond the precision is a no-op. If we have only stored
kono
parents:
diff changeset
606 OFFSET bits or fewer, the rest are already signs. */
kono
parents:
diff changeset
607 if (offset >= precision || len >= xlen)
kono
parents:
diff changeset
608 {
kono
parents:
diff changeset
609 for (unsigned i = 0; i < xlen; ++i)
kono
parents:
diff changeset
610 val[i] = xval[i];
kono
parents:
diff changeset
611 return xlen;
kono
parents:
diff changeset
612 }
kono
parents:
diff changeset
613 unsigned int suboffset = offset % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
614 for (unsigned int i = 0; i < len; i++)
kono
parents:
diff changeset
615 val[i] = xval[i];
kono
parents:
diff changeset
616 if (suboffset > 0)
kono
parents:
diff changeset
617 {
kono
parents:
diff changeset
618 val[len] = sext_hwi (xval[len], suboffset);
kono
parents:
diff changeset
619 len += 1;
kono
parents:
diff changeset
620 }
kono
parents:
diff changeset
621 return canonize (val, len, precision);
kono
parents:
diff changeset
622 }
kono
parents:
diff changeset
623
kono
parents:
diff changeset
624 /* Zero-extend the number represented by XVAL and XLEN into VAL,
kono
parents:
diff changeset
625 starting at OFFSET. Return the number of blocks in VAL. Both XVAL
kono
parents:
diff changeset
626 and VAL have PRECISION bits. */
kono
parents:
diff changeset
627 unsigned int
kono
parents:
diff changeset
628 wi::zext_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
629 unsigned int xlen, unsigned int precision, unsigned int offset)
kono
parents:
diff changeset
630 {
kono
parents:
diff changeset
631 unsigned int len = offset / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
632 /* Extending beyond the precision is a no-op. If we have only stored
kono
parents:
diff changeset
633 OFFSET bits or fewer, and the upper stored bit is zero, then there
kono
parents:
diff changeset
634 is nothing to do. */
kono
parents:
diff changeset
635 if (offset >= precision || (len >= xlen && xval[xlen - 1] >= 0))
kono
parents:
diff changeset
636 {
kono
parents:
diff changeset
637 for (unsigned i = 0; i < xlen; ++i)
kono
parents:
diff changeset
638 val[i] = xval[i];
kono
parents:
diff changeset
639 return xlen;
kono
parents:
diff changeset
640 }
kono
parents:
diff changeset
641 unsigned int suboffset = offset % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
642 for (unsigned int i = 0; i < len; i++)
kono
parents:
diff changeset
643 val[i] = i < xlen ? xval[i] : -1;
kono
parents:
diff changeset
644 if (suboffset > 0)
kono
parents:
diff changeset
645 val[len] = zext_hwi (len < xlen ? xval[len] : -1, suboffset);
kono
parents:
diff changeset
646 else
kono
parents:
diff changeset
647 val[len] = 0;
kono
parents:
diff changeset
648 return canonize (val, len + 1, precision);
kono
parents:
diff changeset
649 }
kono
parents:
diff changeset
650
kono
parents:
diff changeset
651 /*
kono
parents:
diff changeset
652 * Masking, inserting, shifting, rotating.
kono
parents:
diff changeset
653 */
kono
parents:
diff changeset
654
kono
parents:
diff changeset
655 /* Insert WIDTH bits from Y into X starting at START. */
kono
parents:
diff changeset
656 wide_int
kono
parents:
diff changeset
657 wi::insert (const wide_int &x, const wide_int &y, unsigned int start,
kono
parents:
diff changeset
658 unsigned int width)
kono
parents:
diff changeset
659 {
kono
parents:
diff changeset
660 wide_int result;
kono
parents:
diff changeset
661 wide_int mask;
kono
parents:
diff changeset
662 wide_int tmp;
kono
parents:
diff changeset
663
kono
parents:
diff changeset
664 unsigned int precision = x.get_precision ();
kono
parents:
diff changeset
665 if (start >= precision)
kono
parents:
diff changeset
666 return x;
kono
parents:
diff changeset
667
kono
parents:
diff changeset
668 gcc_checking_assert (precision >= width);
kono
parents:
diff changeset
669
kono
parents:
diff changeset
670 if (start + width >= precision)
kono
parents:
diff changeset
671 width = precision - start;
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 mask = wi::shifted_mask (start, width, false, precision);
kono
parents:
diff changeset
674 tmp = wi::lshift (wide_int::from (y, precision, UNSIGNED), start);
kono
parents:
diff changeset
675 result = tmp & mask;
kono
parents:
diff changeset
676
kono
parents:
diff changeset
677 tmp = wi::bit_and_not (x, mask);
kono
parents:
diff changeset
678 result = result | tmp;
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 return result;
kono
parents:
diff changeset
681 }
kono
parents:
diff changeset
682
kono
parents:
diff changeset
683 /* Copy the number represented by XVAL and XLEN into VAL, setting bit BIT.
kono
parents:
diff changeset
684 Return the number of blocks in VAL. Both XVAL and VAL have PRECISION
kono
parents:
diff changeset
685 bits. */
kono
parents:
diff changeset
686 unsigned int
kono
parents:
diff changeset
687 wi::set_bit_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
688 unsigned int xlen, unsigned int precision, unsigned int bit)
kono
parents:
diff changeset
689 {
kono
parents:
diff changeset
690 unsigned int block = bit / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
691 unsigned int subbit = bit % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
692
kono
parents:
diff changeset
693 if (block + 1 >= xlen)
kono
parents:
diff changeset
694 {
kono
parents:
diff changeset
695 /* The operation either affects the last current block or needs
kono
parents:
diff changeset
696 a new block. */
kono
parents:
diff changeset
697 unsigned int len = block + 1;
kono
parents:
diff changeset
698 for (unsigned int i = 0; i < len; i++)
kono
parents:
diff changeset
699 val[i] = safe_uhwi (xval, xlen, i);
kono
parents:
diff changeset
700 val[block] |= HOST_WIDE_INT_1U << subbit;
kono
parents:
diff changeset
701
kono
parents:
diff changeset
702 /* If the bit we just set is at the msb of the block, make sure
kono
parents:
diff changeset
703 that any higher bits are zeros. */
kono
parents:
diff changeset
704 if (bit + 1 < precision && subbit == HOST_BITS_PER_WIDE_INT - 1)
kono
parents:
diff changeset
705 val[len++] = 0;
kono
parents:
diff changeset
706 return len;
kono
parents:
diff changeset
707 }
kono
parents:
diff changeset
708 else
kono
parents:
diff changeset
709 {
kono
parents:
diff changeset
710 for (unsigned int i = 0; i < xlen; i++)
kono
parents:
diff changeset
711 val[i] = xval[i];
kono
parents:
diff changeset
712 val[block] |= HOST_WIDE_INT_1U << subbit;
kono
parents:
diff changeset
713 return canonize (val, xlen, precision);
kono
parents:
diff changeset
714 }
kono
parents:
diff changeset
715 }
kono
parents:
diff changeset
716
kono
parents:
diff changeset
717 /* bswap THIS. */
kono
parents:
diff changeset
718 wide_int
kono
parents:
diff changeset
719 wide_int_storage::bswap () const
kono
parents:
diff changeset
720 {
kono
parents:
diff changeset
721 wide_int result = wide_int::create (precision);
kono
parents:
diff changeset
722 unsigned int i, s;
kono
parents:
diff changeset
723 unsigned int len = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
724 unsigned int xlen = get_len ();
kono
parents:
diff changeset
725 const HOST_WIDE_INT *xval = get_val ();
kono
parents:
diff changeset
726 HOST_WIDE_INT *val = result.write_val ();
kono
parents:
diff changeset
727
kono
parents:
diff changeset
728 /* This is not a well defined operation if the precision is not a
kono
parents:
diff changeset
729 multiple of 8. */
kono
parents:
diff changeset
730 gcc_assert ((precision & 0x7) == 0);
kono
parents:
diff changeset
731
kono
parents:
diff changeset
732 for (i = 0; i < len; i++)
kono
parents:
diff changeset
733 val[i] = 0;
kono
parents:
diff changeset
734
kono
parents:
diff changeset
735 /* Only swap the bytes that are not the padding. */
kono
parents:
diff changeset
736 for (s = 0; s < precision; s += 8)
kono
parents:
diff changeset
737 {
kono
parents:
diff changeset
738 unsigned int d = precision - s - 8;
kono
parents:
diff changeset
739 unsigned HOST_WIDE_INT byte;
kono
parents:
diff changeset
740
kono
parents:
diff changeset
741 unsigned int block = s / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
742 unsigned int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
743
kono
parents:
diff changeset
744 byte = (safe_uhwi (xval, xlen, block) >> offset) & 0xff;
kono
parents:
diff changeset
745
kono
parents:
diff changeset
746 block = d / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
747 offset = d & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
748
kono
parents:
diff changeset
749 val[block] |= byte << offset;
kono
parents:
diff changeset
750 }
kono
parents:
diff changeset
751
kono
parents:
diff changeset
752 result.set_len (canonize (val, len, precision));
kono
parents:
diff changeset
753 return result;
kono
parents:
diff changeset
754 }
kono
parents:
diff changeset
755
kono
parents:
diff changeset
756 /* Fill VAL with a mask where the lower WIDTH bits are ones and the bits
kono
parents:
diff changeset
757 above that up to PREC are zeros. The result is inverted if NEGATE
kono
parents:
diff changeset
758 is true. Return the number of blocks in VAL. */
kono
parents:
diff changeset
759 unsigned int
kono
parents:
diff changeset
760 wi::mask (HOST_WIDE_INT *val, unsigned int width, bool negate,
kono
parents:
diff changeset
761 unsigned int prec)
kono
parents:
diff changeset
762 {
kono
parents:
diff changeset
763 if (width >= prec)
kono
parents:
diff changeset
764 {
kono
parents:
diff changeset
765 val[0] = negate ? 0 : -1;
kono
parents:
diff changeset
766 return 1;
kono
parents:
diff changeset
767 }
kono
parents:
diff changeset
768 else if (width == 0)
kono
parents:
diff changeset
769 {
kono
parents:
diff changeset
770 val[0] = negate ? -1 : 0;
kono
parents:
diff changeset
771 return 1;
kono
parents:
diff changeset
772 }
kono
parents:
diff changeset
773
kono
parents:
diff changeset
774 unsigned int i = 0;
kono
parents:
diff changeset
775 while (i < width / HOST_BITS_PER_WIDE_INT)
kono
parents:
diff changeset
776 val[i++] = negate ? 0 : -1;
kono
parents:
diff changeset
777
kono
parents:
diff changeset
778 unsigned int shift = width & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
779 if (shift != 0)
kono
parents:
diff changeset
780 {
kono
parents:
diff changeset
781 HOST_WIDE_INT last = (HOST_WIDE_INT_1U << shift) - 1;
kono
parents:
diff changeset
782 val[i++] = negate ? ~last : last;
kono
parents:
diff changeset
783 }
kono
parents:
diff changeset
784 else
kono
parents:
diff changeset
785 val[i++] = negate ? -1 : 0;
kono
parents:
diff changeset
786
kono
parents:
diff changeset
787 return i;
kono
parents:
diff changeset
788 }
kono
parents:
diff changeset
789
kono
parents:
diff changeset
790 /* Fill VAL with a mask where the lower START bits are zeros, the next WIDTH
kono
parents:
diff changeset
791 bits are ones, and the bits above that up to PREC are zeros. The result
kono
parents:
diff changeset
792 is inverted if NEGATE is true. Return the number of blocks in VAL. */
kono
parents:
diff changeset
793 unsigned int
kono
parents:
diff changeset
794 wi::shifted_mask (HOST_WIDE_INT *val, unsigned int start, unsigned int width,
kono
parents:
diff changeset
795 bool negate, unsigned int prec)
kono
parents:
diff changeset
796 {
kono
parents:
diff changeset
797 if (start >= prec || width == 0)
kono
parents:
diff changeset
798 {
kono
parents:
diff changeset
799 val[0] = negate ? -1 : 0;
kono
parents:
diff changeset
800 return 1;
kono
parents:
diff changeset
801 }
kono
parents:
diff changeset
802
kono
parents:
diff changeset
803 if (width > prec - start)
kono
parents:
diff changeset
804 width = prec - start;
kono
parents:
diff changeset
805 unsigned int end = start + width;
kono
parents:
diff changeset
806
kono
parents:
diff changeset
807 unsigned int i = 0;
kono
parents:
diff changeset
808 while (i < start / HOST_BITS_PER_WIDE_INT)
kono
parents:
diff changeset
809 val[i++] = negate ? -1 : 0;
kono
parents:
diff changeset
810
kono
parents:
diff changeset
811 unsigned int shift = start & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
812 if (shift)
kono
parents:
diff changeset
813 {
kono
parents:
diff changeset
814 HOST_WIDE_INT block = (HOST_WIDE_INT_1U << shift) - 1;
kono
parents:
diff changeset
815 shift += width;
kono
parents:
diff changeset
816 if (shift < HOST_BITS_PER_WIDE_INT)
kono
parents:
diff changeset
817 {
kono
parents:
diff changeset
818 /* case 000111000 */
kono
parents:
diff changeset
819 block = (HOST_WIDE_INT_1U << shift) - block - 1;
kono
parents:
diff changeset
820 val[i++] = negate ? ~block : block;
kono
parents:
diff changeset
821 return i;
kono
parents:
diff changeset
822 }
kono
parents:
diff changeset
823 else
kono
parents:
diff changeset
824 /* ...111000 */
kono
parents:
diff changeset
825 val[i++] = negate ? block : ~block;
kono
parents:
diff changeset
826 }
kono
parents:
diff changeset
827
kono
parents:
diff changeset
828 while (i < end / HOST_BITS_PER_WIDE_INT)
kono
parents:
diff changeset
829 /* 1111111 */
kono
parents:
diff changeset
830 val[i++] = negate ? 0 : -1;
kono
parents:
diff changeset
831
kono
parents:
diff changeset
832 shift = end & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
833 if (shift != 0)
kono
parents:
diff changeset
834 {
kono
parents:
diff changeset
835 /* 000011111 */
kono
parents:
diff changeset
836 HOST_WIDE_INT block = (HOST_WIDE_INT_1U << shift) - 1;
kono
parents:
diff changeset
837 val[i++] = negate ? ~block : block;
kono
parents:
diff changeset
838 }
kono
parents:
diff changeset
839 else if (end < prec)
kono
parents:
diff changeset
840 val[i++] = negate ? -1 : 0;
kono
parents:
diff changeset
841
kono
parents:
diff changeset
842 return i;
kono
parents:
diff changeset
843 }
kono
parents:
diff changeset
844
kono
parents:
diff changeset
845 /*
kono
parents:
diff changeset
846 * logical operations.
kono
parents:
diff changeset
847 */
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 /* Set VAL to OP0 & OP1. Return the number of blocks used. */
kono
parents:
diff changeset
850 unsigned int
kono
parents:
diff changeset
851 wi::and_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
kono
parents:
diff changeset
852 unsigned int op0len, const HOST_WIDE_INT *op1,
kono
parents:
diff changeset
853 unsigned int op1len, unsigned int prec)
kono
parents:
diff changeset
854 {
kono
parents:
diff changeset
855 int l0 = op0len - 1;
kono
parents:
diff changeset
856 int l1 = op1len - 1;
kono
parents:
diff changeset
857 bool need_canon = true;
kono
parents:
diff changeset
858
kono
parents:
diff changeset
859 unsigned int len = MAX (op0len, op1len);
kono
parents:
diff changeset
860 if (l0 > l1)
kono
parents:
diff changeset
861 {
kono
parents:
diff changeset
862 HOST_WIDE_INT op1mask = -top_bit_of (op1, op1len, prec);
kono
parents:
diff changeset
863 if (op1mask == 0)
kono
parents:
diff changeset
864 {
kono
parents:
diff changeset
865 l0 = l1;
kono
parents:
diff changeset
866 len = l1 + 1;
kono
parents:
diff changeset
867 }
kono
parents:
diff changeset
868 else
kono
parents:
diff changeset
869 {
kono
parents:
diff changeset
870 need_canon = false;
kono
parents:
diff changeset
871 while (l0 > l1)
kono
parents:
diff changeset
872 {
kono
parents:
diff changeset
873 val[l0] = op0[l0];
kono
parents:
diff changeset
874 l0--;
kono
parents:
diff changeset
875 }
kono
parents:
diff changeset
876 }
kono
parents:
diff changeset
877 }
kono
parents:
diff changeset
878 else if (l1 > l0)
kono
parents:
diff changeset
879 {
kono
parents:
diff changeset
880 HOST_WIDE_INT op0mask = -top_bit_of (op0, op0len, prec);
kono
parents:
diff changeset
881 if (op0mask == 0)
kono
parents:
diff changeset
882 len = l0 + 1;
kono
parents:
diff changeset
883 else
kono
parents:
diff changeset
884 {
kono
parents:
diff changeset
885 need_canon = false;
kono
parents:
diff changeset
886 while (l1 > l0)
kono
parents:
diff changeset
887 {
kono
parents:
diff changeset
888 val[l1] = op1[l1];
kono
parents:
diff changeset
889 l1--;
kono
parents:
diff changeset
890 }
kono
parents:
diff changeset
891 }
kono
parents:
diff changeset
892 }
kono
parents:
diff changeset
893
kono
parents:
diff changeset
894 while (l0 >= 0)
kono
parents:
diff changeset
895 {
kono
parents:
diff changeset
896 val[l0] = op0[l0] & op1[l0];
kono
parents:
diff changeset
897 l0--;
kono
parents:
diff changeset
898 }
kono
parents:
diff changeset
899
kono
parents:
diff changeset
900 if (need_canon)
kono
parents:
diff changeset
901 len = canonize (val, len, prec);
kono
parents:
diff changeset
902
kono
parents:
diff changeset
903 return len;
kono
parents:
diff changeset
904 }
kono
parents:
diff changeset
905
kono
parents:
diff changeset
906 /* Set VAL to OP0 & ~OP1. Return the number of blocks used. */
kono
parents:
diff changeset
907 unsigned int
kono
parents:
diff changeset
908 wi::and_not_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
kono
parents:
diff changeset
909 unsigned int op0len, const HOST_WIDE_INT *op1,
kono
parents:
diff changeset
910 unsigned int op1len, unsigned int prec)
kono
parents:
diff changeset
911 {
kono
parents:
diff changeset
912 wide_int result;
kono
parents:
diff changeset
913 int l0 = op0len - 1;
kono
parents:
diff changeset
914 int l1 = op1len - 1;
kono
parents:
diff changeset
915 bool need_canon = true;
kono
parents:
diff changeset
916
kono
parents:
diff changeset
917 unsigned int len = MAX (op0len, op1len);
kono
parents:
diff changeset
918 if (l0 > l1)
kono
parents:
diff changeset
919 {
kono
parents:
diff changeset
920 HOST_WIDE_INT op1mask = -top_bit_of (op1, op1len, prec);
kono
parents:
diff changeset
921 if (op1mask != 0)
kono
parents:
diff changeset
922 {
kono
parents:
diff changeset
923 l0 = l1;
kono
parents:
diff changeset
924 len = l1 + 1;
kono
parents:
diff changeset
925 }
kono
parents:
diff changeset
926 else
kono
parents:
diff changeset
927 {
kono
parents:
diff changeset
928 need_canon = false;
kono
parents:
diff changeset
929 while (l0 > l1)
kono
parents:
diff changeset
930 {
kono
parents:
diff changeset
931 val[l0] = op0[l0];
kono
parents:
diff changeset
932 l0--;
kono
parents:
diff changeset
933 }
kono
parents:
diff changeset
934 }
kono
parents:
diff changeset
935 }
kono
parents:
diff changeset
936 else if (l1 > l0)
kono
parents:
diff changeset
937 {
kono
parents:
diff changeset
938 HOST_WIDE_INT op0mask = -top_bit_of (op0, op0len, prec);
kono
parents:
diff changeset
939 if (op0mask == 0)
kono
parents:
diff changeset
940 len = l0 + 1;
kono
parents:
diff changeset
941 else
kono
parents:
diff changeset
942 {
kono
parents:
diff changeset
943 need_canon = false;
kono
parents:
diff changeset
944 while (l1 > l0)
kono
parents:
diff changeset
945 {
kono
parents:
diff changeset
946 val[l1] = ~op1[l1];
kono
parents:
diff changeset
947 l1--;
kono
parents:
diff changeset
948 }
kono
parents:
diff changeset
949 }
kono
parents:
diff changeset
950 }
kono
parents:
diff changeset
951
kono
parents:
diff changeset
952 while (l0 >= 0)
kono
parents:
diff changeset
953 {
kono
parents:
diff changeset
954 val[l0] = op0[l0] & ~op1[l0];
kono
parents:
diff changeset
955 l0--;
kono
parents:
diff changeset
956 }
kono
parents:
diff changeset
957
kono
parents:
diff changeset
958 if (need_canon)
kono
parents:
diff changeset
959 len = canonize (val, len, prec);
kono
parents:
diff changeset
960
kono
parents:
diff changeset
961 return len;
kono
parents:
diff changeset
962 }
kono
parents:
diff changeset
963
kono
parents:
diff changeset
964 /* Set VAL to OP0 | OP1. Return the number of blocks used. */
kono
parents:
diff changeset
965 unsigned int
kono
parents:
diff changeset
966 wi::or_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
kono
parents:
diff changeset
967 unsigned int op0len, const HOST_WIDE_INT *op1,
kono
parents:
diff changeset
968 unsigned int op1len, unsigned int prec)
kono
parents:
diff changeset
969 {
kono
parents:
diff changeset
970 wide_int result;
kono
parents:
diff changeset
971 int l0 = op0len - 1;
kono
parents:
diff changeset
972 int l1 = op1len - 1;
kono
parents:
diff changeset
973 bool need_canon = true;
kono
parents:
diff changeset
974
kono
parents:
diff changeset
975 unsigned int len = MAX (op0len, op1len);
kono
parents:
diff changeset
976 if (l0 > l1)
kono
parents:
diff changeset
977 {
kono
parents:
diff changeset
978 HOST_WIDE_INT op1mask = -top_bit_of (op1, op1len, prec);
kono
parents:
diff changeset
979 if (op1mask != 0)
kono
parents:
diff changeset
980 {
kono
parents:
diff changeset
981 l0 = l1;
kono
parents:
diff changeset
982 len = l1 + 1;
kono
parents:
diff changeset
983 }
kono
parents:
diff changeset
984 else
kono
parents:
diff changeset
985 {
kono
parents:
diff changeset
986 need_canon = false;
kono
parents:
diff changeset
987 while (l0 > l1)
kono
parents:
diff changeset
988 {
kono
parents:
diff changeset
989 val[l0] = op0[l0];
kono
parents:
diff changeset
990 l0--;
kono
parents:
diff changeset
991 }
kono
parents:
diff changeset
992 }
kono
parents:
diff changeset
993 }
kono
parents:
diff changeset
994 else if (l1 > l0)
kono
parents:
diff changeset
995 {
kono
parents:
diff changeset
996 HOST_WIDE_INT op0mask = -top_bit_of (op0, op0len, prec);
kono
parents:
diff changeset
997 if (op0mask != 0)
kono
parents:
diff changeset
998 len = l0 + 1;
kono
parents:
diff changeset
999 else
kono
parents:
diff changeset
1000 {
kono
parents:
diff changeset
1001 need_canon = false;
kono
parents:
diff changeset
1002 while (l1 > l0)
kono
parents:
diff changeset
1003 {
kono
parents:
diff changeset
1004 val[l1] = op1[l1];
kono
parents:
diff changeset
1005 l1--;
kono
parents:
diff changeset
1006 }
kono
parents:
diff changeset
1007 }
kono
parents:
diff changeset
1008 }
kono
parents:
diff changeset
1009
kono
parents:
diff changeset
1010 while (l0 >= 0)
kono
parents:
diff changeset
1011 {
kono
parents:
diff changeset
1012 val[l0] = op0[l0] | op1[l0];
kono
parents:
diff changeset
1013 l0--;
kono
parents:
diff changeset
1014 }
kono
parents:
diff changeset
1015
kono
parents:
diff changeset
1016 if (need_canon)
kono
parents:
diff changeset
1017 len = canonize (val, len, prec);
kono
parents:
diff changeset
1018
kono
parents:
diff changeset
1019 return len;
kono
parents:
diff changeset
1020 }
kono
parents:
diff changeset
1021
kono
parents:
diff changeset
1022 /* Set VAL to OP0 | ~OP1. Return the number of blocks used. */
kono
parents:
diff changeset
1023 unsigned int
kono
parents:
diff changeset
1024 wi::or_not_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
kono
parents:
diff changeset
1025 unsigned int op0len, const HOST_WIDE_INT *op1,
kono
parents:
diff changeset
1026 unsigned int op1len, unsigned int prec)
kono
parents:
diff changeset
1027 {
kono
parents:
diff changeset
1028 wide_int result;
kono
parents:
diff changeset
1029 int l0 = op0len - 1;
kono
parents:
diff changeset
1030 int l1 = op1len - 1;
kono
parents:
diff changeset
1031 bool need_canon = true;
kono
parents:
diff changeset
1032
kono
parents:
diff changeset
1033 unsigned int len = MAX (op0len, op1len);
kono
parents:
diff changeset
1034 if (l0 > l1)
kono
parents:
diff changeset
1035 {
kono
parents:
diff changeset
1036 HOST_WIDE_INT op1mask = -top_bit_of (op1, op1len, prec);
kono
parents:
diff changeset
1037 if (op1mask == 0)
kono
parents:
diff changeset
1038 {
kono
parents:
diff changeset
1039 l0 = l1;
kono
parents:
diff changeset
1040 len = l1 + 1;
kono
parents:
diff changeset
1041 }
kono
parents:
diff changeset
1042 else
kono
parents:
diff changeset
1043 {
kono
parents:
diff changeset
1044 need_canon = false;
kono
parents:
diff changeset
1045 while (l0 > l1)
kono
parents:
diff changeset
1046 {
kono
parents:
diff changeset
1047 val[l0] = op0[l0];
kono
parents:
diff changeset
1048 l0--;
kono
parents:
diff changeset
1049 }
kono
parents:
diff changeset
1050 }
kono
parents:
diff changeset
1051 }
kono
parents:
diff changeset
1052 else if (l1 > l0)
kono
parents:
diff changeset
1053 {
kono
parents:
diff changeset
1054 HOST_WIDE_INT op0mask = -top_bit_of (op0, op0len, prec);
kono
parents:
diff changeset
1055 if (op0mask != 0)
kono
parents:
diff changeset
1056 len = l0 + 1;
kono
parents:
diff changeset
1057 else
kono
parents:
diff changeset
1058 {
kono
parents:
diff changeset
1059 need_canon = false;
kono
parents:
diff changeset
1060 while (l1 > l0)
kono
parents:
diff changeset
1061 {
kono
parents:
diff changeset
1062 val[l1] = ~op1[l1];
kono
parents:
diff changeset
1063 l1--;
kono
parents:
diff changeset
1064 }
kono
parents:
diff changeset
1065 }
kono
parents:
diff changeset
1066 }
kono
parents:
diff changeset
1067
kono
parents:
diff changeset
1068 while (l0 >= 0)
kono
parents:
diff changeset
1069 {
kono
parents:
diff changeset
1070 val[l0] = op0[l0] | ~op1[l0];
kono
parents:
diff changeset
1071 l0--;
kono
parents:
diff changeset
1072 }
kono
parents:
diff changeset
1073
kono
parents:
diff changeset
1074 if (need_canon)
kono
parents:
diff changeset
1075 len = canonize (val, len, prec);
kono
parents:
diff changeset
1076
kono
parents:
diff changeset
1077 return len;
kono
parents:
diff changeset
1078 }
kono
parents:
diff changeset
1079
kono
parents:
diff changeset
1080 /* Set VAL to OP0 ^ OP1. Return the number of blocks used. */
kono
parents:
diff changeset
1081 unsigned int
kono
parents:
diff changeset
1082 wi::xor_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
kono
parents:
diff changeset
1083 unsigned int op0len, const HOST_WIDE_INT *op1,
kono
parents:
diff changeset
1084 unsigned int op1len, unsigned int prec)
kono
parents:
diff changeset
1085 {
kono
parents:
diff changeset
1086 wide_int result;
kono
parents:
diff changeset
1087 int l0 = op0len - 1;
kono
parents:
diff changeset
1088 int l1 = op1len - 1;
kono
parents:
diff changeset
1089
kono
parents:
diff changeset
1090 unsigned int len = MAX (op0len, op1len);
kono
parents:
diff changeset
1091 if (l0 > l1)
kono
parents:
diff changeset
1092 {
kono
parents:
diff changeset
1093 HOST_WIDE_INT op1mask = -top_bit_of (op1, op1len, prec);
kono
parents:
diff changeset
1094 while (l0 > l1)
kono
parents:
diff changeset
1095 {
kono
parents:
diff changeset
1096 val[l0] = op0[l0] ^ op1mask;
kono
parents:
diff changeset
1097 l0--;
kono
parents:
diff changeset
1098 }
kono
parents:
diff changeset
1099 }
kono
parents:
diff changeset
1100
kono
parents:
diff changeset
1101 if (l1 > l0)
kono
parents:
diff changeset
1102 {
kono
parents:
diff changeset
1103 HOST_WIDE_INT op0mask = -top_bit_of (op0, op0len, prec);
kono
parents:
diff changeset
1104 while (l1 > l0)
kono
parents:
diff changeset
1105 {
kono
parents:
diff changeset
1106 val[l1] = op0mask ^ op1[l1];
kono
parents:
diff changeset
1107 l1--;
kono
parents:
diff changeset
1108 }
kono
parents:
diff changeset
1109 }
kono
parents:
diff changeset
1110
kono
parents:
diff changeset
1111 while (l0 >= 0)
kono
parents:
diff changeset
1112 {
kono
parents:
diff changeset
1113 val[l0] = op0[l0] ^ op1[l0];
kono
parents:
diff changeset
1114 l0--;
kono
parents:
diff changeset
1115 }
kono
parents:
diff changeset
1116
kono
parents:
diff changeset
1117 return canonize (val, len, prec);
kono
parents:
diff changeset
1118 }
kono
parents:
diff changeset
1119
kono
parents:
diff changeset
1120 /*
kono
parents:
diff changeset
1121 * math
kono
parents:
diff changeset
1122 */
kono
parents:
diff changeset
1123
kono
parents:
diff changeset
1124 /* Set VAL to OP0 + OP1. If OVERFLOW is nonnull, record in *OVERFLOW
kono
parents:
diff changeset
1125 whether the result overflows when OP0 and OP1 are treated as having
kono
parents:
diff changeset
1126 signedness SGN. Return the number of blocks in VAL. */
kono
parents:
diff changeset
1127 unsigned int
kono
parents:
diff changeset
1128 wi::add_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
kono
parents:
diff changeset
1129 unsigned int op0len, const HOST_WIDE_INT *op1,
kono
parents:
diff changeset
1130 unsigned int op1len, unsigned int prec,
kono
parents:
diff changeset
1131 signop sgn, bool *overflow)
kono
parents:
diff changeset
1132 {
kono
parents:
diff changeset
1133 unsigned HOST_WIDE_INT o0 = 0;
kono
parents:
diff changeset
1134 unsigned HOST_WIDE_INT o1 = 0;
kono
parents:
diff changeset
1135 unsigned HOST_WIDE_INT x = 0;
kono
parents:
diff changeset
1136 unsigned HOST_WIDE_INT carry = 0;
kono
parents:
diff changeset
1137 unsigned HOST_WIDE_INT old_carry = 0;
kono
parents:
diff changeset
1138 unsigned HOST_WIDE_INT mask0, mask1;
kono
parents:
diff changeset
1139 unsigned int i;
kono
parents:
diff changeset
1140
kono
parents:
diff changeset
1141 unsigned int len = MAX (op0len, op1len);
kono
parents:
diff changeset
1142 mask0 = -top_bit_of (op0, op0len, prec);
kono
parents:
diff changeset
1143 mask1 = -top_bit_of (op1, op1len, prec);
kono
parents:
diff changeset
1144 /* Add all of the explicitly defined elements. */
kono
parents:
diff changeset
1145
kono
parents:
diff changeset
1146 for (i = 0; i < len; i++)
kono
parents:
diff changeset
1147 {
kono
parents:
diff changeset
1148 o0 = i < op0len ? (unsigned HOST_WIDE_INT) op0[i] : mask0;
kono
parents:
diff changeset
1149 o1 = i < op1len ? (unsigned HOST_WIDE_INT) op1[i] : mask1;
kono
parents:
diff changeset
1150 x = o0 + o1 + carry;
kono
parents:
diff changeset
1151 val[i] = x;
kono
parents:
diff changeset
1152 old_carry = carry;
kono
parents:
diff changeset
1153 carry = carry == 0 ? x < o0 : x <= o0;
kono
parents:
diff changeset
1154 }
kono
parents:
diff changeset
1155
kono
parents:
diff changeset
1156 if (len * HOST_BITS_PER_WIDE_INT < prec)
kono
parents:
diff changeset
1157 {
kono
parents:
diff changeset
1158 val[len] = mask0 + mask1 + carry;
kono
parents:
diff changeset
1159 len++;
kono
parents:
diff changeset
1160 if (overflow)
kono
parents:
diff changeset
1161 *overflow = false;
kono
parents:
diff changeset
1162 }
kono
parents:
diff changeset
1163 else if (overflow)
kono
parents:
diff changeset
1164 {
kono
parents:
diff changeset
1165 unsigned int shift = -prec % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1166 if (sgn == SIGNED)
kono
parents:
diff changeset
1167 {
kono
parents:
diff changeset
1168 unsigned HOST_WIDE_INT x = (val[len - 1] ^ o0) & (val[len - 1] ^ o1);
kono
parents:
diff changeset
1169 *overflow = (HOST_WIDE_INT) (x << shift) < 0;
kono
parents:
diff changeset
1170 }
kono
parents:
diff changeset
1171 else
kono
parents:
diff changeset
1172 {
kono
parents:
diff changeset
1173 /* Put the MSB of X and O0 and in the top of the HWI. */
kono
parents:
diff changeset
1174 x <<= shift;
kono
parents:
diff changeset
1175 o0 <<= shift;
kono
parents:
diff changeset
1176 if (old_carry)
kono
parents:
diff changeset
1177 *overflow = (x <= o0);
kono
parents:
diff changeset
1178 else
kono
parents:
diff changeset
1179 *overflow = (x < o0);
kono
parents:
diff changeset
1180 }
kono
parents:
diff changeset
1181 }
kono
parents:
diff changeset
1182
kono
parents:
diff changeset
1183 return canonize (val, len, prec);
kono
parents:
diff changeset
1184 }
kono
parents:
diff changeset
1185
kono
parents:
diff changeset
1186 /* Subroutines of the multiplication and division operations. Unpack
kono
parents:
diff changeset
1187 the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
kono
parents:
diff changeset
1188 HOST_HALF_WIDE_INTs of RESULT. The rest of RESULT is filled by
kono
parents:
diff changeset
1189 uncompressing the top bit of INPUT[IN_LEN - 1]. */
kono
parents:
diff changeset
1190 static void
kono
parents:
diff changeset
1191 wi_unpack (unsigned HOST_HALF_WIDE_INT *result, const HOST_WIDE_INT *input,
kono
parents:
diff changeset
1192 unsigned int in_len, unsigned int out_len,
kono
parents:
diff changeset
1193 unsigned int prec, signop sgn)
kono
parents:
diff changeset
1194 {
kono
parents:
diff changeset
1195 unsigned int i;
kono
parents:
diff changeset
1196 unsigned int j = 0;
kono
parents:
diff changeset
1197 unsigned int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
1198 unsigned int blocks_needed = BLOCKS_NEEDED (prec);
kono
parents:
diff changeset
1199 HOST_WIDE_INT mask;
kono
parents:
diff changeset
1200
kono
parents:
diff changeset
1201 if (sgn == SIGNED)
kono
parents:
diff changeset
1202 {
kono
parents:
diff changeset
1203 mask = -top_bit_of ((const HOST_WIDE_INT *) input, in_len, prec);
kono
parents:
diff changeset
1204 mask &= HALF_INT_MASK;
kono
parents:
diff changeset
1205 }
kono
parents:
diff changeset
1206 else
kono
parents:
diff changeset
1207 mask = 0;
kono
parents:
diff changeset
1208
kono
parents:
diff changeset
1209 for (i = 0; i < blocks_needed - 1; i++)
kono
parents:
diff changeset
1210 {
kono
parents:
diff changeset
1211 HOST_WIDE_INT x = safe_uhwi (input, in_len, i);
kono
parents:
diff changeset
1212 result[j++] = x;
kono
parents:
diff changeset
1213 result[j++] = x >> HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1214 }
kono
parents:
diff changeset
1215
kono
parents:
diff changeset
1216 HOST_WIDE_INT x = safe_uhwi (input, in_len, i);
kono
parents:
diff changeset
1217 if (small_prec)
kono
parents:
diff changeset
1218 {
kono
parents:
diff changeset
1219 if (sgn == SIGNED)
kono
parents:
diff changeset
1220 x = sext_hwi (x, small_prec);
kono
parents:
diff changeset
1221 else
kono
parents:
diff changeset
1222 x = zext_hwi (x, small_prec);
kono
parents:
diff changeset
1223 }
kono
parents:
diff changeset
1224 result[j++] = x;
kono
parents:
diff changeset
1225 result[j++] = x >> HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1226
kono
parents:
diff changeset
1227 /* Smear the sign bit. */
kono
parents:
diff changeset
1228 while (j < out_len)
kono
parents:
diff changeset
1229 result[j++] = mask;
kono
parents:
diff changeset
1230 }
kono
parents:
diff changeset
1231
kono
parents:
diff changeset
1232 /* The inverse of wi_unpack. IN_LEN is the number of input
kono
parents:
diff changeset
1233 blocks and PRECISION is the precision of the result. Return the
kono
parents:
diff changeset
1234 number of blocks in the canonicalized result. */
kono
parents:
diff changeset
1235 static unsigned int
kono
parents:
diff changeset
1236 wi_pack (HOST_WIDE_INT *result,
kono
parents:
diff changeset
1237 const unsigned HOST_HALF_WIDE_INT *input,
kono
parents:
diff changeset
1238 unsigned int in_len, unsigned int precision)
kono
parents:
diff changeset
1239 {
kono
parents:
diff changeset
1240 unsigned int i = 0;
kono
parents:
diff changeset
1241 unsigned int j = 0;
kono
parents:
diff changeset
1242 unsigned int blocks_needed = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
1243
kono
parents:
diff changeset
1244 while (i + 1 < in_len)
kono
parents:
diff changeset
1245 {
kono
parents:
diff changeset
1246 result[j++] = ((unsigned HOST_WIDE_INT) input[i]
kono
parents:
diff changeset
1247 | ((unsigned HOST_WIDE_INT) input[i + 1]
kono
parents:
diff changeset
1248 << HOST_BITS_PER_HALF_WIDE_INT));
kono
parents:
diff changeset
1249 i += 2;
kono
parents:
diff changeset
1250 }
kono
parents:
diff changeset
1251
kono
parents:
diff changeset
1252 /* Handle the case where in_len is odd. For this we zero extend. */
kono
parents:
diff changeset
1253 if (in_len & 1)
kono
parents:
diff changeset
1254 result[j++] = (unsigned HOST_WIDE_INT) input[i];
kono
parents:
diff changeset
1255 else if (j < blocks_needed)
kono
parents:
diff changeset
1256 result[j++] = 0;
kono
parents:
diff changeset
1257 return canonize (result, j, precision);
kono
parents:
diff changeset
1258 }
kono
parents:
diff changeset
1259
kono
parents:
diff changeset
1260 /* Multiply Op1 by Op2. If HIGH is set, only the upper half of the
kono
parents:
diff changeset
1261 result is returned.
kono
parents:
diff changeset
1262
kono
parents:
diff changeset
1263 If HIGH is not set, throw away the upper half after the check is
kono
parents:
diff changeset
1264 made to see if it overflows. Unfortunately there is no better way
kono
parents:
diff changeset
1265 to check for overflow than to do this. If OVERFLOW is nonnull,
kono
parents:
diff changeset
1266 record in *OVERFLOW whether the result overflowed. SGN controls
kono
parents:
diff changeset
1267 the signedness and is used to check overflow or if HIGH is set. */
kono
parents:
diff changeset
1268 unsigned int
kono
parents:
diff changeset
1269 wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val,
kono
parents:
diff changeset
1270 unsigned int op1len, const HOST_WIDE_INT *op2val,
kono
parents:
diff changeset
1271 unsigned int op2len, unsigned int prec, signop sgn,
kono
parents:
diff changeset
1272 bool *overflow, bool high)
kono
parents:
diff changeset
1273 {
kono
parents:
diff changeset
1274 unsigned HOST_WIDE_INT o0, o1, k, t;
kono
parents:
diff changeset
1275 unsigned int i;
kono
parents:
diff changeset
1276 unsigned int j;
kono
parents:
diff changeset
1277 unsigned int blocks_needed = BLOCKS_NEEDED (prec);
kono
parents:
diff changeset
1278 unsigned int half_blocks_needed = blocks_needed * 2;
kono
parents:
diff changeset
1279 /* The sizes here are scaled to support a 2x largest mode by 2x
kono
parents:
diff changeset
1280 largest mode yielding a 4x largest mode result. This is what is
kono
parents:
diff changeset
1281 needed by vpn. */
kono
parents:
diff changeset
1282
kono
parents:
diff changeset
1283 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1284 u[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1285 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1286 v[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1287 /* The '2' in 'R' is because we are internally doing a full
kono
parents:
diff changeset
1288 multiply. */
kono
parents:
diff changeset
1289 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1290 r[2 * 4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1291 HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
kono
parents:
diff changeset
1292
kono
parents:
diff changeset
1293 /* If the top level routine did not really pass in an overflow, then
kono
parents:
diff changeset
1294 just make sure that we never attempt to set it. */
kono
parents:
diff changeset
1295 bool needs_overflow = (overflow != 0);
kono
parents:
diff changeset
1296 if (needs_overflow)
kono
parents:
diff changeset
1297 *overflow = false;
kono
parents:
diff changeset
1298
kono
parents:
diff changeset
1299 wide_int_ref op1 = wi::storage_ref (op1val, op1len, prec);
kono
parents:
diff changeset
1300 wide_int_ref op2 = wi::storage_ref (op2val, op2len, prec);
kono
parents:
diff changeset
1301
kono
parents:
diff changeset
1302 /* This is a surprisingly common case, so do it first. */
kono
parents:
diff changeset
1303 if (op1 == 0 || op2 == 0)
kono
parents:
diff changeset
1304 {
kono
parents:
diff changeset
1305 val[0] = 0;
kono
parents:
diff changeset
1306 return 1;
kono
parents:
diff changeset
1307 }
kono
parents:
diff changeset
1308
kono
parents:
diff changeset
1309 #ifdef umul_ppmm
kono
parents:
diff changeset
1310 if (sgn == UNSIGNED)
kono
parents:
diff changeset
1311 {
kono
parents:
diff changeset
1312 /* If the inputs are single HWIs and the output has room for at
kono
parents:
diff changeset
1313 least two HWIs, we can use umul_ppmm directly. */
kono
parents:
diff changeset
1314 if (prec >= HOST_BITS_PER_WIDE_INT * 2
kono
parents:
diff changeset
1315 && wi::fits_uhwi_p (op1)
kono
parents:
diff changeset
1316 && wi::fits_uhwi_p (op2))
kono
parents:
diff changeset
1317 {
kono
parents:
diff changeset
1318 /* This case never overflows. */
kono
parents:
diff changeset
1319 if (high)
kono
parents:
diff changeset
1320 {
kono
parents:
diff changeset
1321 val[0] = 0;
kono
parents:
diff changeset
1322 return 1;
kono
parents:
diff changeset
1323 }
kono
parents:
diff changeset
1324 umul_ppmm (val[1], val[0], op1.ulow (), op2.ulow ());
kono
parents:
diff changeset
1325 if (val[1] < 0 && prec > HOST_BITS_PER_WIDE_INT * 2)
kono
parents:
diff changeset
1326 {
kono
parents:
diff changeset
1327 val[2] = 0;
kono
parents:
diff changeset
1328 return 3;
kono
parents:
diff changeset
1329 }
kono
parents:
diff changeset
1330 return 1 + (val[1] != 0 || val[0] < 0);
kono
parents:
diff changeset
1331 }
kono
parents:
diff changeset
1332 /* Likewise if the output is a full single HWI, except that the
kono
parents:
diff changeset
1333 upper HWI of the result is only used for determining overflow.
kono
parents:
diff changeset
1334 (We handle this case inline when overflow isn't needed.) */
kono
parents:
diff changeset
1335 else if (prec == HOST_BITS_PER_WIDE_INT)
kono
parents:
diff changeset
1336 {
kono
parents:
diff changeset
1337 unsigned HOST_WIDE_INT upper;
kono
parents:
diff changeset
1338 umul_ppmm (upper, val[0], op1.ulow (), op2.ulow ());
kono
parents:
diff changeset
1339 if (needs_overflow)
kono
parents:
diff changeset
1340 *overflow = (upper != 0);
kono
parents:
diff changeset
1341 if (high)
kono
parents:
diff changeset
1342 val[0] = upper;
kono
parents:
diff changeset
1343 return 1;
kono
parents:
diff changeset
1344 }
kono
parents:
diff changeset
1345 }
kono
parents:
diff changeset
1346 #endif
kono
parents:
diff changeset
1347
kono
parents:
diff changeset
1348 /* Handle multiplications by 1. */
kono
parents:
diff changeset
1349 if (op1 == 1)
kono
parents:
diff changeset
1350 {
kono
parents:
diff changeset
1351 if (high)
kono
parents:
diff changeset
1352 {
kono
parents:
diff changeset
1353 val[0] = wi::neg_p (op2, sgn) ? -1 : 0;
kono
parents:
diff changeset
1354 return 1;
kono
parents:
diff changeset
1355 }
kono
parents:
diff changeset
1356 for (i = 0; i < op2len; i++)
kono
parents:
diff changeset
1357 val[i] = op2val[i];
kono
parents:
diff changeset
1358 return op2len;
kono
parents:
diff changeset
1359 }
kono
parents:
diff changeset
1360 if (op2 == 1)
kono
parents:
diff changeset
1361 {
kono
parents:
diff changeset
1362 if (high)
kono
parents:
diff changeset
1363 {
kono
parents:
diff changeset
1364 val[0] = wi::neg_p (op1, sgn) ? -1 : 0;
kono
parents:
diff changeset
1365 return 1;
kono
parents:
diff changeset
1366 }
kono
parents:
diff changeset
1367 for (i = 0; i < op1len; i++)
kono
parents:
diff changeset
1368 val[i] = op1val[i];
kono
parents:
diff changeset
1369 return op1len;
kono
parents:
diff changeset
1370 }
kono
parents:
diff changeset
1371
kono
parents:
diff changeset
1372 /* If we need to check for overflow, we can only do half wide
kono
parents:
diff changeset
1373 multiplies quickly because we need to look at the top bits to
kono
parents:
diff changeset
1374 check for the overflow. */
kono
parents:
diff changeset
1375 if ((high || needs_overflow)
kono
parents:
diff changeset
1376 && (prec <= HOST_BITS_PER_HALF_WIDE_INT))
kono
parents:
diff changeset
1377 {
kono
parents:
diff changeset
1378 unsigned HOST_WIDE_INT r;
kono
parents:
diff changeset
1379
kono
parents:
diff changeset
1380 if (sgn == SIGNED)
kono
parents:
diff changeset
1381 {
kono
parents:
diff changeset
1382 o0 = op1.to_shwi ();
kono
parents:
diff changeset
1383 o1 = op2.to_shwi ();
kono
parents:
diff changeset
1384 }
kono
parents:
diff changeset
1385 else
kono
parents:
diff changeset
1386 {
kono
parents:
diff changeset
1387 o0 = op1.to_uhwi ();
kono
parents:
diff changeset
1388 o1 = op2.to_uhwi ();
kono
parents:
diff changeset
1389 }
kono
parents:
diff changeset
1390
kono
parents:
diff changeset
1391 r = o0 * o1;
kono
parents:
diff changeset
1392 if (needs_overflow)
kono
parents:
diff changeset
1393 {
kono
parents:
diff changeset
1394 if (sgn == SIGNED)
kono
parents:
diff changeset
1395 {
kono
parents:
diff changeset
1396 if ((HOST_WIDE_INT) r != sext_hwi (r, prec))
kono
parents:
diff changeset
1397 *overflow = true;
kono
parents:
diff changeset
1398 }
kono
parents:
diff changeset
1399 else
kono
parents:
diff changeset
1400 {
kono
parents:
diff changeset
1401 if ((r >> prec) != 0)
kono
parents:
diff changeset
1402 *overflow = true;
kono
parents:
diff changeset
1403 }
kono
parents:
diff changeset
1404 }
kono
parents:
diff changeset
1405 val[0] = high ? r >> prec : r;
kono
parents:
diff changeset
1406 return 1;
kono
parents:
diff changeset
1407 }
kono
parents:
diff changeset
1408
kono
parents:
diff changeset
1409 /* We do unsigned mul and then correct it. */
kono
parents:
diff changeset
1410 wi_unpack (u, op1val, op1len, half_blocks_needed, prec, SIGNED);
kono
parents:
diff changeset
1411 wi_unpack (v, op2val, op2len, half_blocks_needed, prec, SIGNED);
kono
parents:
diff changeset
1412
kono
parents:
diff changeset
1413 /* The 2 is for a full mult. */
kono
parents:
diff changeset
1414 memset (r, 0, half_blocks_needed * 2
kono
parents:
diff changeset
1415 * HOST_BITS_PER_HALF_WIDE_INT / CHAR_BIT);
kono
parents:
diff changeset
1416
kono
parents:
diff changeset
1417 for (j = 0; j < half_blocks_needed; j++)
kono
parents:
diff changeset
1418 {
kono
parents:
diff changeset
1419 k = 0;
kono
parents:
diff changeset
1420 for (i = 0; i < half_blocks_needed; i++)
kono
parents:
diff changeset
1421 {
kono
parents:
diff changeset
1422 t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
kono
parents:
diff changeset
1423 + r[i + j] + k);
kono
parents:
diff changeset
1424 r[i + j] = t & HALF_INT_MASK;
kono
parents:
diff changeset
1425 k = t >> HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1426 }
kono
parents:
diff changeset
1427 r[j + half_blocks_needed] = k;
kono
parents:
diff changeset
1428 }
kono
parents:
diff changeset
1429
kono
parents:
diff changeset
1430 /* We did unsigned math above. For signed we must adjust the
kono
parents:
diff changeset
1431 product (assuming we need to see that). */
kono
parents:
diff changeset
1432 if (sgn == SIGNED && (high || needs_overflow))
kono
parents:
diff changeset
1433 {
kono
parents:
diff changeset
1434 unsigned HOST_WIDE_INT b;
kono
parents:
diff changeset
1435 if (wi::neg_p (op1))
kono
parents:
diff changeset
1436 {
kono
parents:
diff changeset
1437 b = 0;
kono
parents:
diff changeset
1438 for (i = 0; i < half_blocks_needed; i++)
kono
parents:
diff changeset
1439 {
kono
parents:
diff changeset
1440 t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
kono
parents:
diff changeset
1441 - (unsigned HOST_WIDE_INT)v[i] - b;
kono
parents:
diff changeset
1442 r[i + half_blocks_needed] = t & HALF_INT_MASK;
kono
parents:
diff changeset
1443 b = t >> (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
1444 }
kono
parents:
diff changeset
1445 }
kono
parents:
diff changeset
1446 if (wi::neg_p (op2))
kono
parents:
diff changeset
1447 {
kono
parents:
diff changeset
1448 b = 0;
kono
parents:
diff changeset
1449 for (i = 0; i < half_blocks_needed; i++)
kono
parents:
diff changeset
1450 {
kono
parents:
diff changeset
1451 t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
kono
parents:
diff changeset
1452 - (unsigned HOST_WIDE_INT)u[i] - b;
kono
parents:
diff changeset
1453 r[i + half_blocks_needed] = t & HALF_INT_MASK;
kono
parents:
diff changeset
1454 b = t >> (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
1455 }
kono
parents:
diff changeset
1456 }
kono
parents:
diff changeset
1457 }
kono
parents:
diff changeset
1458
kono
parents:
diff changeset
1459 if (needs_overflow)
kono
parents:
diff changeset
1460 {
kono
parents:
diff changeset
1461 HOST_WIDE_INT top;
kono
parents:
diff changeset
1462
kono
parents:
diff changeset
1463 /* For unsigned, overflow is true if any of the top bits are set.
kono
parents:
diff changeset
1464 For signed, overflow is true if any of the top bits are not equal
kono
parents:
diff changeset
1465 to the sign bit. */
kono
parents:
diff changeset
1466 if (sgn == UNSIGNED)
kono
parents:
diff changeset
1467 top = 0;
kono
parents:
diff changeset
1468 else
kono
parents:
diff changeset
1469 {
kono
parents:
diff changeset
1470 top = r[(half_blocks_needed) - 1];
kono
parents:
diff changeset
1471 top = SIGN_MASK (top << (HOST_BITS_PER_WIDE_INT / 2));
kono
parents:
diff changeset
1472 top &= mask;
kono
parents:
diff changeset
1473 }
kono
parents:
diff changeset
1474
kono
parents:
diff changeset
1475 for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
kono
parents:
diff changeset
1476 if (((HOST_WIDE_INT)(r[i] & mask)) != top)
kono
parents:
diff changeset
1477 *overflow = true;
kono
parents:
diff changeset
1478 }
kono
parents:
diff changeset
1479
kono
parents:
diff changeset
1480 int r_offset = high ? half_blocks_needed : 0;
kono
parents:
diff changeset
1481 return wi_pack (val, &r[r_offset], half_blocks_needed, prec);
kono
parents:
diff changeset
1482 }
kono
parents:
diff changeset
1483
kono
parents:
diff changeset
1484 /* Compute the population count of X. */
kono
parents:
diff changeset
1485 int
kono
parents:
diff changeset
1486 wi::popcount (const wide_int_ref &x)
kono
parents:
diff changeset
1487 {
kono
parents:
diff changeset
1488 unsigned int i;
kono
parents:
diff changeset
1489 int count;
kono
parents:
diff changeset
1490
kono
parents:
diff changeset
1491 /* The high order block is special if it is the last block and the
kono
parents:
diff changeset
1492 precision is not an even multiple of HOST_BITS_PER_WIDE_INT. We
kono
parents:
diff changeset
1493 have to clear out any ones above the precision before doing
kono
parents:
diff changeset
1494 popcount on this block. */
kono
parents:
diff changeset
1495 count = x.precision - x.len * HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1496 unsigned int stop = x.len;
kono
parents:
diff changeset
1497 if (count < 0)
kono
parents:
diff changeset
1498 {
kono
parents:
diff changeset
1499 count = popcount_hwi (x.uhigh () << -count);
kono
parents:
diff changeset
1500 stop -= 1;
kono
parents:
diff changeset
1501 }
kono
parents:
diff changeset
1502 else
kono
parents:
diff changeset
1503 {
kono
parents:
diff changeset
1504 if (x.sign_mask () >= 0)
kono
parents:
diff changeset
1505 count = 0;
kono
parents:
diff changeset
1506 }
kono
parents:
diff changeset
1507
kono
parents:
diff changeset
1508 for (i = 0; i < stop; ++i)
kono
parents:
diff changeset
1509 count += popcount_hwi (x.val[i]);
kono
parents:
diff changeset
1510
kono
parents:
diff changeset
1511 return count;
kono
parents:
diff changeset
1512 }
kono
parents:
diff changeset
1513
kono
parents:
diff changeset
1514 /* Set VAL to OP0 - OP1. If OVERFLOW is nonnull, record in *OVERFLOW
kono
parents:
diff changeset
1515 whether the result overflows when OP0 and OP1 are treated as having
kono
parents:
diff changeset
1516 signedness SGN. Return the number of blocks in VAL. */
kono
parents:
diff changeset
1517 unsigned int
kono
parents:
diff changeset
1518 wi::sub_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
kono
parents:
diff changeset
1519 unsigned int op0len, const HOST_WIDE_INT *op1,
kono
parents:
diff changeset
1520 unsigned int op1len, unsigned int prec,
kono
parents:
diff changeset
1521 signop sgn, bool *overflow)
kono
parents:
diff changeset
1522 {
kono
parents:
diff changeset
1523 unsigned HOST_WIDE_INT o0 = 0;
kono
parents:
diff changeset
1524 unsigned HOST_WIDE_INT o1 = 0;
kono
parents:
diff changeset
1525 unsigned HOST_WIDE_INT x = 0;
kono
parents:
diff changeset
1526 /* We implement subtraction as an in place negate and add. Negation
kono
parents:
diff changeset
1527 is just inversion and add 1, so we can do the add of 1 by just
kono
parents:
diff changeset
1528 starting the borrow in of the first element at 1. */
kono
parents:
diff changeset
1529 unsigned HOST_WIDE_INT borrow = 0;
kono
parents:
diff changeset
1530 unsigned HOST_WIDE_INT old_borrow = 0;
kono
parents:
diff changeset
1531
kono
parents:
diff changeset
1532 unsigned HOST_WIDE_INT mask0, mask1;
kono
parents:
diff changeset
1533 unsigned int i;
kono
parents:
diff changeset
1534
kono
parents:
diff changeset
1535 unsigned int len = MAX (op0len, op1len);
kono
parents:
diff changeset
1536 mask0 = -top_bit_of (op0, op0len, prec);
kono
parents:
diff changeset
1537 mask1 = -top_bit_of (op1, op1len, prec);
kono
parents:
diff changeset
1538
kono
parents:
diff changeset
1539 /* Subtract all of the explicitly defined elements. */
kono
parents:
diff changeset
1540 for (i = 0; i < len; i++)
kono
parents:
diff changeset
1541 {
kono
parents:
diff changeset
1542 o0 = i < op0len ? (unsigned HOST_WIDE_INT)op0[i] : mask0;
kono
parents:
diff changeset
1543 o1 = i < op1len ? (unsigned HOST_WIDE_INT)op1[i] : mask1;
kono
parents:
diff changeset
1544 x = o0 - o1 - borrow;
kono
parents:
diff changeset
1545 val[i] = x;
kono
parents:
diff changeset
1546 old_borrow = borrow;
kono
parents:
diff changeset
1547 borrow = borrow == 0 ? o0 < o1 : o0 <= o1;
kono
parents:
diff changeset
1548 }
kono
parents:
diff changeset
1549
kono
parents:
diff changeset
1550 if (len * HOST_BITS_PER_WIDE_INT < prec)
kono
parents:
diff changeset
1551 {
kono
parents:
diff changeset
1552 val[len] = mask0 - mask1 - borrow;
kono
parents:
diff changeset
1553 len++;
kono
parents:
diff changeset
1554 if (overflow)
kono
parents:
diff changeset
1555 *overflow = false;
kono
parents:
diff changeset
1556 }
kono
parents:
diff changeset
1557 else if (overflow)
kono
parents:
diff changeset
1558 {
kono
parents:
diff changeset
1559 unsigned int shift = -prec % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1560 if (sgn == SIGNED)
kono
parents:
diff changeset
1561 {
kono
parents:
diff changeset
1562 unsigned HOST_WIDE_INT x = (o0 ^ o1) & (val[len - 1] ^ o0);
kono
parents:
diff changeset
1563 *overflow = (HOST_WIDE_INT) (x << shift) < 0;
kono
parents:
diff changeset
1564 }
kono
parents:
diff changeset
1565 else
kono
parents:
diff changeset
1566 {
kono
parents:
diff changeset
1567 /* Put the MSB of X and O0 and in the top of the HWI. */
kono
parents:
diff changeset
1568 x <<= shift;
kono
parents:
diff changeset
1569 o0 <<= shift;
kono
parents:
diff changeset
1570 if (old_borrow)
kono
parents:
diff changeset
1571 *overflow = (x >= o0);
kono
parents:
diff changeset
1572 else
kono
parents:
diff changeset
1573 *overflow = (x > o0);
kono
parents:
diff changeset
1574 }
kono
parents:
diff changeset
1575 }
kono
parents:
diff changeset
1576
kono
parents:
diff changeset
1577 return canonize (val, len, prec);
kono
parents:
diff changeset
1578 }
kono
parents:
diff changeset
1579
kono
parents:
diff changeset
1580
kono
parents:
diff changeset
1581 /*
kono
parents:
diff changeset
1582 * Division and Mod
kono
parents:
diff changeset
1583 */
kono
parents:
diff changeset
1584
kono
parents:
diff changeset
1585 /* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR. The
kono
parents:
diff changeset
1586 algorithm is a small modification of the algorithm in Hacker's
kono
parents:
diff changeset
1587 Delight by Warren, which itself is a small modification of Knuth's
kono
parents:
diff changeset
1588 algorithm. M is the number of significant elements of U however
kono
parents:
diff changeset
1589 there needs to be at least one extra element of B_DIVIDEND
kono
parents:
diff changeset
1590 allocated, N is the number of elements of B_DIVISOR. */
kono
parents:
diff changeset
1591 static void
kono
parents:
diff changeset
1592 divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient,
kono
parents:
diff changeset
1593 unsigned HOST_HALF_WIDE_INT *b_remainder,
kono
parents:
diff changeset
1594 unsigned HOST_HALF_WIDE_INT *b_dividend,
kono
parents:
diff changeset
1595 unsigned HOST_HALF_WIDE_INT *b_divisor,
kono
parents:
diff changeset
1596 int m, int n)
kono
parents:
diff changeset
1597 {
kono
parents:
diff changeset
1598 /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
kono
parents:
diff changeset
1599 HOST_WIDE_INT and stored in the lower bits of each word. This
kono
parents:
diff changeset
1600 algorithm should work properly on both 32 and 64 bit
kono
parents:
diff changeset
1601 machines. */
kono
parents:
diff changeset
1602 unsigned HOST_WIDE_INT b
kono
parents:
diff changeset
1603 = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1604 unsigned HOST_WIDE_INT qhat; /* Estimate of quotient digit. */
kono
parents:
diff changeset
1605 unsigned HOST_WIDE_INT rhat; /* A remainder. */
kono
parents:
diff changeset
1606 unsigned HOST_WIDE_INT p; /* Product of two digits. */
kono
parents:
diff changeset
1607 HOST_WIDE_INT t, k;
kono
parents:
diff changeset
1608 int i, j, s;
kono
parents:
diff changeset
1609
kono
parents:
diff changeset
1610 /* Single digit divisor. */
kono
parents:
diff changeset
1611 if (n == 1)
kono
parents:
diff changeset
1612 {
kono
parents:
diff changeset
1613 k = 0;
kono
parents:
diff changeset
1614 for (j = m - 1; j >= 0; j--)
kono
parents:
diff changeset
1615 {
kono
parents:
diff changeset
1616 b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
kono
parents:
diff changeset
1617 k = ((k * b + b_dividend[j])
kono
parents:
diff changeset
1618 - ((unsigned HOST_WIDE_INT)b_quotient[j]
kono
parents:
diff changeset
1619 * (unsigned HOST_WIDE_INT)b_divisor[0]));
kono
parents:
diff changeset
1620 }
kono
parents:
diff changeset
1621 b_remainder[0] = k;
kono
parents:
diff changeset
1622 return;
kono
parents:
diff changeset
1623 }
kono
parents:
diff changeset
1624
kono
parents:
diff changeset
1625 s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
kono
parents:
diff changeset
1626
kono
parents:
diff changeset
1627 if (s)
kono
parents:
diff changeset
1628 {
kono
parents:
diff changeset
1629 /* Normalize B_DIVIDEND and B_DIVISOR. Unlike the published
kono
parents:
diff changeset
1630 algorithm, we can overwrite b_dividend and b_divisor, so we do
kono
parents:
diff changeset
1631 that. */
kono
parents:
diff changeset
1632 for (i = n - 1; i > 0; i--)
kono
parents:
diff changeset
1633 b_divisor[i] = (b_divisor[i] << s)
kono
parents:
diff changeset
1634 | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
kono
parents:
diff changeset
1635 b_divisor[0] = b_divisor[0] << s;
kono
parents:
diff changeset
1636
kono
parents:
diff changeset
1637 b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
kono
parents:
diff changeset
1638 for (i = m - 1; i > 0; i--)
kono
parents:
diff changeset
1639 b_dividend[i] = (b_dividend[i] << s)
kono
parents:
diff changeset
1640 | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
kono
parents:
diff changeset
1641 b_dividend[0] = b_dividend[0] << s;
kono
parents:
diff changeset
1642 }
kono
parents:
diff changeset
1643
kono
parents:
diff changeset
1644 /* Main loop. */
kono
parents:
diff changeset
1645 for (j = m - n; j >= 0; j--)
kono
parents:
diff changeset
1646 {
kono
parents:
diff changeset
1647 qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
kono
parents:
diff changeset
1648 rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
kono
parents:
diff changeset
1649 again:
kono
parents:
diff changeset
1650 if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
kono
parents:
diff changeset
1651 {
kono
parents:
diff changeset
1652 qhat -= 1;
kono
parents:
diff changeset
1653 rhat += b_divisor[n-1];
kono
parents:
diff changeset
1654 if (rhat < b)
kono
parents:
diff changeset
1655 goto again;
kono
parents:
diff changeset
1656 }
kono
parents:
diff changeset
1657
kono
parents:
diff changeset
1658 /* Multiply and subtract. */
kono
parents:
diff changeset
1659 k = 0;
kono
parents:
diff changeset
1660 for (i = 0; i < n; i++)
kono
parents:
diff changeset
1661 {
kono
parents:
diff changeset
1662 p = qhat * b_divisor[i];
kono
parents:
diff changeset
1663 t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
kono
parents:
diff changeset
1664 b_dividend[i + j] = t;
kono
parents:
diff changeset
1665 k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
kono
parents:
diff changeset
1666 - (t >> HOST_BITS_PER_HALF_WIDE_INT));
kono
parents:
diff changeset
1667 }
kono
parents:
diff changeset
1668 t = b_dividend[j+n] - k;
kono
parents:
diff changeset
1669 b_dividend[j+n] = t;
kono
parents:
diff changeset
1670
kono
parents:
diff changeset
1671 b_quotient[j] = qhat;
kono
parents:
diff changeset
1672 if (t < 0)
kono
parents:
diff changeset
1673 {
kono
parents:
diff changeset
1674 b_quotient[j] -= 1;
kono
parents:
diff changeset
1675 k = 0;
kono
parents:
diff changeset
1676 for (i = 0; i < n; i++)
kono
parents:
diff changeset
1677 {
kono
parents:
diff changeset
1678 t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
kono
parents:
diff changeset
1679 b_dividend[i+j] = t;
kono
parents:
diff changeset
1680 k = t >> HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1681 }
kono
parents:
diff changeset
1682 b_dividend[j+n] += k;
kono
parents:
diff changeset
1683 }
kono
parents:
diff changeset
1684 }
kono
parents:
diff changeset
1685 if (s)
kono
parents:
diff changeset
1686 for (i = 0; i < n; i++)
kono
parents:
diff changeset
1687 b_remainder[i] = (b_dividend[i] >> s)
kono
parents:
diff changeset
1688 | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
kono
parents:
diff changeset
1689 else
kono
parents:
diff changeset
1690 for (i = 0; i < n; i++)
kono
parents:
diff changeset
1691 b_remainder[i] = b_dividend[i];
kono
parents:
diff changeset
1692 }
kono
parents:
diff changeset
1693
kono
parents:
diff changeset
1694
kono
parents:
diff changeset
1695 /* Divide DIVIDEND by DIVISOR, which have signedness SGN, and truncate
kono
parents:
diff changeset
1696 the result. If QUOTIENT is nonnull, store the value of the quotient
kono
parents:
diff changeset
1697 there and return the number of blocks in it. The return value is
kono
parents:
diff changeset
1698 not defined otherwise. If REMAINDER is nonnull, store the value
kono
parents:
diff changeset
1699 of the remainder there and store the number of blocks in
kono
parents:
diff changeset
1700 *REMAINDER_LEN. If OFLOW is not null, store in *OFLOW whether
kono
parents:
diff changeset
1701 the division overflowed. */
kono
parents:
diff changeset
1702 unsigned int
kono
parents:
diff changeset
1703 wi::divmod_internal (HOST_WIDE_INT *quotient, unsigned int *remainder_len,
kono
parents:
diff changeset
1704 HOST_WIDE_INT *remainder,
kono
parents:
diff changeset
1705 const HOST_WIDE_INT *dividend_val,
kono
parents:
diff changeset
1706 unsigned int dividend_len, unsigned int dividend_prec,
kono
parents:
diff changeset
1707 const HOST_WIDE_INT *divisor_val, unsigned int divisor_len,
kono
parents:
diff changeset
1708 unsigned int divisor_prec, signop sgn,
kono
parents:
diff changeset
1709 bool *oflow)
kono
parents:
diff changeset
1710 {
kono
parents:
diff changeset
1711 unsigned int dividend_blocks_needed = 2 * BLOCKS_NEEDED (dividend_prec);
kono
parents:
diff changeset
1712 unsigned int divisor_blocks_needed = 2 * BLOCKS_NEEDED (divisor_prec);
kono
parents:
diff changeset
1713 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1714 b_quotient[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1715 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1716 b_remainder[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1717 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1718 b_dividend[(4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
kono
parents:
diff changeset
1719 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1720 b_divisor[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1721 unsigned int m, n;
kono
parents:
diff changeset
1722 bool dividend_neg = false;
kono
parents:
diff changeset
1723 bool divisor_neg = false;
kono
parents:
diff changeset
1724 bool overflow = false;
kono
parents:
diff changeset
1725 wide_int neg_dividend, neg_divisor;
kono
parents:
diff changeset
1726
kono
parents:
diff changeset
1727 wide_int_ref dividend = wi::storage_ref (dividend_val, dividend_len,
kono
parents:
diff changeset
1728 dividend_prec);
kono
parents:
diff changeset
1729 wide_int_ref divisor = wi::storage_ref (divisor_val, divisor_len,
kono
parents:
diff changeset
1730 divisor_prec);
kono
parents:
diff changeset
1731 if (divisor == 0)
kono
parents:
diff changeset
1732 overflow = true;
kono
parents:
diff changeset
1733
kono
parents:
diff changeset
1734 /* The smallest signed number / -1 causes overflow. The dividend_len
kono
parents:
diff changeset
1735 check is for speed rather than correctness. */
kono
parents:
diff changeset
1736 if (sgn == SIGNED
kono
parents:
diff changeset
1737 && dividend_len == BLOCKS_NEEDED (dividend_prec)
kono
parents:
diff changeset
1738 && divisor == -1
kono
parents:
diff changeset
1739 && wi::only_sign_bit_p (dividend))
kono
parents:
diff changeset
1740 overflow = true;
kono
parents:
diff changeset
1741
kono
parents:
diff changeset
1742 /* Handle the overflow cases. Viewed as unsigned value, the quotient of
kono
parents:
diff changeset
1743 (signed min / -1) has the same representation as the orignal dividend.
kono
parents:
diff changeset
1744 We have traditionally made division by zero act as division by one,
kono
parents:
diff changeset
1745 so there too we use the original dividend. */
kono
parents:
diff changeset
1746 if (overflow)
kono
parents:
diff changeset
1747 {
kono
parents:
diff changeset
1748 if (remainder)
kono
parents:
diff changeset
1749 {
kono
parents:
diff changeset
1750 *remainder_len = 1;
kono
parents:
diff changeset
1751 remainder[0] = 0;
kono
parents:
diff changeset
1752 }
kono
parents:
diff changeset
1753 if (oflow != 0)
kono
parents:
diff changeset
1754 *oflow = true;
kono
parents:
diff changeset
1755 if (quotient)
kono
parents:
diff changeset
1756 for (unsigned int i = 0; i < dividend_len; ++i)
kono
parents:
diff changeset
1757 quotient[i] = dividend_val[i];
kono
parents:
diff changeset
1758 return dividend_len;
kono
parents:
diff changeset
1759 }
kono
parents:
diff changeset
1760
kono
parents:
diff changeset
1761 if (oflow)
kono
parents:
diff changeset
1762 *oflow = false;
kono
parents:
diff changeset
1763
kono
parents:
diff changeset
1764 /* Do it on the host if you can. */
kono
parents:
diff changeset
1765 if (sgn == SIGNED
kono
parents:
diff changeset
1766 && wi::fits_shwi_p (dividend)
kono
parents:
diff changeset
1767 && wi::fits_shwi_p (divisor))
kono
parents:
diff changeset
1768 {
kono
parents:
diff changeset
1769 HOST_WIDE_INT o0 = dividend.to_shwi ();
kono
parents:
diff changeset
1770 HOST_WIDE_INT o1 = divisor.to_shwi ();
kono
parents:
diff changeset
1771
kono
parents:
diff changeset
1772 if (o0 == HOST_WIDE_INT_MIN && o1 == -1)
kono
parents:
diff changeset
1773 {
kono
parents:
diff changeset
1774 gcc_checking_assert (dividend_prec > HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
1775 if (quotient)
kono
parents:
diff changeset
1776 {
kono
parents:
diff changeset
1777 quotient[0] = HOST_WIDE_INT_MIN;
kono
parents:
diff changeset
1778 quotient[1] = 0;
kono
parents:
diff changeset
1779 }
kono
parents:
diff changeset
1780 if (remainder)
kono
parents:
diff changeset
1781 {
kono
parents:
diff changeset
1782 remainder[0] = 0;
kono
parents:
diff changeset
1783 *remainder_len = 1;
kono
parents:
diff changeset
1784 }
kono
parents:
diff changeset
1785 return 2;
kono
parents:
diff changeset
1786 }
kono
parents:
diff changeset
1787 else
kono
parents:
diff changeset
1788 {
kono
parents:
diff changeset
1789 if (quotient)
kono
parents:
diff changeset
1790 quotient[0] = o0 / o1;
kono
parents:
diff changeset
1791 if (remainder)
kono
parents:
diff changeset
1792 {
kono
parents:
diff changeset
1793 remainder[0] = o0 % o1;
kono
parents:
diff changeset
1794 *remainder_len = 1;
kono
parents:
diff changeset
1795 }
kono
parents:
diff changeset
1796 return 1;
kono
parents:
diff changeset
1797 }
kono
parents:
diff changeset
1798 }
kono
parents:
diff changeset
1799
kono
parents:
diff changeset
1800 if (sgn == UNSIGNED
kono
parents:
diff changeset
1801 && wi::fits_uhwi_p (dividend)
kono
parents:
diff changeset
1802 && wi::fits_uhwi_p (divisor))
kono
parents:
diff changeset
1803 {
kono
parents:
diff changeset
1804 unsigned HOST_WIDE_INT o0 = dividend.to_uhwi ();
kono
parents:
diff changeset
1805 unsigned HOST_WIDE_INT o1 = divisor.to_uhwi ();
kono
parents:
diff changeset
1806 unsigned int quotient_len = 1;
kono
parents:
diff changeset
1807
kono
parents:
diff changeset
1808 if (quotient)
kono
parents:
diff changeset
1809 {
kono
parents:
diff changeset
1810 quotient[0] = o0 / o1;
kono
parents:
diff changeset
1811 quotient_len = canonize_uhwi (quotient, dividend_prec);
kono
parents:
diff changeset
1812 }
kono
parents:
diff changeset
1813 if (remainder)
kono
parents:
diff changeset
1814 {
kono
parents:
diff changeset
1815 remainder[0] = o0 % o1;
kono
parents:
diff changeset
1816 *remainder_len = canonize_uhwi (remainder, dividend_prec);
kono
parents:
diff changeset
1817 }
kono
parents:
diff changeset
1818 return quotient_len;
kono
parents:
diff changeset
1819 }
kono
parents:
diff changeset
1820
kono
parents:
diff changeset
1821 /* Make the divisor and dividend positive and remember what we
kono
parents:
diff changeset
1822 did. */
kono
parents:
diff changeset
1823 if (sgn == SIGNED)
kono
parents:
diff changeset
1824 {
kono
parents:
diff changeset
1825 if (wi::neg_p (dividend))
kono
parents:
diff changeset
1826 {
kono
parents:
diff changeset
1827 neg_dividend = -dividend;
kono
parents:
diff changeset
1828 dividend = neg_dividend;
kono
parents:
diff changeset
1829 dividend_neg = true;
kono
parents:
diff changeset
1830 }
kono
parents:
diff changeset
1831 if (wi::neg_p (divisor))
kono
parents:
diff changeset
1832 {
kono
parents:
diff changeset
1833 neg_divisor = -divisor;
kono
parents:
diff changeset
1834 divisor = neg_divisor;
kono
parents:
diff changeset
1835 divisor_neg = true;
kono
parents:
diff changeset
1836 }
kono
parents:
diff changeset
1837 }
kono
parents:
diff changeset
1838
kono
parents:
diff changeset
1839 wi_unpack (b_dividend, dividend.get_val (), dividend.get_len (),
kono
parents:
diff changeset
1840 dividend_blocks_needed, dividend_prec, sgn);
kono
parents:
diff changeset
1841 wi_unpack (b_divisor, divisor.get_val (), divisor.get_len (),
kono
parents:
diff changeset
1842 divisor_blocks_needed, divisor_prec, sgn);
kono
parents:
diff changeset
1843
kono
parents:
diff changeset
1844 m = dividend_blocks_needed;
kono
parents:
diff changeset
1845 b_dividend[m] = 0;
kono
parents:
diff changeset
1846 while (m > 1 && b_dividend[m - 1] == 0)
kono
parents:
diff changeset
1847 m--;
kono
parents:
diff changeset
1848
kono
parents:
diff changeset
1849 n = divisor_blocks_needed;
kono
parents:
diff changeset
1850 while (n > 1 && b_divisor[n - 1] == 0)
kono
parents:
diff changeset
1851 n--;
kono
parents:
diff changeset
1852
kono
parents:
diff changeset
1853 memset (b_quotient, 0, sizeof (b_quotient));
kono
parents:
diff changeset
1854
kono
parents:
diff changeset
1855 divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
kono
parents:
diff changeset
1856
kono
parents:
diff changeset
1857 unsigned int quotient_len = 0;
kono
parents:
diff changeset
1858 if (quotient)
kono
parents:
diff changeset
1859 {
kono
parents:
diff changeset
1860 quotient_len = wi_pack (quotient, b_quotient, m, dividend_prec);
kono
parents:
diff changeset
1861 /* The quotient is neg if exactly one of the divisor or dividend is
kono
parents:
diff changeset
1862 neg. */
kono
parents:
diff changeset
1863 if (dividend_neg != divisor_neg)
kono
parents:
diff changeset
1864 quotient_len = wi::sub_large (quotient, zeros, 1, quotient,
kono
parents:
diff changeset
1865 quotient_len, dividend_prec,
kono
parents:
diff changeset
1866 UNSIGNED, 0);
kono
parents:
diff changeset
1867 }
kono
parents:
diff changeset
1868
kono
parents:
diff changeset
1869 if (remainder)
kono
parents:
diff changeset
1870 {
kono
parents:
diff changeset
1871 *remainder_len = wi_pack (remainder, b_remainder, n, dividend_prec);
kono
parents:
diff changeset
1872 /* The remainder is always the same sign as the dividend. */
kono
parents:
diff changeset
1873 if (dividend_neg)
kono
parents:
diff changeset
1874 *remainder_len = wi::sub_large (remainder, zeros, 1, remainder,
kono
parents:
diff changeset
1875 *remainder_len, dividend_prec,
kono
parents:
diff changeset
1876 UNSIGNED, 0);
kono
parents:
diff changeset
1877 }
kono
parents:
diff changeset
1878
kono
parents:
diff changeset
1879 return quotient_len;
kono
parents:
diff changeset
1880 }
kono
parents:
diff changeset
1881
kono
parents:
diff changeset
1882 /*
kono
parents:
diff changeset
1883 * Shifting, rotating and extraction.
kono
parents:
diff changeset
1884 */
kono
parents:
diff changeset
1885
kono
parents:
diff changeset
1886 /* Left shift XVAL by SHIFT and store the result in VAL. Return the
kono
parents:
diff changeset
1887 number of blocks in VAL. Both XVAL and VAL have PRECISION bits. */
kono
parents:
diff changeset
1888 unsigned int
kono
parents:
diff changeset
1889 wi::lshift_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
1890 unsigned int xlen, unsigned int precision,
kono
parents:
diff changeset
1891 unsigned int shift)
kono
parents:
diff changeset
1892 {
kono
parents:
diff changeset
1893 /* Split the shift into a whole-block shift and a subblock shift. */
kono
parents:
diff changeset
1894 unsigned int skip = shift / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1895 unsigned int small_shift = shift % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1896
kono
parents:
diff changeset
1897 /* The whole-block shift fills with zeros. */
kono
parents:
diff changeset
1898 unsigned int len = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
1899 for (unsigned int i = 0; i < skip; ++i)
kono
parents:
diff changeset
1900 val[i] = 0;
kono
parents:
diff changeset
1901
kono
parents:
diff changeset
1902 /* It's easier to handle the simple block case specially. */
kono
parents:
diff changeset
1903 if (small_shift == 0)
kono
parents:
diff changeset
1904 for (unsigned int i = skip; i < len; ++i)
kono
parents:
diff changeset
1905 val[i] = safe_uhwi (xval, xlen, i - skip);
kono
parents:
diff changeset
1906 else
kono
parents:
diff changeset
1907 {
kono
parents:
diff changeset
1908 /* The first unfilled output block is a left shift of the first
kono
parents:
diff changeset
1909 block in XVAL. The other output blocks contain bits from two
kono
parents:
diff changeset
1910 consecutive input blocks. */
kono
parents:
diff changeset
1911 unsigned HOST_WIDE_INT carry = 0;
kono
parents:
diff changeset
1912 for (unsigned int i = skip; i < len; ++i)
kono
parents:
diff changeset
1913 {
kono
parents:
diff changeset
1914 unsigned HOST_WIDE_INT x = safe_uhwi (xval, xlen, i - skip);
kono
parents:
diff changeset
1915 val[i] = (x << small_shift) | carry;
kono
parents:
diff changeset
1916 carry = x >> (-small_shift % HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
1917 }
kono
parents:
diff changeset
1918 }
kono
parents:
diff changeset
1919 return canonize (val, len, precision);
kono
parents:
diff changeset
1920 }
kono
parents:
diff changeset
1921
kono
parents:
diff changeset
1922 /* Right shift XVAL by SHIFT and store the result in VAL. Return the
kono
parents:
diff changeset
1923 number of blocks in VAL. The input has XPRECISION bits and the
kono
parents:
diff changeset
1924 output has XPRECISION - SHIFT bits. */
kono
parents:
diff changeset
1925 static unsigned int
kono
parents:
diff changeset
1926 rshift_large_common (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
1927 unsigned int xlen, unsigned int xprecision,
kono
parents:
diff changeset
1928 unsigned int shift)
kono
parents:
diff changeset
1929 {
kono
parents:
diff changeset
1930 /* Split the shift into a whole-block shift and a subblock shift. */
kono
parents:
diff changeset
1931 unsigned int skip = shift / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1932 unsigned int small_shift = shift % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1933
kono
parents:
diff changeset
1934 /* Work out how many blocks are needed to store the significant bits
kono
parents:
diff changeset
1935 (excluding the upper zeros or signs). */
kono
parents:
diff changeset
1936 unsigned int len = BLOCKS_NEEDED (xprecision - shift);
kono
parents:
diff changeset
1937
kono
parents:
diff changeset
1938 /* It's easier to handle the simple block case specially. */
kono
parents:
diff changeset
1939 if (small_shift == 0)
kono
parents:
diff changeset
1940 for (unsigned int i = 0; i < len; ++i)
kono
parents:
diff changeset
1941 val[i] = safe_uhwi (xval, xlen, i + skip);
kono
parents:
diff changeset
1942 else
kono
parents:
diff changeset
1943 {
kono
parents:
diff changeset
1944 /* Each output block but the last is a combination of two input blocks.
kono
parents:
diff changeset
1945 The last block is a right shift of the last block in XVAL. */
kono
parents:
diff changeset
1946 unsigned HOST_WIDE_INT curr = safe_uhwi (xval, xlen, skip);
kono
parents:
diff changeset
1947 for (unsigned int i = 0; i < len; ++i)
kono
parents:
diff changeset
1948 {
kono
parents:
diff changeset
1949 val[i] = curr >> small_shift;
kono
parents:
diff changeset
1950 curr = safe_uhwi (xval, xlen, i + skip + 1);
kono
parents:
diff changeset
1951 val[i] |= curr << (-small_shift % HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
1952 }
kono
parents:
diff changeset
1953 }
kono
parents:
diff changeset
1954 return len;
kono
parents:
diff changeset
1955 }
kono
parents:
diff changeset
1956
kono
parents:
diff changeset
1957 /* Logically right shift XVAL by SHIFT and store the result in VAL.
kono
parents:
diff changeset
1958 Return the number of blocks in VAL. XVAL has XPRECISION bits and
kono
parents:
diff changeset
1959 VAL has PRECISION bits. */
kono
parents:
diff changeset
1960 unsigned int
kono
parents:
diff changeset
1961 wi::lrshift_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
1962 unsigned int xlen, unsigned int xprecision,
kono
parents:
diff changeset
1963 unsigned int precision, unsigned int shift)
kono
parents:
diff changeset
1964 {
kono
parents:
diff changeset
1965 unsigned int len = rshift_large_common (val, xval, xlen, xprecision, shift);
kono
parents:
diff changeset
1966
kono
parents:
diff changeset
1967 /* The value we just created has precision XPRECISION - SHIFT.
kono
parents:
diff changeset
1968 Zero-extend it to wider precisions. */
kono
parents:
diff changeset
1969 if (precision > xprecision - shift)
kono
parents:
diff changeset
1970 {
kono
parents:
diff changeset
1971 unsigned int small_prec = (xprecision - shift) % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1972 if (small_prec)
kono
parents:
diff changeset
1973 val[len - 1] = zext_hwi (val[len - 1], small_prec);
kono
parents:
diff changeset
1974 else if (val[len - 1] < 0)
kono
parents:
diff changeset
1975 {
kono
parents:
diff changeset
1976 /* Add a new block with a zero. */
kono
parents:
diff changeset
1977 val[len++] = 0;
kono
parents:
diff changeset
1978 return len;
kono
parents:
diff changeset
1979 }
kono
parents:
diff changeset
1980 }
kono
parents:
diff changeset
1981 return canonize (val, len, precision);
kono
parents:
diff changeset
1982 }
kono
parents:
diff changeset
1983
kono
parents:
diff changeset
1984 /* Arithmetically right shift XVAL by SHIFT and store the result in VAL.
kono
parents:
diff changeset
1985 Return the number of blocks in VAL. XVAL has XPRECISION bits and
kono
parents:
diff changeset
1986 VAL has PRECISION bits. */
kono
parents:
diff changeset
1987 unsigned int
kono
parents:
diff changeset
1988 wi::arshift_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
1989 unsigned int xlen, unsigned int xprecision,
kono
parents:
diff changeset
1990 unsigned int precision, unsigned int shift)
kono
parents:
diff changeset
1991 {
kono
parents:
diff changeset
1992 unsigned int len = rshift_large_common (val, xval, xlen, xprecision, shift);
kono
parents:
diff changeset
1993
kono
parents:
diff changeset
1994 /* The value we just created has precision XPRECISION - SHIFT.
kono
parents:
diff changeset
1995 Sign-extend it to wider types. */
kono
parents:
diff changeset
1996 if (precision > xprecision - shift)
kono
parents:
diff changeset
1997 {
kono
parents:
diff changeset
1998 unsigned int small_prec = (xprecision - shift) % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1999 if (small_prec)
kono
parents:
diff changeset
2000 val[len - 1] = sext_hwi (val[len - 1], small_prec);
kono
parents:
diff changeset
2001 }
kono
parents:
diff changeset
2002 return canonize (val, len, precision);
kono
parents:
diff changeset
2003 }
kono
parents:
diff changeset
2004
kono
parents:
diff changeset
2005 /* Return the number of leading (upper) zeros in X. */
kono
parents:
diff changeset
2006 int
kono
parents:
diff changeset
2007 wi::clz (const wide_int_ref &x)
kono
parents:
diff changeset
2008 {
kono
parents:
diff changeset
2009 /* Calculate how many bits there above the highest represented block. */
kono
parents:
diff changeset
2010 int count = x.precision - x.len * HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
2011
kono
parents:
diff changeset
2012 unsigned HOST_WIDE_INT high = x.uhigh ();
kono
parents:
diff changeset
2013 if (count < 0)
kono
parents:
diff changeset
2014 /* The upper -COUNT bits of HIGH are not part of the value.
kono
parents:
diff changeset
2015 Clear them out. */
kono
parents:
diff changeset
2016 high = (high << -count) >> -count;
kono
parents:
diff changeset
2017 else if (x.sign_mask () < 0)
kono
parents:
diff changeset
2018 /* The upper bit is set, so there are no leading zeros. */
kono
parents:
diff changeset
2019 return 0;
kono
parents:
diff changeset
2020
kono
parents:
diff changeset
2021 /* We don't need to look below HIGH. Either HIGH is nonzero,
kono
parents:
diff changeset
2022 or the top bit of the block below is nonzero; clz_hwi is
kono
parents:
diff changeset
2023 HOST_BITS_PER_WIDE_INT in the latter case. */
kono
parents:
diff changeset
2024 return count + clz_hwi (high);
kono
parents:
diff changeset
2025 }
kono
parents:
diff changeset
2026
kono
parents:
diff changeset
2027 /* Return the number of redundant sign bits in X. (That is, the number
kono
parents:
diff changeset
2028 of bits immediately below the sign bit that have the same value as
kono
parents:
diff changeset
2029 the sign bit.) */
kono
parents:
diff changeset
2030 int
kono
parents:
diff changeset
2031 wi::clrsb (const wide_int_ref &x)
kono
parents:
diff changeset
2032 {
kono
parents:
diff changeset
2033 /* Calculate how many bits there above the highest represented block. */
kono
parents:
diff changeset
2034 int count = x.precision - x.len * HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
2035
kono
parents:
diff changeset
2036 unsigned HOST_WIDE_INT high = x.uhigh ();
kono
parents:
diff changeset
2037 unsigned HOST_WIDE_INT mask = -1;
kono
parents:
diff changeset
2038 if (count < 0)
kono
parents:
diff changeset
2039 {
kono
parents:
diff changeset
2040 /* The upper -COUNT bits of HIGH are not part of the value.
kono
parents:
diff changeset
2041 Clear them from both MASK and HIGH. */
kono
parents:
diff changeset
2042 mask >>= -count;
kono
parents:
diff changeset
2043 high &= mask;
kono
parents:
diff changeset
2044 }
kono
parents:
diff changeset
2045
kono
parents:
diff changeset
2046 /* If the top bit is 1, count the number of leading 1s. If the top
kono
parents:
diff changeset
2047 bit is zero, count the number of leading zeros. */
kono
parents:
diff changeset
2048 if (high > mask / 2)
kono
parents:
diff changeset
2049 high ^= mask;
kono
parents:
diff changeset
2050
kono
parents:
diff changeset
2051 /* There are no sign bits below the top block, so we don't need to look
kono
parents:
diff changeset
2052 beyond HIGH. Note that clz_hwi is HOST_BITS_PER_WIDE_INT when
kono
parents:
diff changeset
2053 HIGH is 0. */
kono
parents:
diff changeset
2054 return count + clz_hwi (high) - 1;
kono
parents:
diff changeset
2055 }
kono
parents:
diff changeset
2056
kono
parents:
diff changeset
2057 /* Return the number of trailing (lower) zeros in X. */
kono
parents:
diff changeset
2058 int
kono
parents:
diff changeset
2059 wi::ctz (const wide_int_ref &x)
kono
parents:
diff changeset
2060 {
kono
parents:
diff changeset
2061 if (x.len == 1 && x.ulow () == 0)
kono
parents:
diff changeset
2062 return x.precision;
kono
parents:
diff changeset
2063
kono
parents:
diff changeset
2064 /* Having dealt with the zero case, there must be a block with a
kono
parents:
diff changeset
2065 nonzero bit. We don't care about the bits above the first 1. */
kono
parents:
diff changeset
2066 unsigned int i = 0;
kono
parents:
diff changeset
2067 while (x.val[i] == 0)
kono
parents:
diff changeset
2068 ++i;
kono
parents:
diff changeset
2069 return i * HOST_BITS_PER_WIDE_INT + ctz_hwi (x.val[i]);
kono
parents:
diff changeset
2070 }
kono
parents:
diff changeset
2071
kono
parents:
diff changeset
2072 /* If X is an exact power of 2, return the base-2 logarithm, otherwise
kono
parents:
diff changeset
2073 return -1. */
kono
parents:
diff changeset
2074 int
kono
parents:
diff changeset
2075 wi::exact_log2 (const wide_int_ref &x)
kono
parents:
diff changeset
2076 {
kono
parents:
diff changeset
2077 /* Reject cases where there are implicit -1 blocks above HIGH. */
kono
parents:
diff changeset
2078 if (x.len * HOST_BITS_PER_WIDE_INT < x.precision && x.sign_mask () < 0)
kono
parents:
diff changeset
2079 return -1;
kono
parents:
diff changeset
2080
kono
parents:
diff changeset
2081 /* Set CRUX to the index of the entry that should be nonzero.
kono
parents:
diff changeset
2082 If the top block is zero then the next lowest block (if any)
kono
parents:
diff changeset
2083 must have the high bit set. */
kono
parents:
diff changeset
2084 unsigned int crux = x.len - 1;
kono
parents:
diff changeset
2085 if (crux > 0 && x.val[crux] == 0)
kono
parents:
diff changeset
2086 crux -= 1;
kono
parents:
diff changeset
2087
kono
parents:
diff changeset
2088 /* Check that all lower blocks are zero. */
kono
parents:
diff changeset
2089 for (unsigned int i = 0; i < crux; ++i)
kono
parents:
diff changeset
2090 if (x.val[i] != 0)
kono
parents:
diff changeset
2091 return -1;
kono
parents:
diff changeset
2092
kono
parents:
diff changeset
2093 /* Get a zero-extended form of block CRUX. */
kono
parents:
diff changeset
2094 unsigned HOST_WIDE_INT hwi = x.val[crux];
kono
parents:
diff changeset
2095 if ((crux + 1) * HOST_BITS_PER_WIDE_INT > x.precision)
kono
parents:
diff changeset
2096 hwi = zext_hwi (hwi, x.precision % HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
2097
kono
parents:
diff changeset
2098 /* Now it's down to whether HWI is a power of 2. */
kono
parents:
diff changeset
2099 int res = ::exact_log2 (hwi);
kono
parents:
diff changeset
2100 if (res >= 0)
kono
parents:
diff changeset
2101 res += crux * HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
2102 return res;
kono
parents:
diff changeset
2103 }
kono
parents:
diff changeset
2104
kono
parents:
diff changeset
2105 /* Return the base-2 logarithm of X, rounding down. Return -1 if X is 0. */
kono
parents:
diff changeset
2106 int
kono
parents:
diff changeset
2107 wi::floor_log2 (const wide_int_ref &x)
kono
parents:
diff changeset
2108 {
kono
parents:
diff changeset
2109 return x.precision - 1 - clz (x);
kono
parents:
diff changeset
2110 }
kono
parents:
diff changeset
2111
kono
parents:
diff changeset
2112 /* Return the index of the first (lowest) set bit in X, counting from 1.
kono
parents:
diff changeset
2113 Return 0 if X is 0. */
kono
parents:
diff changeset
2114 int
kono
parents:
diff changeset
2115 wi::ffs (const wide_int_ref &x)
kono
parents:
diff changeset
2116 {
kono
parents:
diff changeset
2117 return eq_p (x, 0) ? 0 : ctz (x) + 1;
kono
parents:
diff changeset
2118 }
kono
parents:
diff changeset
2119
kono
parents:
diff changeset
2120 /* Return true if sign-extending X to have precision PRECISION would give
kono
parents:
diff changeset
2121 the minimum signed value at that precision. */
kono
parents:
diff changeset
2122 bool
kono
parents:
diff changeset
2123 wi::only_sign_bit_p (const wide_int_ref &x, unsigned int precision)
kono
parents:
diff changeset
2124 {
kono
parents:
diff changeset
2125 return ctz (x) + 1 == int (precision);
kono
parents:
diff changeset
2126 }
kono
parents:
diff changeset
2127
kono
parents:
diff changeset
2128 /* Return true if X represents the minimum signed value. */
kono
parents:
diff changeset
2129 bool
kono
parents:
diff changeset
2130 wi::only_sign_bit_p (const wide_int_ref &x)
kono
parents:
diff changeset
2131 {
kono
parents:
diff changeset
2132 return only_sign_bit_p (x, x.precision);
kono
parents:
diff changeset
2133 }
kono
parents:
diff changeset
2134
kono
parents:
diff changeset
2135 /*
kono
parents:
diff changeset
2136 * Private utilities.
kono
parents:
diff changeset
2137 */
kono
parents:
diff changeset
2138
kono
parents:
diff changeset
2139 void gt_ggc_mx (widest_int *) { }
kono
parents:
diff changeset
2140 void gt_pch_nx (widest_int *, void (*) (void *, void *), void *) { }
kono
parents:
diff changeset
2141 void gt_pch_nx (widest_int *) { }
kono
parents:
diff changeset
2142
kono
parents:
diff changeset
2143 template void wide_int::dump () const;
kono
parents:
diff changeset
2144 template void generic_wide_int <wide_int_ref_storage <false> >::dump () const;
kono
parents:
diff changeset
2145 template void generic_wide_int <wide_int_ref_storage <true> >::dump () const;
kono
parents:
diff changeset
2146 template void offset_int::dump () const;
kono
parents:
diff changeset
2147 template void widest_int::dump () const;
kono
parents:
diff changeset
2148
kono
parents:
diff changeset
2149 /* We could add all the above ::dump variants here, but wide_int and
kono
parents:
diff changeset
2150 widest_int should handle the common cases. Besides, you can always
kono
parents:
diff changeset
2151 call the dump method directly. */
kono
parents:
diff changeset
2152
kono
parents:
diff changeset
2153 DEBUG_FUNCTION void
kono
parents:
diff changeset
2154 debug (const wide_int &ref)
kono
parents:
diff changeset
2155 {
kono
parents:
diff changeset
2156 ref.dump ();
kono
parents:
diff changeset
2157 }
kono
parents:
diff changeset
2158
kono
parents:
diff changeset
2159 DEBUG_FUNCTION void
kono
parents:
diff changeset
2160 debug (const wide_int *ptr)
kono
parents:
diff changeset
2161 {
kono
parents:
diff changeset
2162 if (ptr)
kono
parents:
diff changeset
2163 debug (*ptr);
kono
parents:
diff changeset
2164 else
kono
parents:
diff changeset
2165 fprintf (stderr, "<nil>\n");
kono
parents:
diff changeset
2166 }
kono
parents:
diff changeset
2167
kono
parents:
diff changeset
2168 DEBUG_FUNCTION void
kono
parents:
diff changeset
2169 debug (const widest_int &ref)
kono
parents:
diff changeset
2170 {
kono
parents:
diff changeset
2171 ref.dump ();
kono
parents:
diff changeset
2172 }
kono
parents:
diff changeset
2173
kono
parents:
diff changeset
2174 DEBUG_FUNCTION void
kono
parents:
diff changeset
2175 debug (const widest_int *ptr)
kono
parents:
diff changeset
2176 {
kono
parents:
diff changeset
2177 if (ptr)
kono
parents:
diff changeset
2178 debug (*ptr);
kono
parents:
diff changeset
2179 else
kono
parents:
diff changeset
2180 fprintf (stderr, "<nil>\n");
kono
parents:
diff changeset
2181 }
kono
parents:
diff changeset
2182
kono
parents:
diff changeset
2183 #if CHECKING_P
kono
parents:
diff changeset
2184
kono
parents:
diff changeset
2185 namespace selftest {
kono
parents:
diff changeset
2186
kono
parents:
diff changeset
2187 /* Selftests for wide ints. We run these multiple times, once per type. */
kono
parents:
diff changeset
2188
kono
parents:
diff changeset
2189 /* Helper function for building a test value. */
kono
parents:
diff changeset
2190
kono
parents:
diff changeset
2191 template <class VALUE_TYPE>
kono
parents:
diff changeset
2192 static VALUE_TYPE
kono
parents:
diff changeset
2193 from_int (int i);
kono
parents:
diff changeset
2194
kono
parents:
diff changeset
2195 /* Specializations of the fixture for each wide-int type. */
kono
parents:
diff changeset
2196
kono
parents:
diff changeset
2197 /* Specialization for VALUE_TYPE == wide_int. */
kono
parents:
diff changeset
2198
kono
parents:
diff changeset
2199 template <>
kono
parents:
diff changeset
2200 wide_int
kono
parents:
diff changeset
2201 from_int (int i)
kono
parents:
diff changeset
2202 {
kono
parents:
diff changeset
2203 return wi::shwi (i, 32);
kono
parents:
diff changeset
2204 }
kono
parents:
diff changeset
2205
kono
parents:
diff changeset
2206 /* Specialization for VALUE_TYPE == offset_int. */
kono
parents:
diff changeset
2207
kono
parents:
diff changeset
2208 template <>
kono
parents:
diff changeset
2209 offset_int
kono
parents:
diff changeset
2210 from_int (int i)
kono
parents:
diff changeset
2211 {
kono
parents:
diff changeset
2212 return offset_int (i);
kono
parents:
diff changeset
2213 }
kono
parents:
diff changeset
2214
kono
parents:
diff changeset
2215 /* Specialization for VALUE_TYPE == widest_int. */
kono
parents:
diff changeset
2216
kono
parents:
diff changeset
2217 template <>
kono
parents:
diff changeset
2218 widest_int
kono
parents:
diff changeset
2219 from_int (int i)
kono
parents:
diff changeset
2220 {
kono
parents:
diff changeset
2221 return widest_int (i);
kono
parents:
diff changeset
2222 }
kono
parents:
diff changeset
2223
kono
parents:
diff changeset
2224 /* Verify that print_dec (WI, ..., SGN) gives the expected string
kono
parents:
diff changeset
2225 representation (using base 10). */
kono
parents:
diff changeset
2226
kono
parents:
diff changeset
2227 static void
kono
parents:
diff changeset
2228 assert_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
kono
parents:
diff changeset
2229 {
kono
parents:
diff changeset
2230 char buf[WIDE_INT_PRINT_BUFFER_SIZE];
kono
parents:
diff changeset
2231 print_dec (wi, buf, sgn);
kono
parents:
diff changeset
2232 ASSERT_STREQ (expected, buf);
kono
parents:
diff changeset
2233 }
kono
parents:
diff changeset
2234
kono
parents:
diff changeset
2235 /* Likewise for base 16. */
kono
parents:
diff changeset
2236
kono
parents:
diff changeset
2237 static void
kono
parents:
diff changeset
2238 assert_hexeq (const char *expected, const wide_int_ref &wi)
kono
parents:
diff changeset
2239 {
kono
parents:
diff changeset
2240 char buf[WIDE_INT_PRINT_BUFFER_SIZE];
kono
parents:
diff changeset
2241 print_hex (wi, buf);
kono
parents:
diff changeset
2242 ASSERT_STREQ (expected, buf);
kono
parents:
diff changeset
2243 }
kono
parents:
diff changeset
2244
kono
parents:
diff changeset
2245 /* Test cases. */
kono
parents:
diff changeset
2246
kono
parents:
diff changeset
2247 /* Verify that print_dec and print_hex work for VALUE_TYPE. */
kono
parents:
diff changeset
2248
kono
parents:
diff changeset
2249 template <class VALUE_TYPE>
kono
parents:
diff changeset
2250 static void
kono
parents:
diff changeset
2251 test_printing ()
kono
parents:
diff changeset
2252 {
kono
parents:
diff changeset
2253 VALUE_TYPE a = from_int<VALUE_TYPE> (42);
kono
parents:
diff changeset
2254 assert_deceq ("42", a, SIGNED);
kono
parents:
diff changeset
2255 assert_hexeq ("0x2a", a);
kono
parents:
diff changeset
2256 assert_hexeq ("0x1fffffffffffffffff", wi::shwi (-1, 69));
kono
parents:
diff changeset
2257 assert_hexeq ("0xffffffffffffffff", wi::mask (64, false, 69));
kono
parents:
diff changeset
2258 assert_hexeq ("0xffffffffffffffff", wi::mask <widest_int> (64, false));
kono
parents:
diff changeset
2259 if (WIDE_INT_MAX_PRECISION > 128)
kono
parents:
diff changeset
2260 {
kono
parents:
diff changeset
2261 assert_hexeq ("0x20000000000000000fffffffffffffffe",
kono
parents:
diff changeset
2262 wi::lshift (1, 129) + wi::lshift (1, 64) - 2);
kono
parents:
diff changeset
2263 assert_hexeq ("0x200000000000004000123456789abcdef",
kono
parents:
diff changeset
2264 wi::lshift (1, 129) + wi::lshift (1, 74)
kono
parents:
diff changeset
2265 + wi::lshift (0x1234567, 32) + 0x89abcdef);
kono
parents:
diff changeset
2266 }
kono
parents:
diff changeset
2267 }
kono
parents:
diff changeset
2268
kono
parents:
diff changeset
2269 /* Verify that various operations work correctly for VALUE_TYPE,
kono
parents:
diff changeset
2270 unary and binary, using both function syntax, and
kono
parents:
diff changeset
2271 overloaded-operators. */
kono
parents:
diff changeset
2272
kono
parents:
diff changeset
2273 template <class VALUE_TYPE>
kono
parents:
diff changeset
2274 static void
kono
parents:
diff changeset
2275 test_ops ()
kono
parents:
diff changeset
2276 {
kono
parents:
diff changeset
2277 VALUE_TYPE a = from_int<VALUE_TYPE> (7);
kono
parents:
diff changeset
2278 VALUE_TYPE b = from_int<VALUE_TYPE> (3);
kono
parents:
diff changeset
2279
kono
parents:
diff changeset
2280 /* Using functions. */
kono
parents:
diff changeset
2281 assert_deceq ("-7", wi::neg (a), SIGNED);
kono
parents:
diff changeset
2282 assert_deceq ("10", wi::add (a, b), SIGNED);
kono
parents:
diff changeset
2283 assert_deceq ("4", wi::sub (a, b), SIGNED);
kono
parents:
diff changeset
2284 assert_deceq ("-4", wi::sub (b, a), SIGNED);
kono
parents:
diff changeset
2285 assert_deceq ("21", wi::mul (a, b), SIGNED);
kono
parents:
diff changeset
2286
kono
parents:
diff changeset
2287 /* Using operators. */
kono
parents:
diff changeset
2288 assert_deceq ("-7", -a, SIGNED);
kono
parents:
diff changeset
2289 assert_deceq ("10", a + b, SIGNED);
kono
parents:
diff changeset
2290 assert_deceq ("4", a - b, SIGNED);
kono
parents:
diff changeset
2291 assert_deceq ("-4", b - a, SIGNED);
kono
parents:
diff changeset
2292 assert_deceq ("21", a * b, SIGNED);
kono
parents:
diff changeset
2293 }
kono
parents:
diff changeset
2294
kono
parents:
diff changeset
2295 /* Verify that various comparisons work correctly for VALUE_TYPE. */
kono
parents:
diff changeset
2296
kono
parents:
diff changeset
2297 template <class VALUE_TYPE>
kono
parents:
diff changeset
2298 static void
kono
parents:
diff changeset
2299 test_comparisons ()
kono
parents:
diff changeset
2300 {
kono
parents:
diff changeset
2301 VALUE_TYPE a = from_int<VALUE_TYPE> (7);
kono
parents:
diff changeset
2302 VALUE_TYPE b = from_int<VALUE_TYPE> (3);
kono
parents:
diff changeset
2303
kono
parents:
diff changeset
2304 /* == */
kono
parents:
diff changeset
2305 ASSERT_TRUE (wi::eq_p (a, a));
kono
parents:
diff changeset
2306 ASSERT_FALSE (wi::eq_p (a, b));
kono
parents:
diff changeset
2307
kono
parents:
diff changeset
2308 /* != */
kono
parents:
diff changeset
2309 ASSERT_TRUE (wi::ne_p (a, b));
kono
parents:
diff changeset
2310 ASSERT_FALSE (wi::ne_p (a, a));
kono
parents:
diff changeset
2311
kono
parents:
diff changeset
2312 /* < */
kono
parents:
diff changeset
2313 ASSERT_FALSE (wi::lts_p (a, a));
kono
parents:
diff changeset
2314 ASSERT_FALSE (wi::lts_p (a, b));
kono
parents:
diff changeset
2315 ASSERT_TRUE (wi::lts_p (b, a));
kono
parents:
diff changeset
2316
kono
parents:
diff changeset
2317 /* <= */
kono
parents:
diff changeset
2318 ASSERT_TRUE (wi::les_p (a, a));
kono
parents:
diff changeset
2319 ASSERT_FALSE (wi::les_p (a, b));
kono
parents:
diff changeset
2320 ASSERT_TRUE (wi::les_p (b, a));
kono
parents:
diff changeset
2321
kono
parents:
diff changeset
2322 /* > */
kono
parents:
diff changeset
2323 ASSERT_FALSE (wi::gts_p (a, a));
kono
parents:
diff changeset
2324 ASSERT_TRUE (wi::gts_p (a, b));
kono
parents:
diff changeset
2325 ASSERT_FALSE (wi::gts_p (b, a));
kono
parents:
diff changeset
2326
kono
parents:
diff changeset
2327 /* >= */
kono
parents:
diff changeset
2328 ASSERT_TRUE (wi::ges_p (a, a));
kono
parents:
diff changeset
2329 ASSERT_TRUE (wi::ges_p (a, b));
kono
parents:
diff changeset
2330 ASSERT_FALSE (wi::ges_p (b, a));
kono
parents:
diff changeset
2331
kono
parents:
diff changeset
2332 /* comparison */
kono
parents:
diff changeset
2333 ASSERT_EQ (-1, wi::cmps (b, a));
kono
parents:
diff changeset
2334 ASSERT_EQ (0, wi::cmps (a, a));
kono
parents:
diff changeset
2335 ASSERT_EQ (1, wi::cmps (a, b));
kono
parents:
diff changeset
2336 }
kono
parents:
diff changeset
2337
kono
parents:
diff changeset
2338 /* Run all of the selftests, using the given VALUE_TYPE. */
kono
parents:
diff changeset
2339
kono
parents:
diff changeset
2340 template <class VALUE_TYPE>
kono
parents:
diff changeset
2341 static void run_all_wide_int_tests ()
kono
parents:
diff changeset
2342 {
kono
parents:
diff changeset
2343 test_printing <VALUE_TYPE> ();
kono
parents:
diff changeset
2344 test_ops <VALUE_TYPE> ();
kono
parents:
diff changeset
2345 test_comparisons <VALUE_TYPE> ();
kono
parents:
diff changeset
2346 }
kono
parents:
diff changeset
2347
kono
parents:
diff changeset
2348 /* Run all of the selftests within this file, for all value types. */
kono
parents:
diff changeset
2349
kono
parents:
diff changeset
2350 void
kono
parents:
diff changeset
2351 wide_int_cc_tests ()
kono
parents:
diff changeset
2352 {
kono
parents:
diff changeset
2353 run_all_wide_int_tests <wide_int> ();
kono
parents:
diff changeset
2354 run_all_wide_int_tests <offset_int> ();
kono
parents:
diff changeset
2355 run_all_wide_int_tests <widest_int> ();
kono
parents:
diff changeset
2356 }
kono
parents:
diff changeset
2357
kono
parents:
diff changeset
2358 } // namespace selftest
kono
parents:
diff changeset
2359 #endif /* CHECKING_P */