annotate gcc/wide-int.cc @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Operations with very long integers.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2 Copyright (C) 2012-2020 Free Software Foundation, Inc.
111
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,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1131 signop sgn, wi::overflow_type *overflow)
111
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)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1161 *overflow
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1162 = (sgn == UNSIGNED && carry) ? wi::OVF_OVERFLOW : wi::OVF_NONE;
111
kono
parents:
diff changeset
1163 }
kono
parents:
diff changeset
1164 else if (overflow)
kono
parents:
diff changeset
1165 {
kono
parents:
diff changeset
1166 unsigned int shift = -prec % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1167 if (sgn == SIGNED)
kono
parents:
diff changeset
1168 {
kono
parents:
diff changeset
1169 unsigned HOST_WIDE_INT x = (val[len - 1] ^ o0) & (val[len - 1] ^ o1);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1170 if ((HOST_WIDE_INT) (x << shift) < 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1171 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1172 if (o0 > (unsigned HOST_WIDE_INT) val[len - 1])
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1173 *overflow = wi::OVF_UNDERFLOW;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1174 else if (o0 < (unsigned HOST_WIDE_INT) val[len - 1])
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1175 *overflow = wi::OVF_OVERFLOW;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1176 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1177 *overflow = wi::OVF_NONE;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1178 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1179 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1180 *overflow = wi::OVF_NONE;
111
kono
parents:
diff changeset
1181 }
kono
parents:
diff changeset
1182 else
kono
parents:
diff changeset
1183 {
kono
parents:
diff changeset
1184 /* Put the MSB of X and O0 and in the top of the HWI. */
kono
parents:
diff changeset
1185 x <<= shift;
kono
parents:
diff changeset
1186 o0 <<= shift;
kono
parents:
diff changeset
1187 if (old_carry)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1188 *overflow = (x <= o0) ? wi::OVF_OVERFLOW : wi::OVF_NONE;
111
kono
parents:
diff changeset
1189 else
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1190 *overflow = (x < o0) ? wi::OVF_OVERFLOW : wi::OVF_NONE;
111
kono
parents:
diff changeset
1191 }
kono
parents:
diff changeset
1192 }
kono
parents:
diff changeset
1193
kono
parents:
diff changeset
1194 return canonize (val, len, prec);
kono
parents:
diff changeset
1195 }
kono
parents:
diff changeset
1196
kono
parents:
diff changeset
1197 /* Subroutines of the multiplication and division operations. Unpack
kono
parents:
diff changeset
1198 the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
kono
parents:
diff changeset
1199 HOST_HALF_WIDE_INTs of RESULT. The rest of RESULT is filled by
kono
parents:
diff changeset
1200 uncompressing the top bit of INPUT[IN_LEN - 1]. */
kono
parents:
diff changeset
1201 static void
kono
parents:
diff changeset
1202 wi_unpack (unsigned HOST_HALF_WIDE_INT *result, const HOST_WIDE_INT *input,
kono
parents:
diff changeset
1203 unsigned int in_len, unsigned int out_len,
kono
parents:
diff changeset
1204 unsigned int prec, signop sgn)
kono
parents:
diff changeset
1205 {
kono
parents:
diff changeset
1206 unsigned int i;
kono
parents:
diff changeset
1207 unsigned int j = 0;
kono
parents:
diff changeset
1208 unsigned int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
1209 unsigned int blocks_needed = BLOCKS_NEEDED (prec);
kono
parents:
diff changeset
1210 HOST_WIDE_INT mask;
kono
parents:
diff changeset
1211
kono
parents:
diff changeset
1212 if (sgn == SIGNED)
kono
parents:
diff changeset
1213 {
kono
parents:
diff changeset
1214 mask = -top_bit_of ((const HOST_WIDE_INT *) input, in_len, prec);
kono
parents:
diff changeset
1215 mask &= HALF_INT_MASK;
kono
parents:
diff changeset
1216 }
kono
parents:
diff changeset
1217 else
kono
parents:
diff changeset
1218 mask = 0;
kono
parents:
diff changeset
1219
kono
parents:
diff changeset
1220 for (i = 0; i < blocks_needed - 1; i++)
kono
parents:
diff changeset
1221 {
kono
parents:
diff changeset
1222 HOST_WIDE_INT x = safe_uhwi (input, in_len, i);
kono
parents:
diff changeset
1223 result[j++] = x;
kono
parents:
diff changeset
1224 result[j++] = x >> HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1225 }
kono
parents:
diff changeset
1226
kono
parents:
diff changeset
1227 HOST_WIDE_INT x = safe_uhwi (input, in_len, i);
kono
parents:
diff changeset
1228 if (small_prec)
kono
parents:
diff changeset
1229 {
kono
parents:
diff changeset
1230 if (sgn == SIGNED)
kono
parents:
diff changeset
1231 x = sext_hwi (x, small_prec);
kono
parents:
diff changeset
1232 else
kono
parents:
diff changeset
1233 x = zext_hwi (x, small_prec);
kono
parents:
diff changeset
1234 }
kono
parents:
diff changeset
1235 result[j++] = x;
kono
parents:
diff changeset
1236 result[j++] = x >> HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1237
kono
parents:
diff changeset
1238 /* Smear the sign bit. */
kono
parents:
diff changeset
1239 while (j < out_len)
kono
parents:
diff changeset
1240 result[j++] = mask;
kono
parents:
diff changeset
1241 }
kono
parents:
diff changeset
1242
kono
parents:
diff changeset
1243 /* The inverse of wi_unpack. IN_LEN is the number of input
kono
parents:
diff changeset
1244 blocks and PRECISION is the precision of the result. Return the
kono
parents:
diff changeset
1245 number of blocks in the canonicalized result. */
kono
parents:
diff changeset
1246 static unsigned int
kono
parents:
diff changeset
1247 wi_pack (HOST_WIDE_INT *result,
kono
parents:
diff changeset
1248 const unsigned HOST_HALF_WIDE_INT *input,
kono
parents:
diff changeset
1249 unsigned int in_len, unsigned int precision)
kono
parents:
diff changeset
1250 {
kono
parents:
diff changeset
1251 unsigned int i = 0;
kono
parents:
diff changeset
1252 unsigned int j = 0;
kono
parents:
diff changeset
1253 unsigned int blocks_needed = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
1254
kono
parents:
diff changeset
1255 while (i + 1 < in_len)
kono
parents:
diff changeset
1256 {
kono
parents:
diff changeset
1257 result[j++] = ((unsigned HOST_WIDE_INT) input[i]
kono
parents:
diff changeset
1258 | ((unsigned HOST_WIDE_INT) input[i + 1]
kono
parents:
diff changeset
1259 << HOST_BITS_PER_HALF_WIDE_INT));
kono
parents:
diff changeset
1260 i += 2;
kono
parents:
diff changeset
1261 }
kono
parents:
diff changeset
1262
kono
parents:
diff changeset
1263 /* Handle the case where in_len is odd. For this we zero extend. */
kono
parents:
diff changeset
1264 if (in_len & 1)
kono
parents:
diff changeset
1265 result[j++] = (unsigned HOST_WIDE_INT) input[i];
kono
parents:
diff changeset
1266 else if (j < blocks_needed)
kono
parents:
diff changeset
1267 result[j++] = 0;
kono
parents:
diff changeset
1268 return canonize (result, j, precision);
kono
parents:
diff changeset
1269 }
kono
parents:
diff changeset
1270
kono
parents:
diff changeset
1271 /* Multiply Op1 by Op2. If HIGH is set, only the upper half of the
kono
parents:
diff changeset
1272 result is returned.
kono
parents:
diff changeset
1273
kono
parents:
diff changeset
1274 If HIGH is not set, throw away the upper half after the check is
kono
parents:
diff changeset
1275 made to see if it overflows. Unfortunately there is no better way
kono
parents:
diff changeset
1276 to check for overflow than to do this. If OVERFLOW is nonnull,
kono
parents:
diff changeset
1277 record in *OVERFLOW whether the result overflowed. SGN controls
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1278 the signedness and is used to check overflow or if HIGH is set.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1279
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1280 NOTE: Overflow type for signed overflow is not yet implemented. */
111
kono
parents:
diff changeset
1281 unsigned int
kono
parents:
diff changeset
1282 wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val,
kono
parents:
diff changeset
1283 unsigned int op1len, const HOST_WIDE_INT *op2val,
kono
parents:
diff changeset
1284 unsigned int op2len, unsigned int prec, signop sgn,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1285 wi::overflow_type *overflow, bool high)
111
kono
parents:
diff changeset
1286 {
kono
parents:
diff changeset
1287 unsigned HOST_WIDE_INT o0, o1, k, t;
kono
parents:
diff changeset
1288 unsigned int i;
kono
parents:
diff changeset
1289 unsigned int j;
kono
parents:
diff changeset
1290 unsigned int blocks_needed = BLOCKS_NEEDED (prec);
kono
parents:
diff changeset
1291 unsigned int half_blocks_needed = blocks_needed * 2;
kono
parents:
diff changeset
1292 /* The sizes here are scaled to support a 2x largest mode by 2x
kono
parents:
diff changeset
1293 largest mode yielding a 4x largest mode result. This is what is
kono
parents:
diff changeset
1294 needed by vpn. */
kono
parents:
diff changeset
1295
kono
parents:
diff changeset
1296 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1297 u[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1298 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1299 v[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1300 /* The '2' in 'R' is because we are internally doing a full
kono
parents:
diff changeset
1301 multiply. */
kono
parents:
diff changeset
1302 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1303 r[2 * 4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1304 HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
kono
parents:
diff changeset
1305
kono
parents:
diff changeset
1306 /* If the top level routine did not really pass in an overflow, then
kono
parents:
diff changeset
1307 just make sure that we never attempt to set it. */
kono
parents:
diff changeset
1308 bool needs_overflow = (overflow != 0);
kono
parents:
diff changeset
1309 if (needs_overflow)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1310 *overflow = wi::OVF_NONE;
111
kono
parents:
diff changeset
1311
kono
parents:
diff changeset
1312 wide_int_ref op1 = wi::storage_ref (op1val, op1len, prec);
kono
parents:
diff changeset
1313 wide_int_ref op2 = wi::storage_ref (op2val, op2len, prec);
kono
parents:
diff changeset
1314
kono
parents:
diff changeset
1315 /* This is a surprisingly common case, so do it first. */
kono
parents:
diff changeset
1316 if (op1 == 0 || op2 == 0)
kono
parents:
diff changeset
1317 {
kono
parents:
diff changeset
1318 val[0] = 0;
kono
parents:
diff changeset
1319 return 1;
kono
parents:
diff changeset
1320 }
kono
parents:
diff changeset
1321
kono
parents:
diff changeset
1322 #ifdef umul_ppmm
kono
parents:
diff changeset
1323 if (sgn == UNSIGNED)
kono
parents:
diff changeset
1324 {
kono
parents:
diff changeset
1325 /* If the inputs are single HWIs and the output has room for at
kono
parents:
diff changeset
1326 least two HWIs, we can use umul_ppmm directly. */
kono
parents:
diff changeset
1327 if (prec >= HOST_BITS_PER_WIDE_INT * 2
kono
parents:
diff changeset
1328 && wi::fits_uhwi_p (op1)
kono
parents:
diff changeset
1329 && wi::fits_uhwi_p (op2))
kono
parents:
diff changeset
1330 {
kono
parents:
diff changeset
1331 /* This case never overflows. */
kono
parents:
diff changeset
1332 if (high)
kono
parents:
diff changeset
1333 {
kono
parents:
diff changeset
1334 val[0] = 0;
kono
parents:
diff changeset
1335 return 1;
kono
parents:
diff changeset
1336 }
kono
parents:
diff changeset
1337 umul_ppmm (val[1], val[0], op1.ulow (), op2.ulow ());
kono
parents:
diff changeset
1338 if (val[1] < 0 && prec > HOST_BITS_PER_WIDE_INT * 2)
kono
parents:
diff changeset
1339 {
kono
parents:
diff changeset
1340 val[2] = 0;
kono
parents:
diff changeset
1341 return 3;
kono
parents:
diff changeset
1342 }
kono
parents:
diff changeset
1343 return 1 + (val[1] != 0 || val[0] < 0);
kono
parents:
diff changeset
1344 }
kono
parents:
diff changeset
1345 /* Likewise if the output is a full single HWI, except that the
kono
parents:
diff changeset
1346 upper HWI of the result is only used for determining overflow.
kono
parents:
diff changeset
1347 (We handle this case inline when overflow isn't needed.) */
kono
parents:
diff changeset
1348 else if (prec == HOST_BITS_PER_WIDE_INT)
kono
parents:
diff changeset
1349 {
kono
parents:
diff changeset
1350 unsigned HOST_WIDE_INT upper;
kono
parents:
diff changeset
1351 umul_ppmm (upper, val[0], op1.ulow (), op2.ulow ());
kono
parents:
diff changeset
1352 if (needs_overflow)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1353 /* Unsigned overflow can only be +OVERFLOW. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1354 *overflow = (upper != 0) ? wi::OVF_OVERFLOW : wi::OVF_NONE;
111
kono
parents:
diff changeset
1355 if (high)
kono
parents:
diff changeset
1356 val[0] = upper;
kono
parents:
diff changeset
1357 return 1;
kono
parents:
diff changeset
1358 }
kono
parents:
diff changeset
1359 }
kono
parents:
diff changeset
1360 #endif
kono
parents:
diff changeset
1361
kono
parents:
diff changeset
1362 /* Handle multiplications by 1. */
kono
parents:
diff changeset
1363 if (op1 == 1)
kono
parents:
diff changeset
1364 {
kono
parents:
diff changeset
1365 if (high)
kono
parents:
diff changeset
1366 {
kono
parents:
diff changeset
1367 val[0] = wi::neg_p (op2, sgn) ? -1 : 0;
kono
parents:
diff changeset
1368 return 1;
kono
parents:
diff changeset
1369 }
kono
parents:
diff changeset
1370 for (i = 0; i < op2len; i++)
kono
parents:
diff changeset
1371 val[i] = op2val[i];
kono
parents:
diff changeset
1372 return op2len;
kono
parents:
diff changeset
1373 }
kono
parents:
diff changeset
1374 if (op2 == 1)
kono
parents:
diff changeset
1375 {
kono
parents:
diff changeset
1376 if (high)
kono
parents:
diff changeset
1377 {
kono
parents:
diff changeset
1378 val[0] = wi::neg_p (op1, sgn) ? -1 : 0;
kono
parents:
diff changeset
1379 return 1;
kono
parents:
diff changeset
1380 }
kono
parents:
diff changeset
1381 for (i = 0; i < op1len; i++)
kono
parents:
diff changeset
1382 val[i] = op1val[i];
kono
parents:
diff changeset
1383 return op1len;
kono
parents:
diff changeset
1384 }
kono
parents:
diff changeset
1385
kono
parents:
diff changeset
1386 /* If we need to check for overflow, we can only do half wide
kono
parents:
diff changeset
1387 multiplies quickly because we need to look at the top bits to
kono
parents:
diff changeset
1388 check for the overflow. */
kono
parents:
diff changeset
1389 if ((high || needs_overflow)
kono
parents:
diff changeset
1390 && (prec <= HOST_BITS_PER_HALF_WIDE_INT))
kono
parents:
diff changeset
1391 {
kono
parents:
diff changeset
1392 unsigned HOST_WIDE_INT r;
kono
parents:
diff changeset
1393
kono
parents:
diff changeset
1394 if (sgn == SIGNED)
kono
parents:
diff changeset
1395 {
kono
parents:
diff changeset
1396 o0 = op1.to_shwi ();
kono
parents:
diff changeset
1397 o1 = op2.to_shwi ();
kono
parents:
diff changeset
1398 }
kono
parents:
diff changeset
1399 else
kono
parents:
diff changeset
1400 {
kono
parents:
diff changeset
1401 o0 = op1.to_uhwi ();
kono
parents:
diff changeset
1402 o1 = op2.to_uhwi ();
kono
parents:
diff changeset
1403 }
kono
parents:
diff changeset
1404
kono
parents:
diff changeset
1405 r = o0 * o1;
kono
parents:
diff changeset
1406 if (needs_overflow)
kono
parents:
diff changeset
1407 {
kono
parents:
diff changeset
1408 if (sgn == SIGNED)
kono
parents:
diff changeset
1409 {
kono
parents:
diff changeset
1410 if ((HOST_WIDE_INT) r != sext_hwi (r, prec))
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1411 /* FIXME: Signed overflow type is not implemented yet. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1412 *overflow = OVF_UNKNOWN;
111
kono
parents:
diff changeset
1413 }
kono
parents:
diff changeset
1414 else
kono
parents:
diff changeset
1415 {
kono
parents:
diff changeset
1416 if ((r >> prec) != 0)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1417 /* Unsigned overflow can only be +OVERFLOW. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1418 *overflow = OVF_OVERFLOW;
111
kono
parents:
diff changeset
1419 }
kono
parents:
diff changeset
1420 }
kono
parents:
diff changeset
1421 val[0] = high ? r >> prec : r;
kono
parents:
diff changeset
1422 return 1;
kono
parents:
diff changeset
1423 }
kono
parents:
diff changeset
1424
kono
parents:
diff changeset
1425 /* We do unsigned mul and then correct it. */
kono
parents:
diff changeset
1426 wi_unpack (u, op1val, op1len, half_blocks_needed, prec, SIGNED);
kono
parents:
diff changeset
1427 wi_unpack (v, op2val, op2len, half_blocks_needed, prec, SIGNED);
kono
parents:
diff changeset
1428
kono
parents:
diff changeset
1429 /* The 2 is for a full mult. */
kono
parents:
diff changeset
1430 memset (r, 0, half_blocks_needed * 2
kono
parents:
diff changeset
1431 * HOST_BITS_PER_HALF_WIDE_INT / CHAR_BIT);
kono
parents:
diff changeset
1432
kono
parents:
diff changeset
1433 for (j = 0; j < half_blocks_needed; j++)
kono
parents:
diff changeset
1434 {
kono
parents:
diff changeset
1435 k = 0;
kono
parents:
diff changeset
1436 for (i = 0; i < half_blocks_needed; i++)
kono
parents:
diff changeset
1437 {
kono
parents:
diff changeset
1438 t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
kono
parents:
diff changeset
1439 + r[i + j] + k);
kono
parents:
diff changeset
1440 r[i + j] = t & HALF_INT_MASK;
kono
parents:
diff changeset
1441 k = t >> HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1442 }
kono
parents:
diff changeset
1443 r[j + half_blocks_needed] = k;
kono
parents:
diff changeset
1444 }
kono
parents:
diff changeset
1445
kono
parents:
diff changeset
1446 /* We did unsigned math above. For signed we must adjust the
kono
parents:
diff changeset
1447 product (assuming we need to see that). */
kono
parents:
diff changeset
1448 if (sgn == SIGNED && (high || needs_overflow))
kono
parents:
diff changeset
1449 {
kono
parents:
diff changeset
1450 unsigned HOST_WIDE_INT b;
kono
parents:
diff changeset
1451 if (wi::neg_p (op1))
kono
parents:
diff changeset
1452 {
kono
parents:
diff changeset
1453 b = 0;
kono
parents:
diff changeset
1454 for (i = 0; i < half_blocks_needed; i++)
kono
parents:
diff changeset
1455 {
kono
parents:
diff changeset
1456 t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
kono
parents:
diff changeset
1457 - (unsigned HOST_WIDE_INT)v[i] - b;
kono
parents:
diff changeset
1458 r[i + half_blocks_needed] = t & HALF_INT_MASK;
kono
parents:
diff changeset
1459 b = t >> (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
1460 }
kono
parents:
diff changeset
1461 }
kono
parents:
diff changeset
1462 if (wi::neg_p (op2))
kono
parents:
diff changeset
1463 {
kono
parents:
diff changeset
1464 b = 0;
kono
parents:
diff changeset
1465 for (i = 0; i < half_blocks_needed; i++)
kono
parents:
diff changeset
1466 {
kono
parents:
diff changeset
1467 t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
kono
parents:
diff changeset
1468 - (unsigned HOST_WIDE_INT)u[i] - b;
kono
parents:
diff changeset
1469 r[i + half_blocks_needed] = t & HALF_INT_MASK;
kono
parents:
diff changeset
1470 b = t >> (HOST_BITS_PER_WIDE_INT - 1);
kono
parents:
diff changeset
1471 }
kono
parents:
diff changeset
1472 }
kono
parents:
diff changeset
1473 }
kono
parents:
diff changeset
1474
kono
parents:
diff changeset
1475 if (needs_overflow)
kono
parents:
diff changeset
1476 {
kono
parents:
diff changeset
1477 HOST_WIDE_INT top;
kono
parents:
diff changeset
1478
kono
parents:
diff changeset
1479 /* For unsigned, overflow is true if any of the top bits are set.
kono
parents:
diff changeset
1480 For signed, overflow is true if any of the top bits are not equal
kono
parents:
diff changeset
1481 to the sign bit. */
kono
parents:
diff changeset
1482 if (sgn == UNSIGNED)
kono
parents:
diff changeset
1483 top = 0;
kono
parents:
diff changeset
1484 else
kono
parents:
diff changeset
1485 {
kono
parents:
diff changeset
1486 top = r[(half_blocks_needed) - 1];
kono
parents:
diff changeset
1487 top = SIGN_MASK (top << (HOST_BITS_PER_WIDE_INT / 2));
kono
parents:
diff changeset
1488 top &= mask;
kono
parents:
diff changeset
1489 }
kono
parents:
diff changeset
1490
kono
parents:
diff changeset
1491 for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
kono
parents:
diff changeset
1492 if (((HOST_WIDE_INT)(r[i] & mask)) != top)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1493 /* FIXME: Signed overflow type is not implemented yet. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1494 *overflow = (sgn == UNSIGNED) ? wi::OVF_OVERFLOW : wi::OVF_UNKNOWN;
111
kono
parents:
diff changeset
1495 }
kono
parents:
diff changeset
1496
kono
parents:
diff changeset
1497 int r_offset = high ? half_blocks_needed : 0;
kono
parents:
diff changeset
1498 return wi_pack (val, &r[r_offset], half_blocks_needed, prec);
kono
parents:
diff changeset
1499 }
kono
parents:
diff changeset
1500
kono
parents:
diff changeset
1501 /* Compute the population count of X. */
kono
parents:
diff changeset
1502 int
kono
parents:
diff changeset
1503 wi::popcount (const wide_int_ref &x)
kono
parents:
diff changeset
1504 {
kono
parents:
diff changeset
1505 unsigned int i;
kono
parents:
diff changeset
1506 int count;
kono
parents:
diff changeset
1507
kono
parents:
diff changeset
1508 /* The high order block is special if it is the last block and the
kono
parents:
diff changeset
1509 precision is not an even multiple of HOST_BITS_PER_WIDE_INT. We
kono
parents:
diff changeset
1510 have to clear out any ones above the precision before doing
kono
parents:
diff changeset
1511 popcount on this block. */
kono
parents:
diff changeset
1512 count = x.precision - x.len * HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1513 unsigned int stop = x.len;
kono
parents:
diff changeset
1514 if (count < 0)
kono
parents:
diff changeset
1515 {
kono
parents:
diff changeset
1516 count = popcount_hwi (x.uhigh () << -count);
kono
parents:
diff changeset
1517 stop -= 1;
kono
parents:
diff changeset
1518 }
kono
parents:
diff changeset
1519 else
kono
parents:
diff changeset
1520 {
kono
parents:
diff changeset
1521 if (x.sign_mask () >= 0)
kono
parents:
diff changeset
1522 count = 0;
kono
parents:
diff changeset
1523 }
kono
parents:
diff changeset
1524
kono
parents:
diff changeset
1525 for (i = 0; i < stop; ++i)
kono
parents:
diff changeset
1526 count += popcount_hwi (x.val[i]);
kono
parents:
diff changeset
1527
kono
parents:
diff changeset
1528 return count;
kono
parents:
diff changeset
1529 }
kono
parents:
diff changeset
1530
kono
parents:
diff changeset
1531 /* Set VAL to OP0 - OP1. If OVERFLOW is nonnull, record in *OVERFLOW
kono
parents:
diff changeset
1532 whether the result overflows when OP0 and OP1 are treated as having
kono
parents:
diff changeset
1533 signedness SGN. Return the number of blocks in VAL. */
kono
parents:
diff changeset
1534 unsigned int
kono
parents:
diff changeset
1535 wi::sub_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
kono
parents:
diff changeset
1536 unsigned int op0len, const HOST_WIDE_INT *op1,
kono
parents:
diff changeset
1537 unsigned int op1len, unsigned int prec,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1538 signop sgn, wi::overflow_type *overflow)
111
kono
parents:
diff changeset
1539 {
kono
parents:
diff changeset
1540 unsigned HOST_WIDE_INT o0 = 0;
kono
parents:
diff changeset
1541 unsigned HOST_WIDE_INT o1 = 0;
kono
parents:
diff changeset
1542 unsigned HOST_WIDE_INT x = 0;
kono
parents:
diff changeset
1543 /* We implement subtraction as an in place negate and add. Negation
kono
parents:
diff changeset
1544 is just inversion and add 1, so we can do the add of 1 by just
kono
parents:
diff changeset
1545 starting the borrow in of the first element at 1. */
kono
parents:
diff changeset
1546 unsigned HOST_WIDE_INT borrow = 0;
kono
parents:
diff changeset
1547 unsigned HOST_WIDE_INT old_borrow = 0;
kono
parents:
diff changeset
1548
kono
parents:
diff changeset
1549 unsigned HOST_WIDE_INT mask0, mask1;
kono
parents:
diff changeset
1550 unsigned int i;
kono
parents:
diff changeset
1551
kono
parents:
diff changeset
1552 unsigned int len = MAX (op0len, op1len);
kono
parents:
diff changeset
1553 mask0 = -top_bit_of (op0, op0len, prec);
kono
parents:
diff changeset
1554 mask1 = -top_bit_of (op1, op1len, prec);
kono
parents:
diff changeset
1555
kono
parents:
diff changeset
1556 /* Subtract all of the explicitly defined elements. */
kono
parents:
diff changeset
1557 for (i = 0; i < len; i++)
kono
parents:
diff changeset
1558 {
kono
parents:
diff changeset
1559 o0 = i < op0len ? (unsigned HOST_WIDE_INT)op0[i] : mask0;
kono
parents:
diff changeset
1560 o1 = i < op1len ? (unsigned HOST_WIDE_INT)op1[i] : mask1;
kono
parents:
diff changeset
1561 x = o0 - o1 - borrow;
kono
parents:
diff changeset
1562 val[i] = x;
kono
parents:
diff changeset
1563 old_borrow = borrow;
kono
parents:
diff changeset
1564 borrow = borrow == 0 ? o0 < o1 : o0 <= o1;
kono
parents:
diff changeset
1565 }
kono
parents:
diff changeset
1566
kono
parents:
diff changeset
1567 if (len * HOST_BITS_PER_WIDE_INT < prec)
kono
parents:
diff changeset
1568 {
kono
parents:
diff changeset
1569 val[len] = mask0 - mask1 - borrow;
kono
parents:
diff changeset
1570 len++;
kono
parents:
diff changeset
1571 if (overflow)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1572 *overflow = (sgn == UNSIGNED && borrow) ? OVF_UNDERFLOW : OVF_NONE;
111
kono
parents:
diff changeset
1573 }
kono
parents:
diff changeset
1574 else if (overflow)
kono
parents:
diff changeset
1575 {
kono
parents:
diff changeset
1576 unsigned int shift = -prec % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1577 if (sgn == SIGNED)
kono
parents:
diff changeset
1578 {
kono
parents:
diff changeset
1579 unsigned HOST_WIDE_INT x = (o0 ^ o1) & (val[len - 1] ^ o0);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1580 if ((HOST_WIDE_INT) (x << shift) < 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1581 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1582 if (o0 > o1)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1583 *overflow = OVF_UNDERFLOW;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1584 else if (o0 < o1)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1585 *overflow = OVF_OVERFLOW;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1586 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1587 *overflow = OVF_NONE;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1588 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1589 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1590 *overflow = OVF_NONE;
111
kono
parents:
diff changeset
1591 }
kono
parents:
diff changeset
1592 else
kono
parents:
diff changeset
1593 {
kono
parents:
diff changeset
1594 /* Put the MSB of X and O0 and in the top of the HWI. */
kono
parents:
diff changeset
1595 x <<= shift;
kono
parents:
diff changeset
1596 o0 <<= shift;
kono
parents:
diff changeset
1597 if (old_borrow)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1598 *overflow = (x >= o0) ? OVF_UNDERFLOW : OVF_NONE;
111
kono
parents:
diff changeset
1599 else
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1600 *overflow = (x > o0) ? OVF_UNDERFLOW : OVF_NONE;
111
kono
parents:
diff changeset
1601 }
kono
parents:
diff changeset
1602 }
kono
parents:
diff changeset
1603
kono
parents:
diff changeset
1604 return canonize (val, len, prec);
kono
parents:
diff changeset
1605 }
kono
parents:
diff changeset
1606
kono
parents:
diff changeset
1607
kono
parents:
diff changeset
1608 /*
kono
parents:
diff changeset
1609 * Division and Mod
kono
parents:
diff changeset
1610 */
kono
parents:
diff changeset
1611
kono
parents:
diff changeset
1612 /* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR. The
kono
parents:
diff changeset
1613 algorithm is a small modification of the algorithm in Hacker's
kono
parents:
diff changeset
1614 Delight by Warren, which itself is a small modification of Knuth's
kono
parents:
diff changeset
1615 algorithm. M is the number of significant elements of U however
kono
parents:
diff changeset
1616 there needs to be at least one extra element of B_DIVIDEND
kono
parents:
diff changeset
1617 allocated, N is the number of elements of B_DIVISOR. */
kono
parents:
diff changeset
1618 static void
kono
parents:
diff changeset
1619 divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient,
kono
parents:
diff changeset
1620 unsigned HOST_HALF_WIDE_INT *b_remainder,
kono
parents:
diff changeset
1621 unsigned HOST_HALF_WIDE_INT *b_dividend,
kono
parents:
diff changeset
1622 unsigned HOST_HALF_WIDE_INT *b_divisor,
kono
parents:
diff changeset
1623 int m, int n)
kono
parents:
diff changeset
1624 {
kono
parents:
diff changeset
1625 /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
kono
parents:
diff changeset
1626 HOST_WIDE_INT and stored in the lower bits of each word. This
kono
parents:
diff changeset
1627 algorithm should work properly on both 32 and 64 bit
kono
parents:
diff changeset
1628 machines. */
kono
parents:
diff changeset
1629 unsigned HOST_WIDE_INT b
kono
parents:
diff changeset
1630 = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1631 unsigned HOST_WIDE_INT qhat; /* Estimate of quotient digit. */
kono
parents:
diff changeset
1632 unsigned HOST_WIDE_INT rhat; /* A remainder. */
kono
parents:
diff changeset
1633 unsigned HOST_WIDE_INT p; /* Product of two digits. */
kono
parents:
diff changeset
1634 HOST_WIDE_INT t, k;
kono
parents:
diff changeset
1635 int i, j, s;
kono
parents:
diff changeset
1636
kono
parents:
diff changeset
1637 /* Single digit divisor. */
kono
parents:
diff changeset
1638 if (n == 1)
kono
parents:
diff changeset
1639 {
kono
parents:
diff changeset
1640 k = 0;
kono
parents:
diff changeset
1641 for (j = m - 1; j >= 0; j--)
kono
parents:
diff changeset
1642 {
kono
parents:
diff changeset
1643 b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
kono
parents:
diff changeset
1644 k = ((k * b + b_dividend[j])
kono
parents:
diff changeset
1645 - ((unsigned HOST_WIDE_INT)b_quotient[j]
kono
parents:
diff changeset
1646 * (unsigned HOST_WIDE_INT)b_divisor[0]));
kono
parents:
diff changeset
1647 }
kono
parents:
diff changeset
1648 b_remainder[0] = k;
kono
parents:
diff changeset
1649 return;
kono
parents:
diff changeset
1650 }
kono
parents:
diff changeset
1651
kono
parents:
diff changeset
1652 s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
kono
parents:
diff changeset
1653
kono
parents:
diff changeset
1654 if (s)
kono
parents:
diff changeset
1655 {
kono
parents:
diff changeset
1656 /* Normalize B_DIVIDEND and B_DIVISOR. Unlike the published
kono
parents:
diff changeset
1657 algorithm, we can overwrite b_dividend and b_divisor, so we do
kono
parents:
diff changeset
1658 that. */
kono
parents:
diff changeset
1659 for (i = n - 1; i > 0; i--)
kono
parents:
diff changeset
1660 b_divisor[i] = (b_divisor[i] << s)
kono
parents:
diff changeset
1661 | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
kono
parents:
diff changeset
1662 b_divisor[0] = b_divisor[0] << s;
kono
parents:
diff changeset
1663
kono
parents:
diff changeset
1664 b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
kono
parents:
diff changeset
1665 for (i = m - 1; i > 0; i--)
kono
parents:
diff changeset
1666 b_dividend[i] = (b_dividend[i] << s)
kono
parents:
diff changeset
1667 | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
kono
parents:
diff changeset
1668 b_dividend[0] = b_dividend[0] << s;
kono
parents:
diff changeset
1669 }
kono
parents:
diff changeset
1670
kono
parents:
diff changeset
1671 /* Main loop. */
kono
parents:
diff changeset
1672 for (j = m - n; j >= 0; j--)
kono
parents:
diff changeset
1673 {
kono
parents:
diff changeset
1674 qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
kono
parents:
diff changeset
1675 rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
kono
parents:
diff changeset
1676 again:
kono
parents:
diff changeset
1677 if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
kono
parents:
diff changeset
1678 {
kono
parents:
diff changeset
1679 qhat -= 1;
kono
parents:
diff changeset
1680 rhat += b_divisor[n-1];
kono
parents:
diff changeset
1681 if (rhat < b)
kono
parents:
diff changeset
1682 goto again;
kono
parents:
diff changeset
1683 }
kono
parents:
diff changeset
1684
kono
parents:
diff changeset
1685 /* Multiply and subtract. */
kono
parents:
diff changeset
1686 k = 0;
kono
parents:
diff changeset
1687 for (i = 0; i < n; i++)
kono
parents:
diff changeset
1688 {
kono
parents:
diff changeset
1689 p = qhat * b_divisor[i];
kono
parents:
diff changeset
1690 t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
kono
parents:
diff changeset
1691 b_dividend[i + j] = t;
kono
parents:
diff changeset
1692 k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
kono
parents:
diff changeset
1693 - (t >> HOST_BITS_PER_HALF_WIDE_INT));
kono
parents:
diff changeset
1694 }
kono
parents:
diff changeset
1695 t = b_dividend[j+n] - k;
kono
parents:
diff changeset
1696 b_dividend[j+n] = t;
kono
parents:
diff changeset
1697
kono
parents:
diff changeset
1698 b_quotient[j] = qhat;
kono
parents:
diff changeset
1699 if (t < 0)
kono
parents:
diff changeset
1700 {
kono
parents:
diff changeset
1701 b_quotient[j] -= 1;
kono
parents:
diff changeset
1702 k = 0;
kono
parents:
diff changeset
1703 for (i = 0; i < n; i++)
kono
parents:
diff changeset
1704 {
kono
parents:
diff changeset
1705 t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
kono
parents:
diff changeset
1706 b_dividend[i+j] = t;
kono
parents:
diff changeset
1707 k = t >> HOST_BITS_PER_HALF_WIDE_INT;
kono
parents:
diff changeset
1708 }
kono
parents:
diff changeset
1709 b_dividend[j+n] += k;
kono
parents:
diff changeset
1710 }
kono
parents:
diff changeset
1711 }
kono
parents:
diff changeset
1712 if (s)
kono
parents:
diff changeset
1713 for (i = 0; i < n; i++)
kono
parents:
diff changeset
1714 b_remainder[i] = (b_dividend[i] >> s)
kono
parents:
diff changeset
1715 | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
kono
parents:
diff changeset
1716 else
kono
parents:
diff changeset
1717 for (i = 0; i < n; i++)
kono
parents:
diff changeset
1718 b_remainder[i] = b_dividend[i];
kono
parents:
diff changeset
1719 }
kono
parents:
diff changeset
1720
kono
parents:
diff changeset
1721
kono
parents:
diff changeset
1722 /* Divide DIVIDEND by DIVISOR, which have signedness SGN, and truncate
kono
parents:
diff changeset
1723 the result. If QUOTIENT is nonnull, store the value of the quotient
kono
parents:
diff changeset
1724 there and return the number of blocks in it. The return value is
kono
parents:
diff changeset
1725 not defined otherwise. If REMAINDER is nonnull, store the value
kono
parents:
diff changeset
1726 of the remainder there and store the number of blocks in
kono
parents:
diff changeset
1727 *REMAINDER_LEN. If OFLOW is not null, store in *OFLOW whether
kono
parents:
diff changeset
1728 the division overflowed. */
kono
parents:
diff changeset
1729 unsigned int
kono
parents:
diff changeset
1730 wi::divmod_internal (HOST_WIDE_INT *quotient, unsigned int *remainder_len,
kono
parents:
diff changeset
1731 HOST_WIDE_INT *remainder,
kono
parents:
diff changeset
1732 const HOST_WIDE_INT *dividend_val,
kono
parents:
diff changeset
1733 unsigned int dividend_len, unsigned int dividend_prec,
kono
parents:
diff changeset
1734 const HOST_WIDE_INT *divisor_val, unsigned int divisor_len,
kono
parents:
diff changeset
1735 unsigned int divisor_prec, signop sgn,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1736 wi::overflow_type *oflow)
111
kono
parents:
diff changeset
1737 {
kono
parents:
diff changeset
1738 unsigned int dividend_blocks_needed = 2 * BLOCKS_NEEDED (dividend_prec);
kono
parents:
diff changeset
1739 unsigned int divisor_blocks_needed = 2 * BLOCKS_NEEDED (divisor_prec);
kono
parents:
diff changeset
1740 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1741 b_quotient[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1742 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1743 b_remainder[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1744 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1745 b_dividend[(4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
kono
parents:
diff changeset
1746 unsigned HOST_HALF_WIDE_INT
kono
parents:
diff changeset
1747 b_divisor[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
kono
parents:
diff changeset
1748 unsigned int m, n;
kono
parents:
diff changeset
1749 bool dividend_neg = false;
kono
parents:
diff changeset
1750 bool divisor_neg = false;
kono
parents:
diff changeset
1751 bool overflow = false;
kono
parents:
diff changeset
1752 wide_int neg_dividend, neg_divisor;
kono
parents:
diff changeset
1753
kono
parents:
diff changeset
1754 wide_int_ref dividend = wi::storage_ref (dividend_val, dividend_len,
kono
parents:
diff changeset
1755 dividend_prec);
kono
parents:
diff changeset
1756 wide_int_ref divisor = wi::storage_ref (divisor_val, divisor_len,
kono
parents:
diff changeset
1757 divisor_prec);
kono
parents:
diff changeset
1758 if (divisor == 0)
kono
parents:
diff changeset
1759 overflow = true;
kono
parents:
diff changeset
1760
kono
parents:
diff changeset
1761 /* The smallest signed number / -1 causes overflow. The dividend_len
kono
parents:
diff changeset
1762 check is for speed rather than correctness. */
kono
parents:
diff changeset
1763 if (sgn == SIGNED
kono
parents:
diff changeset
1764 && dividend_len == BLOCKS_NEEDED (dividend_prec)
kono
parents:
diff changeset
1765 && divisor == -1
kono
parents:
diff changeset
1766 && wi::only_sign_bit_p (dividend))
kono
parents:
diff changeset
1767 overflow = true;
kono
parents:
diff changeset
1768
kono
parents:
diff changeset
1769 /* Handle the overflow cases. Viewed as unsigned value, the quotient of
kono
parents:
diff changeset
1770 (signed min / -1) has the same representation as the orignal dividend.
kono
parents:
diff changeset
1771 We have traditionally made division by zero act as division by one,
kono
parents:
diff changeset
1772 so there too we use the original dividend. */
kono
parents:
diff changeset
1773 if (overflow)
kono
parents:
diff changeset
1774 {
kono
parents:
diff changeset
1775 if (remainder)
kono
parents:
diff changeset
1776 {
kono
parents:
diff changeset
1777 *remainder_len = 1;
kono
parents:
diff changeset
1778 remainder[0] = 0;
kono
parents:
diff changeset
1779 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1780 if (oflow)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1781 *oflow = OVF_OVERFLOW;
111
kono
parents:
diff changeset
1782 if (quotient)
kono
parents:
diff changeset
1783 for (unsigned int i = 0; i < dividend_len; ++i)
kono
parents:
diff changeset
1784 quotient[i] = dividend_val[i];
kono
parents:
diff changeset
1785 return dividend_len;
kono
parents:
diff changeset
1786 }
kono
parents:
diff changeset
1787
kono
parents:
diff changeset
1788 if (oflow)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1789 *oflow = OVF_NONE;
111
kono
parents:
diff changeset
1790
kono
parents:
diff changeset
1791 /* Do it on the host if you can. */
kono
parents:
diff changeset
1792 if (sgn == SIGNED
kono
parents:
diff changeset
1793 && wi::fits_shwi_p (dividend)
kono
parents:
diff changeset
1794 && wi::fits_shwi_p (divisor))
kono
parents:
diff changeset
1795 {
kono
parents:
diff changeset
1796 HOST_WIDE_INT o0 = dividend.to_shwi ();
kono
parents:
diff changeset
1797 HOST_WIDE_INT o1 = divisor.to_shwi ();
kono
parents:
diff changeset
1798
kono
parents:
diff changeset
1799 if (o0 == HOST_WIDE_INT_MIN && o1 == -1)
kono
parents:
diff changeset
1800 {
kono
parents:
diff changeset
1801 gcc_checking_assert (dividend_prec > HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
1802 if (quotient)
kono
parents:
diff changeset
1803 {
kono
parents:
diff changeset
1804 quotient[0] = HOST_WIDE_INT_MIN;
kono
parents:
diff changeset
1805 quotient[1] = 0;
kono
parents:
diff changeset
1806 }
kono
parents:
diff changeset
1807 if (remainder)
kono
parents:
diff changeset
1808 {
kono
parents:
diff changeset
1809 remainder[0] = 0;
kono
parents:
diff changeset
1810 *remainder_len = 1;
kono
parents:
diff changeset
1811 }
kono
parents:
diff changeset
1812 return 2;
kono
parents:
diff changeset
1813 }
kono
parents:
diff changeset
1814 else
kono
parents:
diff changeset
1815 {
kono
parents:
diff changeset
1816 if (quotient)
kono
parents:
diff changeset
1817 quotient[0] = o0 / o1;
kono
parents:
diff changeset
1818 if (remainder)
kono
parents:
diff changeset
1819 {
kono
parents:
diff changeset
1820 remainder[0] = o0 % o1;
kono
parents:
diff changeset
1821 *remainder_len = 1;
kono
parents:
diff changeset
1822 }
kono
parents:
diff changeset
1823 return 1;
kono
parents:
diff changeset
1824 }
kono
parents:
diff changeset
1825 }
kono
parents:
diff changeset
1826
kono
parents:
diff changeset
1827 if (sgn == UNSIGNED
kono
parents:
diff changeset
1828 && wi::fits_uhwi_p (dividend)
kono
parents:
diff changeset
1829 && wi::fits_uhwi_p (divisor))
kono
parents:
diff changeset
1830 {
kono
parents:
diff changeset
1831 unsigned HOST_WIDE_INT o0 = dividend.to_uhwi ();
kono
parents:
diff changeset
1832 unsigned HOST_WIDE_INT o1 = divisor.to_uhwi ();
kono
parents:
diff changeset
1833 unsigned int quotient_len = 1;
kono
parents:
diff changeset
1834
kono
parents:
diff changeset
1835 if (quotient)
kono
parents:
diff changeset
1836 {
kono
parents:
diff changeset
1837 quotient[0] = o0 / o1;
kono
parents:
diff changeset
1838 quotient_len = canonize_uhwi (quotient, dividend_prec);
kono
parents:
diff changeset
1839 }
kono
parents:
diff changeset
1840 if (remainder)
kono
parents:
diff changeset
1841 {
kono
parents:
diff changeset
1842 remainder[0] = o0 % o1;
kono
parents:
diff changeset
1843 *remainder_len = canonize_uhwi (remainder, dividend_prec);
kono
parents:
diff changeset
1844 }
kono
parents:
diff changeset
1845 return quotient_len;
kono
parents:
diff changeset
1846 }
kono
parents:
diff changeset
1847
kono
parents:
diff changeset
1848 /* Make the divisor and dividend positive and remember what we
kono
parents:
diff changeset
1849 did. */
kono
parents:
diff changeset
1850 if (sgn == SIGNED)
kono
parents:
diff changeset
1851 {
kono
parents:
diff changeset
1852 if (wi::neg_p (dividend))
kono
parents:
diff changeset
1853 {
kono
parents:
diff changeset
1854 neg_dividend = -dividend;
kono
parents:
diff changeset
1855 dividend = neg_dividend;
kono
parents:
diff changeset
1856 dividend_neg = true;
kono
parents:
diff changeset
1857 }
kono
parents:
diff changeset
1858 if (wi::neg_p (divisor))
kono
parents:
diff changeset
1859 {
kono
parents:
diff changeset
1860 neg_divisor = -divisor;
kono
parents:
diff changeset
1861 divisor = neg_divisor;
kono
parents:
diff changeset
1862 divisor_neg = true;
kono
parents:
diff changeset
1863 }
kono
parents:
diff changeset
1864 }
kono
parents:
diff changeset
1865
kono
parents:
diff changeset
1866 wi_unpack (b_dividend, dividend.get_val (), dividend.get_len (),
kono
parents:
diff changeset
1867 dividend_blocks_needed, dividend_prec, sgn);
kono
parents:
diff changeset
1868 wi_unpack (b_divisor, divisor.get_val (), divisor.get_len (),
kono
parents:
diff changeset
1869 divisor_blocks_needed, divisor_prec, sgn);
kono
parents:
diff changeset
1870
kono
parents:
diff changeset
1871 m = dividend_blocks_needed;
kono
parents:
diff changeset
1872 b_dividend[m] = 0;
kono
parents:
diff changeset
1873 while (m > 1 && b_dividend[m - 1] == 0)
kono
parents:
diff changeset
1874 m--;
kono
parents:
diff changeset
1875
kono
parents:
diff changeset
1876 n = divisor_blocks_needed;
kono
parents:
diff changeset
1877 while (n > 1 && b_divisor[n - 1] == 0)
kono
parents:
diff changeset
1878 n--;
kono
parents:
diff changeset
1879
kono
parents:
diff changeset
1880 memset (b_quotient, 0, sizeof (b_quotient));
kono
parents:
diff changeset
1881
kono
parents:
diff changeset
1882 divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
kono
parents:
diff changeset
1883
kono
parents:
diff changeset
1884 unsigned int quotient_len = 0;
kono
parents:
diff changeset
1885 if (quotient)
kono
parents:
diff changeset
1886 {
kono
parents:
diff changeset
1887 quotient_len = wi_pack (quotient, b_quotient, m, dividend_prec);
kono
parents:
diff changeset
1888 /* The quotient is neg if exactly one of the divisor or dividend is
kono
parents:
diff changeset
1889 neg. */
kono
parents:
diff changeset
1890 if (dividend_neg != divisor_neg)
kono
parents:
diff changeset
1891 quotient_len = wi::sub_large (quotient, zeros, 1, quotient,
kono
parents:
diff changeset
1892 quotient_len, dividend_prec,
kono
parents:
diff changeset
1893 UNSIGNED, 0);
kono
parents:
diff changeset
1894 }
kono
parents:
diff changeset
1895
kono
parents:
diff changeset
1896 if (remainder)
kono
parents:
diff changeset
1897 {
kono
parents:
diff changeset
1898 *remainder_len = wi_pack (remainder, b_remainder, n, dividend_prec);
kono
parents:
diff changeset
1899 /* The remainder is always the same sign as the dividend. */
kono
parents:
diff changeset
1900 if (dividend_neg)
kono
parents:
diff changeset
1901 *remainder_len = wi::sub_large (remainder, zeros, 1, remainder,
kono
parents:
diff changeset
1902 *remainder_len, dividend_prec,
kono
parents:
diff changeset
1903 UNSIGNED, 0);
kono
parents:
diff changeset
1904 }
kono
parents:
diff changeset
1905
kono
parents:
diff changeset
1906 return quotient_len;
kono
parents:
diff changeset
1907 }
kono
parents:
diff changeset
1908
kono
parents:
diff changeset
1909 /*
kono
parents:
diff changeset
1910 * Shifting, rotating and extraction.
kono
parents:
diff changeset
1911 */
kono
parents:
diff changeset
1912
kono
parents:
diff changeset
1913 /* Left shift XVAL by SHIFT and store the result in VAL. Return the
kono
parents:
diff changeset
1914 number of blocks in VAL. Both XVAL and VAL have PRECISION bits. */
kono
parents:
diff changeset
1915 unsigned int
kono
parents:
diff changeset
1916 wi::lshift_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
1917 unsigned int xlen, unsigned int precision,
kono
parents:
diff changeset
1918 unsigned int shift)
kono
parents:
diff changeset
1919 {
kono
parents:
diff changeset
1920 /* Split the shift into a whole-block shift and a subblock shift. */
kono
parents:
diff changeset
1921 unsigned int skip = shift / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1922 unsigned int small_shift = shift % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1923
kono
parents:
diff changeset
1924 /* The whole-block shift fills with zeros. */
kono
parents:
diff changeset
1925 unsigned int len = BLOCKS_NEEDED (precision);
kono
parents:
diff changeset
1926 for (unsigned int i = 0; i < skip; ++i)
kono
parents:
diff changeset
1927 val[i] = 0;
kono
parents:
diff changeset
1928
kono
parents:
diff changeset
1929 /* It's easier to handle the simple block case specially. */
kono
parents:
diff changeset
1930 if (small_shift == 0)
kono
parents:
diff changeset
1931 for (unsigned int i = skip; i < len; ++i)
kono
parents:
diff changeset
1932 val[i] = safe_uhwi (xval, xlen, i - skip);
kono
parents:
diff changeset
1933 else
kono
parents:
diff changeset
1934 {
kono
parents:
diff changeset
1935 /* The first unfilled output block is a left shift of the first
kono
parents:
diff changeset
1936 block in XVAL. The other output blocks contain bits from two
kono
parents:
diff changeset
1937 consecutive input blocks. */
kono
parents:
diff changeset
1938 unsigned HOST_WIDE_INT carry = 0;
kono
parents:
diff changeset
1939 for (unsigned int i = skip; i < len; ++i)
kono
parents:
diff changeset
1940 {
kono
parents:
diff changeset
1941 unsigned HOST_WIDE_INT x = safe_uhwi (xval, xlen, i - skip);
kono
parents:
diff changeset
1942 val[i] = (x << small_shift) | carry;
kono
parents:
diff changeset
1943 carry = x >> (-small_shift % HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
1944 }
kono
parents:
diff changeset
1945 }
kono
parents:
diff changeset
1946 return canonize (val, len, precision);
kono
parents:
diff changeset
1947 }
kono
parents:
diff changeset
1948
kono
parents:
diff changeset
1949 /* Right shift XVAL by SHIFT and store the result in VAL. Return the
kono
parents:
diff changeset
1950 number of blocks in VAL. The input has XPRECISION bits and the
kono
parents:
diff changeset
1951 output has XPRECISION - SHIFT bits. */
kono
parents:
diff changeset
1952 static unsigned int
kono
parents:
diff changeset
1953 rshift_large_common (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
1954 unsigned int xlen, unsigned int xprecision,
kono
parents:
diff changeset
1955 unsigned int shift)
kono
parents:
diff changeset
1956 {
kono
parents:
diff changeset
1957 /* Split the shift into a whole-block shift and a subblock shift. */
kono
parents:
diff changeset
1958 unsigned int skip = shift / HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1959 unsigned int small_shift = shift % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
1960
kono
parents:
diff changeset
1961 /* Work out how many blocks are needed to store the significant bits
kono
parents:
diff changeset
1962 (excluding the upper zeros or signs). */
kono
parents:
diff changeset
1963 unsigned int len = BLOCKS_NEEDED (xprecision - shift);
kono
parents:
diff changeset
1964
kono
parents:
diff changeset
1965 /* It's easier to handle the simple block case specially. */
kono
parents:
diff changeset
1966 if (small_shift == 0)
kono
parents:
diff changeset
1967 for (unsigned int i = 0; i < len; ++i)
kono
parents:
diff changeset
1968 val[i] = safe_uhwi (xval, xlen, i + skip);
kono
parents:
diff changeset
1969 else
kono
parents:
diff changeset
1970 {
kono
parents:
diff changeset
1971 /* Each output block but the last is a combination of two input blocks.
kono
parents:
diff changeset
1972 The last block is a right shift of the last block in XVAL. */
kono
parents:
diff changeset
1973 unsigned HOST_WIDE_INT curr = safe_uhwi (xval, xlen, skip);
kono
parents:
diff changeset
1974 for (unsigned int i = 0; i < len; ++i)
kono
parents:
diff changeset
1975 {
kono
parents:
diff changeset
1976 val[i] = curr >> small_shift;
kono
parents:
diff changeset
1977 curr = safe_uhwi (xval, xlen, i + skip + 1);
kono
parents:
diff changeset
1978 val[i] |= curr << (-small_shift % HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
1979 }
kono
parents:
diff changeset
1980 }
kono
parents:
diff changeset
1981 return len;
kono
parents:
diff changeset
1982 }
kono
parents:
diff changeset
1983
kono
parents:
diff changeset
1984 /* Logically 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::lrshift_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 Zero-extend it to wider precisions. */
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] = zext_hwi (val[len - 1], small_prec);
kono
parents:
diff changeset
2001 else if (val[len - 1] < 0)
kono
parents:
diff changeset
2002 {
kono
parents:
diff changeset
2003 /* Add a new block with a zero. */
kono
parents:
diff changeset
2004 val[len++] = 0;
kono
parents:
diff changeset
2005 return len;
kono
parents:
diff changeset
2006 }
kono
parents:
diff changeset
2007 }
kono
parents:
diff changeset
2008 return canonize (val, len, precision);
kono
parents:
diff changeset
2009 }
kono
parents:
diff changeset
2010
kono
parents:
diff changeset
2011 /* Arithmetically right shift XVAL by SHIFT and store the result in VAL.
kono
parents:
diff changeset
2012 Return the number of blocks in VAL. XVAL has XPRECISION bits and
kono
parents:
diff changeset
2013 VAL has PRECISION bits. */
kono
parents:
diff changeset
2014 unsigned int
kono
parents:
diff changeset
2015 wi::arshift_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval,
kono
parents:
diff changeset
2016 unsigned int xlen, unsigned int xprecision,
kono
parents:
diff changeset
2017 unsigned int precision, unsigned int shift)
kono
parents:
diff changeset
2018 {
kono
parents:
diff changeset
2019 unsigned int len = rshift_large_common (val, xval, xlen, xprecision, shift);
kono
parents:
diff changeset
2020
kono
parents:
diff changeset
2021 /* The value we just created has precision XPRECISION - SHIFT.
kono
parents:
diff changeset
2022 Sign-extend it to wider types. */
kono
parents:
diff changeset
2023 if (precision > xprecision - shift)
kono
parents:
diff changeset
2024 {
kono
parents:
diff changeset
2025 unsigned int small_prec = (xprecision - shift) % HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
2026 if (small_prec)
kono
parents:
diff changeset
2027 val[len - 1] = sext_hwi (val[len - 1], small_prec);
kono
parents:
diff changeset
2028 }
kono
parents:
diff changeset
2029 return canonize (val, len, precision);
kono
parents:
diff changeset
2030 }
kono
parents:
diff changeset
2031
kono
parents:
diff changeset
2032 /* Return the number of leading (upper) zeros in X. */
kono
parents:
diff changeset
2033 int
kono
parents:
diff changeset
2034 wi::clz (const wide_int_ref &x)
kono
parents:
diff changeset
2035 {
kono
parents:
diff changeset
2036 /* Calculate how many bits there above the highest represented block. */
kono
parents:
diff changeset
2037 int count = x.precision - x.len * HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
2038
kono
parents:
diff changeset
2039 unsigned HOST_WIDE_INT high = x.uhigh ();
kono
parents:
diff changeset
2040 if (count < 0)
kono
parents:
diff changeset
2041 /* The upper -COUNT bits of HIGH are not part of the value.
kono
parents:
diff changeset
2042 Clear them out. */
kono
parents:
diff changeset
2043 high = (high << -count) >> -count;
kono
parents:
diff changeset
2044 else if (x.sign_mask () < 0)
kono
parents:
diff changeset
2045 /* The upper bit is set, so there are no leading zeros. */
kono
parents:
diff changeset
2046 return 0;
kono
parents:
diff changeset
2047
kono
parents:
diff changeset
2048 /* We don't need to look below HIGH. Either HIGH is nonzero,
kono
parents:
diff changeset
2049 or the top bit of the block below is nonzero; clz_hwi is
kono
parents:
diff changeset
2050 HOST_BITS_PER_WIDE_INT in the latter case. */
kono
parents:
diff changeset
2051 return count + clz_hwi (high);
kono
parents:
diff changeset
2052 }
kono
parents:
diff changeset
2053
kono
parents:
diff changeset
2054 /* Return the number of redundant sign bits in X. (That is, the number
kono
parents:
diff changeset
2055 of bits immediately below the sign bit that have the same value as
kono
parents:
diff changeset
2056 the sign bit.) */
kono
parents:
diff changeset
2057 int
kono
parents:
diff changeset
2058 wi::clrsb (const wide_int_ref &x)
kono
parents:
diff changeset
2059 {
kono
parents:
diff changeset
2060 /* Calculate how many bits there above the highest represented block. */
kono
parents:
diff changeset
2061 int count = x.precision - x.len * HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
2062
kono
parents:
diff changeset
2063 unsigned HOST_WIDE_INT high = x.uhigh ();
kono
parents:
diff changeset
2064 unsigned HOST_WIDE_INT mask = -1;
kono
parents:
diff changeset
2065 if (count < 0)
kono
parents:
diff changeset
2066 {
kono
parents:
diff changeset
2067 /* The upper -COUNT bits of HIGH are not part of the value.
kono
parents:
diff changeset
2068 Clear them from both MASK and HIGH. */
kono
parents:
diff changeset
2069 mask >>= -count;
kono
parents:
diff changeset
2070 high &= mask;
kono
parents:
diff changeset
2071 }
kono
parents:
diff changeset
2072
kono
parents:
diff changeset
2073 /* If the top bit is 1, count the number of leading 1s. If the top
kono
parents:
diff changeset
2074 bit is zero, count the number of leading zeros. */
kono
parents:
diff changeset
2075 if (high > mask / 2)
kono
parents:
diff changeset
2076 high ^= mask;
kono
parents:
diff changeset
2077
kono
parents:
diff changeset
2078 /* There are no sign bits below the top block, so we don't need to look
kono
parents:
diff changeset
2079 beyond HIGH. Note that clz_hwi is HOST_BITS_PER_WIDE_INT when
kono
parents:
diff changeset
2080 HIGH is 0. */
kono
parents:
diff changeset
2081 return count + clz_hwi (high) - 1;
kono
parents:
diff changeset
2082 }
kono
parents:
diff changeset
2083
kono
parents:
diff changeset
2084 /* Return the number of trailing (lower) zeros in X. */
kono
parents:
diff changeset
2085 int
kono
parents:
diff changeset
2086 wi::ctz (const wide_int_ref &x)
kono
parents:
diff changeset
2087 {
kono
parents:
diff changeset
2088 if (x.len == 1 && x.ulow () == 0)
kono
parents:
diff changeset
2089 return x.precision;
kono
parents:
diff changeset
2090
kono
parents:
diff changeset
2091 /* Having dealt with the zero case, there must be a block with a
kono
parents:
diff changeset
2092 nonzero bit. We don't care about the bits above the first 1. */
kono
parents:
diff changeset
2093 unsigned int i = 0;
kono
parents:
diff changeset
2094 while (x.val[i] == 0)
kono
parents:
diff changeset
2095 ++i;
kono
parents:
diff changeset
2096 return i * HOST_BITS_PER_WIDE_INT + ctz_hwi (x.val[i]);
kono
parents:
diff changeset
2097 }
kono
parents:
diff changeset
2098
kono
parents:
diff changeset
2099 /* If X is an exact power of 2, return the base-2 logarithm, otherwise
kono
parents:
diff changeset
2100 return -1. */
kono
parents:
diff changeset
2101 int
kono
parents:
diff changeset
2102 wi::exact_log2 (const wide_int_ref &x)
kono
parents:
diff changeset
2103 {
kono
parents:
diff changeset
2104 /* Reject cases where there are implicit -1 blocks above HIGH. */
kono
parents:
diff changeset
2105 if (x.len * HOST_BITS_PER_WIDE_INT < x.precision && x.sign_mask () < 0)
kono
parents:
diff changeset
2106 return -1;
kono
parents:
diff changeset
2107
kono
parents:
diff changeset
2108 /* Set CRUX to the index of the entry that should be nonzero.
kono
parents:
diff changeset
2109 If the top block is zero then the next lowest block (if any)
kono
parents:
diff changeset
2110 must have the high bit set. */
kono
parents:
diff changeset
2111 unsigned int crux = x.len - 1;
kono
parents:
diff changeset
2112 if (crux > 0 && x.val[crux] == 0)
kono
parents:
diff changeset
2113 crux -= 1;
kono
parents:
diff changeset
2114
kono
parents:
diff changeset
2115 /* Check that all lower blocks are zero. */
kono
parents:
diff changeset
2116 for (unsigned int i = 0; i < crux; ++i)
kono
parents:
diff changeset
2117 if (x.val[i] != 0)
kono
parents:
diff changeset
2118 return -1;
kono
parents:
diff changeset
2119
kono
parents:
diff changeset
2120 /* Get a zero-extended form of block CRUX. */
kono
parents:
diff changeset
2121 unsigned HOST_WIDE_INT hwi = x.val[crux];
kono
parents:
diff changeset
2122 if ((crux + 1) * HOST_BITS_PER_WIDE_INT > x.precision)
kono
parents:
diff changeset
2123 hwi = zext_hwi (hwi, x.precision % HOST_BITS_PER_WIDE_INT);
kono
parents:
diff changeset
2124
kono
parents:
diff changeset
2125 /* Now it's down to whether HWI is a power of 2. */
kono
parents:
diff changeset
2126 int res = ::exact_log2 (hwi);
kono
parents:
diff changeset
2127 if (res >= 0)
kono
parents:
diff changeset
2128 res += crux * HOST_BITS_PER_WIDE_INT;
kono
parents:
diff changeset
2129 return res;
kono
parents:
diff changeset
2130 }
kono
parents:
diff changeset
2131
kono
parents:
diff changeset
2132 /* Return the base-2 logarithm of X, rounding down. Return -1 if X is 0. */
kono
parents:
diff changeset
2133 int
kono
parents:
diff changeset
2134 wi::floor_log2 (const wide_int_ref &x)
kono
parents:
diff changeset
2135 {
kono
parents:
diff changeset
2136 return x.precision - 1 - clz (x);
kono
parents:
diff changeset
2137 }
kono
parents:
diff changeset
2138
kono
parents:
diff changeset
2139 /* Return the index of the first (lowest) set bit in X, counting from 1.
kono
parents:
diff changeset
2140 Return 0 if X is 0. */
kono
parents:
diff changeset
2141 int
kono
parents:
diff changeset
2142 wi::ffs (const wide_int_ref &x)
kono
parents:
diff changeset
2143 {
kono
parents:
diff changeset
2144 return eq_p (x, 0) ? 0 : ctz (x) + 1;
kono
parents:
diff changeset
2145 }
kono
parents:
diff changeset
2146
kono
parents:
diff changeset
2147 /* Return true if sign-extending X to have precision PRECISION would give
kono
parents:
diff changeset
2148 the minimum signed value at that precision. */
kono
parents:
diff changeset
2149 bool
kono
parents:
diff changeset
2150 wi::only_sign_bit_p (const wide_int_ref &x, unsigned int precision)
kono
parents:
diff changeset
2151 {
kono
parents:
diff changeset
2152 return ctz (x) + 1 == int (precision);
kono
parents:
diff changeset
2153 }
kono
parents:
diff changeset
2154
kono
parents:
diff changeset
2155 /* Return true if X represents the minimum signed value. */
kono
parents:
diff changeset
2156 bool
kono
parents:
diff changeset
2157 wi::only_sign_bit_p (const wide_int_ref &x)
kono
parents:
diff changeset
2158 {
kono
parents:
diff changeset
2159 return only_sign_bit_p (x, x.precision);
kono
parents:
diff changeset
2160 }
kono
parents:
diff changeset
2161
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2162 /* Return VAL if VAL has no bits set outside MASK. Otherwise round VAL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2163 down to the previous value that has no bits set outside MASK.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2164 This rounding wraps for signed values if VAL is negative and
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2165 the top bit of MASK is clear.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2166
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2167 For example, round_down_for_mask (6, 0xf1) would give 1 and
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2168 round_down_for_mask (24, 0xf1) would give 17. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2169
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2170 wide_int
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2171 wi::round_down_for_mask (const wide_int &val, const wide_int &mask)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2172 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2173 /* Get the bits in VAL that are outside the mask. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2174 wide_int extra_bits = wi::bit_and_not (val, mask);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2175 if (extra_bits == 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2176 return val;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2177
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2178 /* Get a mask that includes the top bit in EXTRA_BITS and is all 1s
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2179 below that bit. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2180 unsigned int precision = val.get_precision ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2181 wide_int lower_mask = wi::mask (precision - wi::clz (extra_bits),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2182 false, precision);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2183
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2184 /* Clear the bits that aren't in MASK, but ensure that all bits
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2185 in MASK below the top cleared bit are set. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2186 return (val & mask) | (mask & lower_mask);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2187 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2188
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2189 /* Return VAL if VAL has no bits set outside MASK. Otherwise round VAL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2190 up to the next value that has no bits set outside MASK. The rounding
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2191 wraps if there are no suitable values greater than VAL.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2192
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2193 For example, round_up_for_mask (6, 0xf1) would give 16 and
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2194 round_up_for_mask (24, 0xf1) would give 32. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2195
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2196 wide_int
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2197 wi::round_up_for_mask (const wide_int &val, const wide_int &mask)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2198 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2199 /* Get the bits in VAL that are outside the mask. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2200 wide_int extra_bits = wi::bit_and_not (val, mask);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2201 if (extra_bits == 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2202 return val;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2203
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2204 /* Get a mask that is all 1s above the top bit in EXTRA_BITS. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2205 unsigned int precision = val.get_precision ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2206 wide_int upper_mask = wi::mask (precision - wi::clz (extra_bits),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2207 true, precision);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2208
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2209 /* Get the bits of the mask that are above the top bit in EXTRA_BITS. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2210 upper_mask &= mask;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2211
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2212 /* Conceptually we need to:
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2213
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2214 - clear bits of VAL outside UPPER_MASK
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2215 - add the lowest bit in UPPER_MASK to VAL (or add 0 if UPPER_MASK is 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2216 - propagate the carry through the bits of VAL in UPPER_MASK
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2217
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2218 If (~VAL & UPPER_MASK) is nonzero, the carry eventually
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2219 reaches that bit and the process leaves all lower bits clear.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2220 If (~VAL & UPPER_MASK) is zero then the result is also zero. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2221 wide_int tmp = wi::bit_and_not (upper_mask, val);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2222
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2223 return (val | tmp) & -tmp;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2224 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2225
111
kono
parents:
diff changeset
2226 /*
kono
parents:
diff changeset
2227 * Private utilities.
kono
parents:
diff changeset
2228 */
kono
parents:
diff changeset
2229
kono
parents:
diff changeset
2230 void gt_ggc_mx (widest_int *) { }
kono
parents:
diff changeset
2231 void gt_pch_nx (widest_int *, void (*) (void *, void *), void *) { }
kono
parents:
diff changeset
2232 void gt_pch_nx (widest_int *) { }
kono
parents:
diff changeset
2233
kono
parents:
diff changeset
2234 template void wide_int::dump () const;
kono
parents:
diff changeset
2235 template void generic_wide_int <wide_int_ref_storage <false> >::dump () const;
kono
parents:
diff changeset
2236 template void generic_wide_int <wide_int_ref_storage <true> >::dump () const;
kono
parents:
diff changeset
2237 template void offset_int::dump () const;
kono
parents:
diff changeset
2238 template void widest_int::dump () const;
kono
parents:
diff changeset
2239
kono
parents:
diff changeset
2240 /* We could add all the above ::dump variants here, but wide_int and
kono
parents:
diff changeset
2241 widest_int should handle the common cases. Besides, you can always
kono
parents:
diff changeset
2242 call the dump method directly. */
kono
parents:
diff changeset
2243
kono
parents:
diff changeset
2244 DEBUG_FUNCTION void
kono
parents:
diff changeset
2245 debug (const wide_int &ref)
kono
parents:
diff changeset
2246 {
kono
parents:
diff changeset
2247 ref.dump ();
kono
parents:
diff changeset
2248 }
kono
parents:
diff changeset
2249
kono
parents:
diff changeset
2250 DEBUG_FUNCTION void
kono
parents:
diff changeset
2251 debug (const wide_int *ptr)
kono
parents:
diff changeset
2252 {
kono
parents:
diff changeset
2253 if (ptr)
kono
parents:
diff changeset
2254 debug (*ptr);
kono
parents:
diff changeset
2255 else
kono
parents:
diff changeset
2256 fprintf (stderr, "<nil>\n");
kono
parents:
diff changeset
2257 }
kono
parents:
diff changeset
2258
kono
parents:
diff changeset
2259 DEBUG_FUNCTION void
kono
parents:
diff changeset
2260 debug (const widest_int &ref)
kono
parents:
diff changeset
2261 {
kono
parents:
diff changeset
2262 ref.dump ();
kono
parents:
diff changeset
2263 }
kono
parents:
diff changeset
2264
kono
parents:
diff changeset
2265 DEBUG_FUNCTION void
kono
parents:
diff changeset
2266 debug (const widest_int *ptr)
kono
parents:
diff changeset
2267 {
kono
parents:
diff changeset
2268 if (ptr)
kono
parents:
diff changeset
2269 debug (*ptr);
kono
parents:
diff changeset
2270 else
kono
parents:
diff changeset
2271 fprintf (stderr, "<nil>\n");
kono
parents:
diff changeset
2272 }
kono
parents:
diff changeset
2273
kono
parents:
diff changeset
2274 #if CHECKING_P
kono
parents:
diff changeset
2275
kono
parents:
diff changeset
2276 namespace selftest {
kono
parents:
diff changeset
2277
kono
parents:
diff changeset
2278 /* Selftests for wide ints. We run these multiple times, once per type. */
kono
parents:
diff changeset
2279
kono
parents:
diff changeset
2280 /* Helper function for building a test value. */
kono
parents:
diff changeset
2281
kono
parents:
diff changeset
2282 template <class VALUE_TYPE>
kono
parents:
diff changeset
2283 static VALUE_TYPE
kono
parents:
diff changeset
2284 from_int (int i);
kono
parents:
diff changeset
2285
kono
parents:
diff changeset
2286 /* Specializations of the fixture for each wide-int type. */
kono
parents:
diff changeset
2287
kono
parents:
diff changeset
2288 /* Specialization for VALUE_TYPE == wide_int. */
kono
parents:
diff changeset
2289
kono
parents:
diff changeset
2290 template <>
kono
parents:
diff changeset
2291 wide_int
kono
parents:
diff changeset
2292 from_int (int i)
kono
parents:
diff changeset
2293 {
kono
parents:
diff changeset
2294 return wi::shwi (i, 32);
kono
parents:
diff changeset
2295 }
kono
parents:
diff changeset
2296
kono
parents:
diff changeset
2297 /* Specialization for VALUE_TYPE == offset_int. */
kono
parents:
diff changeset
2298
kono
parents:
diff changeset
2299 template <>
kono
parents:
diff changeset
2300 offset_int
kono
parents:
diff changeset
2301 from_int (int i)
kono
parents:
diff changeset
2302 {
kono
parents:
diff changeset
2303 return offset_int (i);
kono
parents:
diff changeset
2304 }
kono
parents:
diff changeset
2305
kono
parents:
diff changeset
2306 /* Specialization for VALUE_TYPE == widest_int. */
kono
parents:
diff changeset
2307
kono
parents:
diff changeset
2308 template <>
kono
parents:
diff changeset
2309 widest_int
kono
parents:
diff changeset
2310 from_int (int i)
kono
parents:
diff changeset
2311 {
kono
parents:
diff changeset
2312 return widest_int (i);
kono
parents:
diff changeset
2313 }
kono
parents:
diff changeset
2314
kono
parents:
diff changeset
2315 /* Verify that print_dec (WI, ..., SGN) gives the expected string
kono
parents:
diff changeset
2316 representation (using base 10). */
kono
parents:
diff changeset
2317
kono
parents:
diff changeset
2318 static void
kono
parents:
diff changeset
2319 assert_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
kono
parents:
diff changeset
2320 {
kono
parents:
diff changeset
2321 char buf[WIDE_INT_PRINT_BUFFER_SIZE];
kono
parents:
diff changeset
2322 print_dec (wi, buf, sgn);
kono
parents:
diff changeset
2323 ASSERT_STREQ (expected, buf);
kono
parents:
diff changeset
2324 }
kono
parents:
diff changeset
2325
kono
parents:
diff changeset
2326 /* Likewise for base 16. */
kono
parents:
diff changeset
2327
kono
parents:
diff changeset
2328 static void
kono
parents:
diff changeset
2329 assert_hexeq (const char *expected, const wide_int_ref &wi)
kono
parents:
diff changeset
2330 {
kono
parents:
diff changeset
2331 char buf[WIDE_INT_PRINT_BUFFER_SIZE];
kono
parents:
diff changeset
2332 print_hex (wi, buf);
kono
parents:
diff changeset
2333 ASSERT_STREQ (expected, buf);
kono
parents:
diff changeset
2334 }
kono
parents:
diff changeset
2335
kono
parents:
diff changeset
2336 /* Test cases. */
kono
parents:
diff changeset
2337
kono
parents:
diff changeset
2338 /* Verify that print_dec and print_hex work for VALUE_TYPE. */
kono
parents:
diff changeset
2339
kono
parents:
diff changeset
2340 template <class VALUE_TYPE>
kono
parents:
diff changeset
2341 static void
kono
parents:
diff changeset
2342 test_printing ()
kono
parents:
diff changeset
2343 {
kono
parents:
diff changeset
2344 VALUE_TYPE a = from_int<VALUE_TYPE> (42);
kono
parents:
diff changeset
2345 assert_deceq ("42", a, SIGNED);
kono
parents:
diff changeset
2346 assert_hexeq ("0x2a", a);
kono
parents:
diff changeset
2347 assert_hexeq ("0x1fffffffffffffffff", wi::shwi (-1, 69));
kono
parents:
diff changeset
2348 assert_hexeq ("0xffffffffffffffff", wi::mask (64, false, 69));
kono
parents:
diff changeset
2349 assert_hexeq ("0xffffffffffffffff", wi::mask <widest_int> (64, false));
kono
parents:
diff changeset
2350 if (WIDE_INT_MAX_PRECISION > 128)
kono
parents:
diff changeset
2351 {
kono
parents:
diff changeset
2352 assert_hexeq ("0x20000000000000000fffffffffffffffe",
kono
parents:
diff changeset
2353 wi::lshift (1, 129) + wi::lshift (1, 64) - 2);
kono
parents:
diff changeset
2354 assert_hexeq ("0x200000000000004000123456789abcdef",
kono
parents:
diff changeset
2355 wi::lshift (1, 129) + wi::lshift (1, 74)
kono
parents:
diff changeset
2356 + wi::lshift (0x1234567, 32) + 0x89abcdef);
kono
parents:
diff changeset
2357 }
kono
parents:
diff changeset
2358 }
kono
parents:
diff changeset
2359
kono
parents:
diff changeset
2360 /* Verify that various operations work correctly for VALUE_TYPE,
kono
parents:
diff changeset
2361 unary and binary, using both function syntax, and
kono
parents:
diff changeset
2362 overloaded-operators. */
kono
parents:
diff changeset
2363
kono
parents:
diff changeset
2364 template <class VALUE_TYPE>
kono
parents:
diff changeset
2365 static void
kono
parents:
diff changeset
2366 test_ops ()
kono
parents:
diff changeset
2367 {
kono
parents:
diff changeset
2368 VALUE_TYPE a = from_int<VALUE_TYPE> (7);
kono
parents:
diff changeset
2369 VALUE_TYPE b = from_int<VALUE_TYPE> (3);
kono
parents:
diff changeset
2370
kono
parents:
diff changeset
2371 /* Using functions. */
kono
parents:
diff changeset
2372 assert_deceq ("-7", wi::neg (a), SIGNED);
kono
parents:
diff changeset
2373 assert_deceq ("10", wi::add (a, b), SIGNED);
kono
parents:
diff changeset
2374 assert_deceq ("4", wi::sub (a, b), SIGNED);
kono
parents:
diff changeset
2375 assert_deceq ("-4", wi::sub (b, a), SIGNED);
kono
parents:
diff changeset
2376 assert_deceq ("21", wi::mul (a, b), SIGNED);
kono
parents:
diff changeset
2377
kono
parents:
diff changeset
2378 /* Using operators. */
kono
parents:
diff changeset
2379 assert_deceq ("-7", -a, SIGNED);
kono
parents:
diff changeset
2380 assert_deceq ("10", a + b, SIGNED);
kono
parents:
diff changeset
2381 assert_deceq ("4", a - b, SIGNED);
kono
parents:
diff changeset
2382 assert_deceq ("-4", b - a, SIGNED);
kono
parents:
diff changeset
2383 assert_deceq ("21", a * b, SIGNED);
kono
parents:
diff changeset
2384 }
kono
parents:
diff changeset
2385
kono
parents:
diff changeset
2386 /* Verify that various comparisons work correctly for VALUE_TYPE. */
kono
parents:
diff changeset
2387
kono
parents:
diff changeset
2388 template <class VALUE_TYPE>
kono
parents:
diff changeset
2389 static void
kono
parents:
diff changeset
2390 test_comparisons ()
kono
parents:
diff changeset
2391 {
kono
parents:
diff changeset
2392 VALUE_TYPE a = from_int<VALUE_TYPE> (7);
kono
parents:
diff changeset
2393 VALUE_TYPE b = from_int<VALUE_TYPE> (3);
kono
parents:
diff changeset
2394
kono
parents:
diff changeset
2395 /* == */
kono
parents:
diff changeset
2396 ASSERT_TRUE (wi::eq_p (a, a));
kono
parents:
diff changeset
2397 ASSERT_FALSE (wi::eq_p (a, b));
kono
parents:
diff changeset
2398
kono
parents:
diff changeset
2399 /* != */
kono
parents:
diff changeset
2400 ASSERT_TRUE (wi::ne_p (a, b));
kono
parents:
diff changeset
2401 ASSERT_FALSE (wi::ne_p (a, a));
kono
parents:
diff changeset
2402
kono
parents:
diff changeset
2403 /* < */
kono
parents:
diff changeset
2404 ASSERT_FALSE (wi::lts_p (a, a));
kono
parents:
diff changeset
2405 ASSERT_FALSE (wi::lts_p (a, b));
kono
parents:
diff changeset
2406 ASSERT_TRUE (wi::lts_p (b, a));
kono
parents:
diff changeset
2407
kono
parents:
diff changeset
2408 /* <= */
kono
parents:
diff changeset
2409 ASSERT_TRUE (wi::les_p (a, a));
kono
parents:
diff changeset
2410 ASSERT_FALSE (wi::les_p (a, b));
kono
parents:
diff changeset
2411 ASSERT_TRUE (wi::les_p (b, a));
kono
parents:
diff changeset
2412
kono
parents:
diff changeset
2413 /* > */
kono
parents:
diff changeset
2414 ASSERT_FALSE (wi::gts_p (a, a));
kono
parents:
diff changeset
2415 ASSERT_TRUE (wi::gts_p (a, b));
kono
parents:
diff changeset
2416 ASSERT_FALSE (wi::gts_p (b, a));
kono
parents:
diff changeset
2417
kono
parents:
diff changeset
2418 /* >= */
kono
parents:
diff changeset
2419 ASSERT_TRUE (wi::ges_p (a, a));
kono
parents:
diff changeset
2420 ASSERT_TRUE (wi::ges_p (a, b));
kono
parents:
diff changeset
2421 ASSERT_FALSE (wi::ges_p (b, a));
kono
parents:
diff changeset
2422
kono
parents:
diff changeset
2423 /* comparison */
kono
parents:
diff changeset
2424 ASSERT_EQ (-1, wi::cmps (b, a));
kono
parents:
diff changeset
2425 ASSERT_EQ (0, wi::cmps (a, a));
kono
parents:
diff changeset
2426 ASSERT_EQ (1, wi::cmps (a, b));
kono
parents:
diff changeset
2427 }
kono
parents:
diff changeset
2428
kono
parents:
diff changeset
2429 /* Run all of the selftests, using the given VALUE_TYPE. */
kono
parents:
diff changeset
2430
kono
parents:
diff changeset
2431 template <class VALUE_TYPE>
kono
parents:
diff changeset
2432 static void run_all_wide_int_tests ()
kono
parents:
diff changeset
2433 {
kono
parents:
diff changeset
2434 test_printing <VALUE_TYPE> ();
kono
parents:
diff changeset
2435 test_ops <VALUE_TYPE> ();
kono
parents:
diff changeset
2436 test_comparisons <VALUE_TYPE> ();
kono
parents:
diff changeset
2437 }
kono
parents:
diff changeset
2438
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2439 /* Test overflow conditions. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2440
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2441 static void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2442 test_overflow ()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2443 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2444 static int precs[] = { 31, 32, 33, 63, 64, 65, 127, 128 };
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2445 static int offsets[] = { 16, 1, 0 };
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2446 for (unsigned int i = 0; i < ARRAY_SIZE (precs); ++i)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2447 for (unsigned int j = 0; j < ARRAY_SIZE (offsets); ++j)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2448 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2449 int prec = precs[i];
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2450 int offset = offsets[j];
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2451 wi::overflow_type overflow;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2452 wide_int sum, diff;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2453
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2454 sum = wi::add (wi::max_value (prec, UNSIGNED) - offset, 1,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2455 UNSIGNED, &overflow);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2456 ASSERT_EQ (sum, -offset);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2457 ASSERT_EQ (overflow != wi::OVF_NONE, offset == 0);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2458
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2459 sum = wi::add (1, wi::max_value (prec, UNSIGNED) - offset,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2460 UNSIGNED, &overflow);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2461 ASSERT_EQ (sum, -offset);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2462 ASSERT_EQ (overflow != wi::OVF_NONE, offset == 0);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2463
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2464 diff = wi::sub (wi::max_value (prec, UNSIGNED) - offset,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2465 wi::max_value (prec, UNSIGNED),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2466 UNSIGNED, &overflow);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2467 ASSERT_EQ (diff, -offset);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2468 ASSERT_EQ (overflow != wi::OVF_NONE, offset != 0);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2469
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2470 diff = wi::sub (wi::max_value (prec, UNSIGNED) - offset,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2471 wi::max_value (prec, UNSIGNED) - 1,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2472 UNSIGNED, &overflow);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2473 ASSERT_EQ (diff, 1 - offset);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2474 ASSERT_EQ (overflow != wi::OVF_NONE, offset > 1);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2475 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2476 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2477
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2478 /* Test the round_{down,up}_for_mask functions. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2479
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2480 static void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2481 test_round_for_mask ()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2482 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2483 unsigned int prec = 18;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2484 ASSERT_EQ (17, wi::round_down_for_mask (wi::shwi (17, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2485 wi::shwi (0xf1, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2486 ASSERT_EQ (17, wi::round_up_for_mask (wi::shwi (17, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2487 wi::shwi (0xf1, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2488
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2489 ASSERT_EQ (1, wi::round_down_for_mask (wi::shwi (6, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2490 wi::shwi (0xf1, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2491 ASSERT_EQ (16, wi::round_up_for_mask (wi::shwi (6, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2492 wi::shwi (0xf1, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2493
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2494 ASSERT_EQ (17, wi::round_down_for_mask (wi::shwi (24, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2495 wi::shwi (0xf1, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2496 ASSERT_EQ (32, wi::round_up_for_mask (wi::shwi (24, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2497 wi::shwi (0xf1, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2498
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2499 ASSERT_EQ (0x011, wi::round_down_for_mask (wi::shwi (0x22, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2500 wi::shwi (0x111, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2501 ASSERT_EQ (0x100, wi::round_up_for_mask (wi::shwi (0x22, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2502 wi::shwi (0x111, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2503
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2504 ASSERT_EQ (100, wi::round_down_for_mask (wi::shwi (101, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2505 wi::shwi (0xfc, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2506 ASSERT_EQ (104, wi::round_up_for_mask (wi::shwi (101, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2507 wi::shwi (0xfc, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2508
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2509 ASSERT_EQ (0x2bc, wi::round_down_for_mask (wi::shwi (0x2c2, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2510 wi::shwi (0xabc, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2511 ASSERT_EQ (0x800, wi::round_up_for_mask (wi::shwi (0x2c2, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2512 wi::shwi (0xabc, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2513
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2514 ASSERT_EQ (0xabc, wi::round_down_for_mask (wi::shwi (0xabd, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2515 wi::shwi (0xabc, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2516 ASSERT_EQ (0, wi::round_up_for_mask (wi::shwi (0xabd, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2517 wi::shwi (0xabc, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2518
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2519 ASSERT_EQ (0xabc, wi::round_down_for_mask (wi::shwi (0x1000, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2520 wi::shwi (0xabc, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2521 ASSERT_EQ (0, wi::round_up_for_mask (wi::shwi (0x1000, prec),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2522 wi::shwi (0xabc, prec)));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2523 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2524
111
kono
parents:
diff changeset
2525 /* Run all of the selftests within this file, for all value types. */
kono
parents:
diff changeset
2526
kono
parents:
diff changeset
2527 void
kono
parents:
diff changeset
2528 wide_int_cc_tests ()
kono
parents:
diff changeset
2529 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2530 run_all_wide_int_tests <wide_int> ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2531 run_all_wide_int_tests <offset_int> ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2532 run_all_wide_int_tests <widest_int> ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2533 test_overflow ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2534 test_round_for_mask ();
111
kono
parents:
diff changeset
2535 }
kono
parents:
diff changeset
2536
kono
parents:
diff changeset
2537 } // namespace selftest
kono
parents:
diff changeset
2538 #endif /* CHECKING_P */