Mercurial > hg > CbC > CbC_gcc
diff gcc/double-int.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/double-int.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/double-int.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,5 +1,5 @@ /* Operations with long integers. - Copyright (C) 2006, 2007, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2006-2017 Free Software Foundation, Inc. This file is part of GCC. @@ -20,9 +20,35 @@ #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" /* For SHIFT_COUNT_TRUNCATED. */ +#include "tm.h" /* For BITS_PER_UNIT and *_BIG_ENDIAN. */ #include "tree.h" +static int add_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT, + unsigned HOST_WIDE_INT, HOST_WIDE_INT, + unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, + bool); + +#define add_double(l1,h1,l2,h2,lv,hv) \ + add_double_with_sign (l1, h1, l2, h2, lv, hv, false) + +static int neg_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT, + unsigned HOST_WIDE_INT *, HOST_WIDE_INT *); + +static int mul_double_wide_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT, + unsigned HOST_WIDE_INT, HOST_WIDE_INT, + unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, + unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, + bool); + +#define mul_double(l1,h1,l2,h2,lv,hv) \ + mul_double_wide_with_sign (l1, h1, l2, h2, lv, hv, NULL, NULL, false) + +static int div_and_round_double (unsigned, int, unsigned HOST_WIDE_INT, + HOST_WIDE_INT, unsigned HOST_WIDE_INT, + HOST_WIDE_INT, unsigned HOST_WIDE_INT *, + HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, + HOST_WIDE_INT *); + /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring overflow. Suppose A, B and SUM have the same respective signs as A1, B1, and SUM1. Then this yields nonzero if overflow occurred during the @@ -39,10 +65,10 @@ number. The value of the word is LOWPART + HIGHPART * BASE. */ #define LOWPART(x) \ - ((x) & (((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)) - 1)) + ((x) & ((HOST_WIDE_INT_1U << (HOST_BITS_PER_WIDE_INT / 2)) - 1)) #define HIGHPART(x) \ ((unsigned HOST_WIDE_INT) (x) >> HOST_BITS_PER_WIDE_INT / 2) -#define BASE ((unsigned HOST_WIDE_INT) 1 << HOST_BITS_PER_WIDE_INT / 2) +#define BASE (HOST_WIDE_INT_1U << HOST_BITS_PER_WIDE_INT / 2) /* Unpack a two-word integer into 4 words. LOW and HI are the integer, as two `HOST_WIDE_INT' pieces. @@ -75,7 +101,7 @@ One argument is L1 and H1; the other, L2 and H2. The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */ -int +static int add_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, @@ -105,14 +131,14 @@ The argument is given as two `HOST_WIDE_INT' pieces in L1 and H1. The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */ -int +static int neg_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv) { if (l1 == 0) { *lv = 0; - *hv = - h1; + *hv = - (unsigned HOST_WIDE_INT) h1; return (*hv & h1) < 0; } else @@ -123,25 +149,28 @@ } } -/* Multiply two doubleword integers with doubleword result. +/* Multiply two doubleword integers with quadword result. Return nonzero if the operation overflows according to UNSIGNED_P. Each argument is given as two `HOST_WIDE_INT' pieces. One argument is L1 and H1; the other, L2 and H2. - The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */ + The value is stored as four `HOST_WIDE_INT' pieces in *LV and *HV, + *LW and *HW. + If lw is NULL then only the low part and no overflow is computed. */ -int -mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, - unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2, - unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, - bool unsigned_p) +static int +mul_double_wide_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, + unsigned HOST_WIDE_INT *lw, HOST_WIDE_INT *hw, + bool unsigned_p) { HOST_WIDE_INT arg1[4]; HOST_WIDE_INT arg2[4]; HOST_WIDE_INT prod[4 * 2]; unsigned HOST_WIDE_INT carry; int i, j, k; - unsigned HOST_WIDE_INT toplow, neglow; - HOST_WIDE_INT tophigh, neghigh; + unsigned HOST_WIDE_INT neglow; + HOST_WIDE_INT neghigh; encode (arg1, l1, h1); encode (arg2, l2, h2); @@ -155,7 +184,7 @@ { k = i + j; /* This product is <= 0xFFFE0001, the sum <= 0xFFFF0000. */ - carry += arg1[i] * arg2[j]; + carry += (unsigned HOST_WIDE_INT) arg1[i] * arg2[j]; /* Since prod[p] < 0xFFFF, this sum <= 0xFFFFFFFF. */ carry += prod[k]; prod[k] = LOWPART (carry); @@ -165,25 +194,89 @@ } decode (prod, lv, hv); - decode (prod + 4, &toplow, &tophigh); + + /* We are not interested in the wide part nor in overflow. */ + if (lw == NULL) + return 0; + + decode (prod + 4, lw, hw); /* Unsigned overflow is immediate. */ if (unsigned_p) - return (toplow | tophigh) != 0; + return (*lw | *hw) != 0; /* Check for signed overflow by calculating the signed representation of the top half of the result; it should agree with the low half's sign bit. */ if (h1 < 0) { neg_double (l2, h2, &neglow, &neghigh); - add_double (neglow, neghigh, toplow, tophigh, &toplow, &tophigh); + add_double (neglow, neghigh, *lw, *hw, lw, hw); } if (h2 < 0) { neg_double (l1, h1, &neglow, &neghigh); - add_double (neglow, neghigh, toplow, tophigh, &toplow, &tophigh); + add_double (neglow, neghigh, *lw, *hw, lw, hw); + } + return (*hv < 0 ? ~(*lw & *hw) : *lw | *hw) != 0; +} + +/* Shift the doubleword integer in L1, H1 right by COUNT places + keeping only PREC bits of result. ARITH nonzero specifies + arithmetic shifting; otherwise use logical shift. + Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ + +static void +rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + unsigned HOST_WIDE_INT count, unsigned int prec, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, + bool arith) +{ + unsigned HOST_WIDE_INT signmask; + + signmask = (arith + ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1)) + : 0); + + if (count >= HOST_BITS_PER_DOUBLE_INT) + { + /* Shifting by the host word size is undefined according to the + ANSI standard, so we must handle this as a special case. */ + *hv = 0; + *lv = 0; } - return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0; + else if (count >= HOST_BITS_PER_WIDE_INT) + { + *hv = 0; + *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT); + } + else + { + *hv = (unsigned HOST_WIDE_INT) h1 >> count; + *lv = ((l1 >> count) + | ((unsigned HOST_WIDE_INT) h1 + << (HOST_BITS_PER_WIDE_INT - count - 1) << 1)); + } + + /* Zero / sign extend all bits that are beyond the precision. */ + + if (count >= prec) + { + *hv = signmask; + *lv = signmask; + } + else if ((prec - count) >= HOST_BITS_PER_DOUBLE_INT) + ; + else if ((prec - count) >= HOST_BITS_PER_WIDE_INT) + { + *hv &= ~(HOST_WIDE_INT_M1U << (prec - count - HOST_BITS_PER_WIDE_INT)); + *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT); + } + else + { + *hv = signmask; + *lv &= ~(HOST_WIDE_INT_M1U << (prec - count)); + *lv |= signmask << (prec - count); + } } /* Shift the doubleword integer in L1, H1 left by COUNT places @@ -192,23 +285,14 @@ ARITH nonzero specifies arithmetic shifting; otherwise use logical shift. Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ -void +static void lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, - HOST_WIDE_INT count, unsigned int prec, - unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith) + unsigned HOST_WIDE_INT count, unsigned int prec, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv) { unsigned HOST_WIDE_INT signmask; - if (count < 0) - { - rshift_double (l1, h1, -count, prec, lv, hv, arith); - return; - } - - if (SHIFT_COUNT_TRUNCATED) - count %= prec; - - if (count >= 2 * HOST_BITS_PER_WIDE_INT) + if (count >= HOST_BITS_PER_DOUBLE_INT) { /* Shifting by the host word size is undefined according to the ANSI standard, so we must handle this as a special case. */ @@ -234,89 +318,21 @@ >> (prec - HOST_BITS_PER_WIDE_INT - 1)) : (*lv >> (prec - 1))) & 1); - if (prec >= 2 * HOST_BITS_PER_WIDE_INT) + if (prec >= HOST_BITS_PER_DOUBLE_INT) ; else if (prec >= HOST_BITS_PER_WIDE_INT) { - *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT)); + *hv &= ~(HOST_WIDE_INT_M1U << (prec - HOST_BITS_PER_WIDE_INT)); *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT); } else { *hv = signmask; - *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec); + *lv &= ~(HOST_WIDE_INT_M1U << prec); *lv |= signmask << prec; } } -/* Shift the doubleword integer in L1, H1 right by COUNT places - keeping only PREC bits of result. Shift left if COUNT is negative. - ARITH nonzero specifies arithmetic shifting; otherwise use logical shift. - Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ - -void -rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, - HOST_WIDE_INT count, unsigned int prec, - unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, - bool arith) -{ - unsigned HOST_WIDE_INT signmask; - - if (count < 0) - { - lshift_double (l1, h1, -count, prec, lv, hv, arith); - return; - } - - signmask = (arith - ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1)) - : 0); - - if (SHIFT_COUNT_TRUNCATED) - count %= prec; - - if (count >= 2 * HOST_BITS_PER_WIDE_INT) - { - /* Shifting by the host word size is undefined according to the - ANSI standard, so we must handle this as a special case. */ - *hv = 0; - *lv = 0; - } - else if (count >= HOST_BITS_PER_WIDE_INT) - { - *hv = 0; - *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT); - } - else - { - *hv = (unsigned HOST_WIDE_INT) h1 >> count; - *lv = ((l1 >> count) - | ((unsigned HOST_WIDE_INT) h1 - << (HOST_BITS_PER_WIDE_INT - count - 1) << 1)); - } - - /* Zero / sign extend all bits that are beyond the precision. */ - - if (count >= (HOST_WIDE_INT)prec) - { - *hv = signmask; - *lv = signmask; - } - else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT) - ; - else if ((prec - count) >= HOST_BITS_PER_WIDE_INT) - { - *hv &= ~((HOST_WIDE_INT) (-1) << (prec - count - HOST_BITS_PER_WIDE_INT)); - *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT); - } - else - { - *hv = signmask; - *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count)); - *lv |= signmask << (prec - count); - } -} - /* Divide doubleword integer LNUM, HNUM by doubleword integer LDEN, HDEN for a quotient (stored in *LQUO, *HQUO) and remainder (in *LREM, *HREM). CODE is a tree code for a kind of division, one of @@ -326,7 +342,7 @@ Return nonzero if the operation overflows. UNS nonzero says do unsigned division. */ -int +static int div_and_round_double (unsigned code, int uns, /* num == numerator == dividend */ unsigned HOST_WIDE_INT lnum_orig, @@ -530,7 +546,7 @@ if (quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio < 0 && rem != 0 */ { /* quo = quo - 1; */ - add_double (*lquo, *hquo, (HOST_WIDE_INT) -1, (HOST_WIDE_INT) -1, + add_double (*lquo, *hquo, HOST_WIDE_INT_M1, HOST_WIDE_INT_M1, lquo, hquo); } else @@ -541,7 +557,7 @@ case CEIL_MOD_EXPR: /* round toward positive infinity */ if (!quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio > 0 && rem != 0 */ { - add_double (*lquo, *hquo, (HOST_WIDE_INT) 1, (HOST_WIDE_INT) 0, + add_double (*lquo, *hquo, HOST_WIDE_INT_1, HOST_WIDE_INT_0, lquo, hquo); } else @@ -553,32 +569,31 @@ { unsigned HOST_WIDE_INT labs_rem = *lrem; HOST_WIDE_INT habs_rem = *hrem; - unsigned HOST_WIDE_INT labs_den = lden, ltwice; - HOST_WIDE_INT habs_den = hden, htwice; + unsigned HOST_WIDE_INT labs_den = lden, lnegabs_rem, ldiff; + HOST_WIDE_INT habs_den = hden, hnegabs_rem, hdiff; /* Get absolute values. */ - if (*hrem < 0) + if (!uns && *hrem < 0) neg_double (*lrem, *hrem, &labs_rem, &habs_rem); - if (hden < 0) + if (!uns && hden < 0) neg_double (lden, hden, &labs_den, &habs_den); - /* If (2 * abs (lrem) >= abs (lden)), adjust the quotient. */ - mul_double ((HOST_WIDE_INT) 2, (HOST_WIDE_INT) 0, - labs_rem, habs_rem, <wice, &htwice); + /* If abs(rem) >= abs(den) - abs(rem), adjust the quotient. */ + neg_double (labs_rem, habs_rem, &lnegabs_rem, &hnegabs_rem); + add_double (labs_den, habs_den, lnegabs_rem, hnegabs_rem, + &ldiff, &hdiff); - if (((unsigned HOST_WIDE_INT) habs_den - < (unsigned HOST_WIDE_INT) htwice) - || (((unsigned HOST_WIDE_INT) habs_den - == (unsigned HOST_WIDE_INT) htwice) - && (labs_den <= ltwice))) + if (((unsigned HOST_WIDE_INT) habs_rem + > (unsigned HOST_WIDE_INT) hdiff) + || (habs_rem == hdiff && labs_rem >= ldiff)) { - if (*hquo < 0) + if (quo_neg) /* quo = quo - 1; */ add_double (*lquo, *hquo, - (HOST_WIDE_INT) -1, (HOST_WIDE_INT) -1, lquo, hquo); + HOST_WIDE_INT_M1, HOST_WIDE_INT_M1, lquo, hquo); else /* quo = quo + 1; */ - add_double (*lquo, *hquo, (HOST_WIDE_INT) 1, (HOST_WIDE_INT) 0, + add_double (*lquo, *hquo, HOST_WIDE_INT_1, HOST_WIDE_INT_0, lquo, hquo); } else @@ -598,10 +613,57 @@ } +/* Construct from a buffer of length LEN. BUFFER will be read according + to byte endianness and word endianness. Only the lower LEN bytes + of the result are set; the remaining high bytes are cleared. */ + +double_int +double_int::from_buffer (const unsigned char *buffer, int len) +{ + double_int result = double_int_zero; + int words = len / UNITS_PER_WORD; + + gcc_assert (len * BITS_PER_UNIT <= HOST_BITS_PER_DOUBLE_INT); + + for (int byte = 0; byte < len; byte++) + { + int offset; + int bitpos = byte * BITS_PER_UNIT; + unsigned HOST_WIDE_INT value; + + if (len > UNITS_PER_WORD) + { + int word = byte / UNITS_PER_WORD; + + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + + offset = word * UNITS_PER_WORD; + + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + offset = BYTES_BIG_ENDIAN ? (len - 1) - byte : byte; + + value = (unsigned HOST_WIDE_INT) buffer[offset]; + + if (bitpos < HOST_BITS_PER_WIDE_INT) + result.low |= value << bitpos; + else + result.high |= value << (bitpos - HOST_BITS_PER_WIDE_INT); + } + + return result; +} + + /* Returns mask for PREC bits. */ double_int -double_int_mask (unsigned prec) +double_int::mask (unsigned prec) { unsigned HOST_WIDE_INT m; double_int mask; @@ -616,12 +678,32 @@ else { mask.high = 0; - mask.low = ((unsigned HOST_WIDE_INT) 2 << (prec - 1)) - 1; + mask.low = prec ? ((unsigned HOST_WIDE_INT) 2 << (prec - 1)) - 1 : 0; } return mask; } +/* Returns a maximum value for signed or unsigned integer + of precision PREC. */ + +double_int +double_int::max_value (unsigned int prec, bool uns) +{ + return double_int::mask (prec - (uns ? 0 : 1)); +} + +/* Returns a minimum value for signed or unsigned integer + of precision PREC. */ + +double_int +double_int::min_value (unsigned int prec, bool uns) +{ + if (uns) + return double_int_zero; + return double_int_one.lshift (prec - 1, prec, false); +} + /* Clears the bits of CST over the precision PREC. If UNS is false, the bits outside of the precision are set to the sign bit (i.e., the PREC-th one), otherwise they are set to zero. @@ -630,20 +712,21 @@ of CST, with the given signedness. */ double_int -double_int_ext (double_int cst, unsigned prec, bool uns) +double_int::ext (unsigned prec, bool uns) const { if (uns) - return double_int_zext (cst, prec); + return this->zext (prec); else - return double_int_sext (cst, prec); + return this->sext (prec); } -/* The same as double_int_ext with UNS = true. */ +/* The same as double_int::ext with UNS = true. */ double_int -double_int_zext (double_int cst, unsigned prec) +double_int::zext (unsigned prec) const { - double_int mask = double_int_mask (prec); + const double_int &cst = *this; + double_int mask = double_int::mask (prec); double_int r; r.low = cst.low & mask.low; @@ -652,12 +735,13 @@ return r; } -/* The same as double_int_ext with UNS = false. */ +/* The same as double_int::ext with UNS = false. */ double_int -double_int_sext (double_int cst, unsigned prec) +double_int::sext (unsigned prec) const { - double_int mask = double_int_mask (prec); + const double_int &cst = *this; + double_int mask = double_int::mask (prec); double_int r; unsigned HOST_WIDE_INT snum; @@ -685,8 +769,9 @@ /* Returns true if CST fits in signed HOST_WIDE_INT. */ bool -double_int_fits_in_shwi_p (double_int cst) +double_int::fits_shwi () const { + const double_int &cst = *this; if (cst.high == 0) return (HOST_WIDE_INT) cst.low >= 0; else if (cst.high == -1) @@ -699,65 +784,147 @@ unsigned HOST_WIDE_INT if UNS is true. */ bool -double_int_fits_in_hwi_p (double_int cst, bool uns) +double_int::fits_hwi (bool uns) const { if (uns) - return double_int_fits_in_uhwi_p (cst); + return this->fits_uhwi (); else - return double_int_fits_in_shwi_p (cst); + return this->fits_shwi (); } /* Returns A * B. */ double_int -double_int_mul (double_int a, double_int b) +double_int::operator * (double_int b) const { + const double_int &a = *this; double_int ret; mul_double (a.low, a.high, b.low, b.high, &ret.low, &ret.high); return ret; } +/* Multiplies *this with B and returns a reference to *this. */ + +double_int & +double_int::operator *= (double_int b) +{ + mul_double (low, high, b.low, b.high, &low, &high); + return *this; +} + /* Returns A * B. If the operation overflows according to UNSIGNED_P, *OVERFLOW is set to nonzero. */ double_int -double_int_mul_with_sign (double_int a, double_int b, - bool unsigned_p, int *overflow) +double_int::mul_with_sign (double_int b, bool unsigned_p, bool *overflow) const { - double_int ret; - *overflow = mul_double_with_sign (a.low, a.high, b.low, b.high, - &ret.low, &ret.high, unsigned_p); + const double_int &a = *this; + double_int ret, tem; + *overflow = mul_double_wide_with_sign (a.low, a.high, b.low, b.high, + &ret.low, &ret.high, + &tem.low, &tem.high, unsigned_p); return ret; } +double_int +double_int::wide_mul_with_sign (double_int b, bool unsigned_p, + double_int *higher, bool *overflow) const + +{ + double_int lower; + *overflow = mul_double_wide_with_sign (low, high, b.low, b.high, + &lower.low, &lower.high, + &higher->low, &higher->high, + unsigned_p); + return lower; +} + /* Returns A + B. */ double_int -double_int_add (double_int a, double_int b) +double_int::operator + (double_int b) const { + const double_int &a = *this; double_int ret; add_double (a.low, a.high, b.low, b.high, &ret.low, &ret.high); return ret; } +/* Adds B to *this and returns a reference to *this. */ + +double_int & +double_int::operator += (double_int b) +{ + add_double (low, high, b.low, b.high, &low, &high); + return *this; +} + + +/* Returns A + B. If the operation overflows according to UNSIGNED_P, + *OVERFLOW is set to nonzero. */ + +double_int +double_int::add_with_sign (double_int b, bool unsigned_p, bool *overflow) const +{ + const double_int &a = *this; + double_int ret; + *overflow = add_double_with_sign (a.low, a.high, b.low, b.high, + &ret.low, &ret.high, unsigned_p); + return ret; +} + /* Returns A - B. */ double_int -double_int_sub (double_int a, double_int b) +double_int::operator - (double_int b) const { + const double_int &a = *this; double_int ret; neg_double (b.low, b.high, &b.low, &b.high); add_double (a.low, a.high, b.low, b.high, &ret.low, &ret.high); return ret; } +/* Subtracts B from *this and returns a reference to *this. */ + +double_int & +double_int::operator -= (double_int b) +{ + neg_double (b.low, b.high, &b.low, &b.high); + add_double (low, high, b.low, b.high, &low, &high); + return *this; +} + + +/* Returns A - B. If the operation overflows via inconsistent sign bits, + *OVERFLOW is set to nonzero. */ + +double_int +double_int::sub_with_overflow (double_int b, bool *overflow) const +{ + double_int ret; + neg_double (b.low, b.high, &ret.low, &ret.high); + add_double (low, high, ret.low, ret.high, &ret.low, &ret.high); + *overflow = OVERFLOW_SUM_SIGN (ret.high, b.high, high); + return ret; +} + /* Returns -A. */ double_int -double_int_neg (double_int a) +double_int::operator - () const +{ + const double_int &a = *this; + double_int ret; + neg_double (a.low, a.high, &ret.low, &ret.high); + return ret; +} + +double_int +double_int::neg_with_overflow (bool *overflow) const { double_int ret; - neg_double (a.low, a.high, &ret.low, &ret.high); + *overflow = neg_double (low, high, &ret.low, &ret.high); return ret; } @@ -767,9 +934,23 @@ stored to MOD. */ double_int -double_int_divmod (double_int a, double_int b, bool uns, unsigned code, - double_int *mod) +double_int::divmod_with_overflow (double_int b, bool uns, unsigned code, + double_int *mod, bool *overflow) const { + const double_int &a = *this; + double_int ret; + + *overflow = div_and_round_double (code, uns, a.low, a.high, + b.low, b.high, &ret.low, &ret.high, + &mod->low, &mod->high); + return ret; +} + +double_int +double_int::divmod (double_int b, bool uns, unsigned code, + double_int *mod) const +{ + const double_int &a = *this; double_int ret; div_and_round_double (code, uns, a.low, a.high, @@ -778,20 +959,20 @@ return ret; } -/* The same as double_int_divmod with UNS = false. */ +/* The same as double_int::divmod with UNS = false. */ double_int -double_int_sdivmod (double_int a, double_int b, unsigned code, double_int *mod) +double_int::sdivmod (double_int b, unsigned code, double_int *mod) const { - return double_int_divmod (a, b, false, code, mod); + return this->divmod (b, false, code, mod); } -/* The same as double_int_divmod with UNS = true. */ +/* The same as double_int::divmod with UNS = true. */ double_int -double_int_udivmod (double_int a, double_int b, unsigned code, double_int *mod) +double_int::udivmod (double_int b, unsigned code, double_int *mod) const { - return double_int_divmod (a, b, true, code, mod); + return this->divmod (b, true, code, mod); } /* Returns A / B (computed as unsigned depending on UNS, and rounded as @@ -799,27 +980,27 @@ must be included before tree.h. */ double_int -double_int_div (double_int a, double_int b, bool uns, unsigned code) +double_int::div (double_int b, bool uns, unsigned code) const { double_int mod; - return double_int_divmod (a, b, uns, code, &mod); + return this->divmod (b, uns, code, &mod); } -/* The same as double_int_div with UNS = false. */ +/* The same as double_int::div with UNS = false. */ double_int -double_int_sdiv (double_int a, double_int b, unsigned code) +double_int::sdiv (double_int b, unsigned code) const { - return double_int_div (a, b, false, code); + return this->div (b, false, code); } -/* The same as double_int_div with UNS = true. */ +/* The same as double_int::div with UNS = true. */ double_int -double_int_udiv (double_int a, double_int b, unsigned code) +double_int::udiv (double_int b, unsigned code) const { - return double_int_div (a, b, true, code); + return this->div (b, true, code); } /* Returns A % B (computed as unsigned depending on UNS, and rounded as @@ -827,46 +1008,68 @@ must be included before tree.h. */ double_int -double_int_mod (double_int a, double_int b, bool uns, unsigned code) +double_int::mod (double_int b, bool uns, unsigned code) const { double_int mod; - double_int_divmod (a, b, uns, code, &mod); + this->divmod (b, uns, code, &mod); return mod; } -/* The same as double_int_mod with UNS = false. */ +/* The same as double_int::mod with UNS = false. */ + +double_int +double_int::smod (double_int b, unsigned code) const +{ + return this->mod (b, false, code); +} + +/* The same as double_int::mod with UNS = true. */ double_int -double_int_smod (double_int a, double_int b, unsigned code) +double_int::umod (double_int b, unsigned code) const { - return double_int_mod (a, b, false, code); + return this->mod (b, true, code); } -/* The same as double_int_mod with UNS = true. */ +/* Return TRUE iff PRODUCT is an integral multiple of FACTOR, and return + the multiple in *MULTIPLE. Otherwise return FALSE and leave *MULTIPLE + unchanged. */ -double_int -double_int_umod (double_int a, double_int b, unsigned code) +bool +double_int::multiple_of (double_int factor, + bool unsigned_p, double_int *multiple) const { - return double_int_mod (a, b, true, code); + double_int remainder; + double_int quotient = this->divmod (factor, unsigned_p, + TRUNC_DIV_EXPR, &remainder); + if (remainder.is_zero ()) + { + *multiple = quotient; + return true; + } + + return false; } /* Set BITPOS bit in A. */ double_int -double_int_setbit (double_int a, unsigned bitpos) +double_int::set_bit (unsigned bitpos) const { + double_int a = *this; if (bitpos < HOST_BITS_PER_WIDE_INT) - a.low |= (unsigned HOST_WIDE_INT) 1 << bitpos; + a.low |= HOST_WIDE_INT_1U << bitpos; else - a.high |= (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT); + a.high |= HOST_WIDE_INT_1 << (bitpos - HOST_BITS_PER_WIDE_INT); return a; } /* Count trailing zeros in A. */ int -double_int_ctz (double_int a) +double_int::trailing_zeros () const { + const double_int &a = *this; unsigned HOST_WIDE_INT w = a.low ? a.low : (unsigned HOST_WIDE_INT) a.high; unsigned bits = a.low ? 0 : HOST_BITS_PER_WIDE_INT; if (!w) @@ -875,35 +1078,161 @@ return bits; } +/* Shift A left by COUNT places. */ + +double_int +double_int::lshift (HOST_WIDE_INT count) const +{ + double_int ret; + + gcc_checking_assert (count >= 0); + + if (count >= HOST_BITS_PER_DOUBLE_INT) + { + /* Shifting by the host word size is undefined according to the + ANSI standard, so we must handle this as a special case. */ + ret.high = 0; + ret.low = 0; + } + else if (count >= HOST_BITS_PER_WIDE_INT) + { + ret.high = low << (count - HOST_BITS_PER_WIDE_INT); + ret.low = 0; + } + else + { + ret.high = (((unsigned HOST_WIDE_INT) high << count) + | (low >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1)); + ret.low = low << count; + } + + return ret; +} + +/* Shift A right by COUNT places. */ + +double_int +double_int::rshift (HOST_WIDE_INT count) const +{ + double_int ret; + + gcc_checking_assert (count >= 0); + + if (count >= HOST_BITS_PER_DOUBLE_INT) + { + /* Shifting by the host word size is undefined according to the + ANSI standard, so we must handle this as a special case. */ + ret.high = 0; + ret.low = 0; + } + else if (count >= HOST_BITS_PER_WIDE_INT) + { + ret.high = 0; + ret.low + = (unsigned HOST_WIDE_INT) (high >> (count - HOST_BITS_PER_WIDE_INT)); + } + else + { + ret.high = high >> count; + ret.low = ((low >> count) + | ((unsigned HOST_WIDE_INT) high + << (HOST_BITS_PER_WIDE_INT - count - 1) << 1)); + } + + return ret; +} + /* Shift A left by COUNT places keeping only PREC bits of result. Shift right if COUNT is negative. ARITH true specifies arithmetic shifting; otherwise use logical shift. */ double_int -double_int_lshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith) +double_int::lshift (HOST_WIDE_INT count, unsigned int prec, bool arith) const { double_int ret; - lshift_double (a.low, a.high, count, prec, &ret.low, &ret.high, arith); + if (count > 0) + lshift_double (low, high, count, prec, &ret.low, &ret.high); + else + rshift_double (low, high, absu_hwi (count), prec, &ret.low, &ret.high, arith); return ret; } -/* Shift A rigth by COUNT places keeping only PREC bits of result. Shift +/* Shift A right by COUNT places keeping only PREC bits of result. Shift left if COUNT is negative. ARITH true specifies arithmetic shifting; otherwise use logical shift. */ double_int -double_int_rshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith) +double_int::rshift (HOST_WIDE_INT count, unsigned int prec, bool arith) const { double_int ret; - rshift_double (a.low, a.high, count, prec, &ret.low, &ret.high, arith); + if (count > 0) + rshift_double (low, high, count, prec, &ret.low, &ret.high, arith); + else + lshift_double (low, high, absu_hwi (count), prec, &ret.low, &ret.high); return ret; } +/* Arithmetic shift A left by COUNT places keeping only PREC bits of result. + Shift right if COUNT is negative. */ + +double_int +double_int::alshift (HOST_WIDE_INT count, unsigned int prec) const +{ + double_int r; + if (count > 0) + lshift_double (low, high, count, prec, &r.low, &r.high); + else + rshift_double (low, high, absu_hwi (count), prec, &r.low, &r.high, true); + return r; +} + +/* Arithmetic shift A right by COUNT places keeping only PREC bits of result. + Shift left if COUNT is negative. */ + +double_int +double_int::arshift (HOST_WIDE_INT count, unsigned int prec) const +{ + double_int r; + if (count > 0) + rshift_double (low, high, count, prec, &r.low, &r.high, true); + else + lshift_double (low, high, absu_hwi (count), prec, &r.low, &r.high); + return r; +} + +/* Logical shift A left by COUNT places keeping only PREC bits of result. + Shift right if COUNT is negative. */ + +double_int +double_int::llshift (HOST_WIDE_INT count, unsigned int prec) const +{ + double_int r; + if (count > 0) + lshift_double (low, high, count, prec, &r.low, &r.high); + else + rshift_double (low, high, absu_hwi (count), prec, &r.low, &r.high, false); + return r; +} + +/* Logical shift A right by COUNT places keeping only PREC bits of result. + Shift left if COUNT is negative. */ + +double_int +double_int::lrshift (HOST_WIDE_INT count, unsigned int prec) const +{ + double_int r; + if (count > 0) + rshift_double (low, high, count, prec, &r.low, &r.high, false); + else + lshift_double (low, high, absu_hwi (count), prec, &r.low, &r.high); + return r; +} + /* Rotate A left by COUNT places keeping only PREC bits of result. Rotate right if COUNT is negative. */ double_int -double_int_lrotate (double_int a, HOST_WIDE_INT count, unsigned int prec) +double_int::lrotate (HOST_WIDE_INT count, unsigned int prec) const { double_int t1, t2; @@ -911,17 +1240,17 @@ if (count < 0) count += prec; - t1 = double_int_lshift (a, count, prec, false); - t2 = double_int_rshift (a, prec - count, prec, false); + t1 = this->llshift (count, prec); + t2 = this->lrshift (prec - count, prec); - return double_int_ior (t1, t2); + return t1 | t2; } /* Rotate A rigth by COUNT places keeping only PREC bits of result. Rotate right if COUNT is negative. */ double_int -double_int_rrotate (double_int a, HOST_WIDE_INT count, unsigned int prec) +double_int::rrotate (HOST_WIDE_INT count, unsigned int prec) const { double_int t1, t2; @@ -929,30 +1258,31 @@ if (count < 0) count += prec; - t1 = double_int_rshift (a, count, prec, false); - t2 = double_int_lshift (a, prec - count, prec, false); + t1 = this->lrshift (count, prec); + t2 = this->llshift (prec - count, prec); - return double_int_ior (t1, t2); + return t1 | t2; } /* Returns -1 if A < B, 0 if A == B and 1 if A > B. Signedness of the comparison is given by UNS. */ int -double_int_cmp (double_int a, double_int b, bool uns) +double_int::cmp (double_int b, bool uns) const { if (uns) - return double_int_ucmp (a, b); + return this->ucmp (b); else - return double_int_scmp (a, b); + return this->scmp (b); } /* Compares two unsigned values A and B. Returns -1 if A < B, 0 if A == B, and 1 if A > B. */ int -double_int_ucmp (double_int a, double_int b) +double_int::ucmp (double_int b) const { + const double_int &a = *this; if ((unsigned HOST_WIDE_INT) a.high < (unsigned HOST_WIDE_INT) b.high) return -1; if ((unsigned HOST_WIDE_INT) a.high > (unsigned HOST_WIDE_INT) b.high) @@ -969,8 +1299,9 @@ and 1 if A > B. */ int -double_int_scmp (double_int a, double_int b) +double_int::scmp (double_int b) const { + const double_int &a = *this; if (a.high < b.high) return -1; if (a.high > b.high) @@ -983,49 +1314,139 @@ return 0; } +/* Compares two unsigned values A and B for less-than. */ + +bool +double_int::ult (double_int b) const +{ + if ((unsigned HOST_WIDE_INT) high < (unsigned HOST_WIDE_INT) b.high) + return true; + if ((unsigned HOST_WIDE_INT) high > (unsigned HOST_WIDE_INT) b.high) + return false; + if (low < b.low) + return true; + return false; +} + +/* Compares two unsigned values A and B for less-than or equal-to. */ + +bool +double_int::ule (double_int b) const +{ + if ((unsigned HOST_WIDE_INT) high < (unsigned HOST_WIDE_INT) b.high) + return true; + if ((unsigned HOST_WIDE_INT) high > (unsigned HOST_WIDE_INT) b.high) + return false; + if (low <= b.low) + return true; + return false; +} + +/* Compares two unsigned values A and B for greater-than. */ + +bool +double_int::ugt (double_int b) const +{ + if ((unsigned HOST_WIDE_INT) high > (unsigned HOST_WIDE_INT) b.high) + return true; + if ((unsigned HOST_WIDE_INT) high < (unsigned HOST_WIDE_INT) b.high) + return false; + if (low > b.low) + return true; + return false; +} + +/* Compares two signed values A and B for less-than. */ + +bool +double_int::slt (double_int b) const +{ + if (high < b.high) + return true; + if (high > b.high) + return false; + if (low < b.low) + return true; + return false; +} + +/* Compares two signed values A and B for less-than or equal-to. */ + +bool +double_int::sle (double_int b) const +{ + if (high < b.high) + return true; + if (high > b.high) + return false; + if (low <= b.low) + return true; + return false; +} + +/* Compares two signed values A and B for greater-than. */ + +bool +double_int::sgt (double_int b) const +{ + if (high > b.high) + return true; + if (high < b.high) + return false; + if (low > b.low) + return true; + return false; +} + + /* Compares two values A and B. Returns max value. Signedness of the comparison is given by UNS. */ double_int -double_int_max (double_int a, double_int b, bool uns) +double_int::max (double_int b, bool uns) { - return (double_int_cmp (a, b, uns) == 1) ? a : b; + return (this->cmp (b, uns) == 1) ? *this : b; } /* Compares two signed values A and B. Returns max value. */ -double_int double_int_smax (double_int a, double_int b) +double_int +double_int::smax (double_int b) { - return (double_int_scmp (a, b) == 1) ? a : b; + return (this->scmp (b) == 1) ? *this : b; } /* Compares two unsigned values A and B. Returns max value. */ -double_int double_int_umax (double_int a, double_int b) +double_int +double_int::umax (double_int b) { - return (double_int_ucmp (a, b) == 1) ? a : b; + return (this->ucmp (b) == 1) ? *this : b; } /* Compares two values A and B. Returns mix value. Signedness of the comparison is given by UNS. */ -double_int double_int_min (double_int a, double_int b, bool uns) +double_int +double_int::min (double_int b, bool uns) { - return (double_int_cmp (a, b, uns) == -1) ? a : b; + return (this->cmp (b, uns) == -1) ? *this : b; } /* Compares two signed values A and B. Returns min value. */ -double_int double_int_smin (double_int a, double_int b) +double_int +double_int::smin (double_int b) { - return (double_int_scmp (a, b) == -1) ? a : b; + return (this->scmp (b) == -1) ? *this : b; } /* Compares two unsigned values A and B. Returns min value. */ -double_int double_int_umin (double_int a, double_int b) +double_int +double_int::umin (double_int b) { - return (double_int_ucmp (a, b) == -1) ? a : b; + return (this->ucmp (b) == -1) ? *this : b; } /* Splits last digit of *CST (taken as unsigned) in BASE and returns it. */ @@ -1053,19 +1474,19 @@ unsigned digits[100], n; int i; - if (double_int_zero_p (cst)) + if (cst.is_zero ()) { fprintf (file, "0"); return; } - if (!uns && double_int_negative_p (cst)) + if (!uns && cst.is_negative ()) { fprintf (file, "-"); - cst = double_int_neg (cst); + cst = -cst; } - for (n = 0; !double_int_zero_p (cst); n++) + for (n = 0; !cst.is_zero (); n++) digits[n] = double_int_split_digit (&cst, 10); for (i = n - 1; i >= 0; i--) fprintf (file, "%u", digits[i]); @@ -1081,10 +1502,10 @@ bool negate = false; unsigned HOST_WIDE_INT vp[2]; - if (!uns && double_int_negative_p (val)) + if (!uns && val.is_negative ()) { negate = true; - val = double_int_neg (val); + val = -val; } vp[0] = val.low; @@ -1127,11 +1548,11 @@ for representing the value. The code to calculate count is extracted from the GMP manual, section "Integer Import and Export": http://gmplib.org/manual/Integer-Import-and-Export.html */ - numb = 8*sizeof(HOST_WIDE_INT); + numb = 8 * sizeof (HOST_WIDE_INT); count = (mpz_sizeinbase (val, 2) + numb-1) / numb; if (count < 2) count = 2; - vp = (unsigned HOST_WIDE_INT *) alloca (count * sizeof(HOST_WIDE_INT)); + vp = (unsigned HOST_WIDE_INT *) alloca (count * sizeof (HOST_WIDE_INT)); vp[0] = 0; vp[1] = 0; @@ -1142,9 +1563,9 @@ res.low = vp[0]; res.high = (HOST_WIDE_INT) vp[1]; - res = double_int_ext (res, TYPE_PRECISION (type), TYPE_UNSIGNED (type)); + res = res.ext (TYPE_PRECISION (type), TYPE_UNSIGNED (type)); if (mpz_sgn (val) < 0) - res = double_int_neg (res); + res = -res; return res; }