Files
ldc/dmd2/intrange.c
Alexey Prokhin 0e754b5acd Merge dmd v2.055
2011-09-13 21:01:32 +04:00

1106 lines
40 KiB
C

// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by KennyTM
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include "intrange.h"
#include "mars.h"
#include "mtype.h"
#include "expression.h"
#ifndef PERFORM_UNITTEST
#define PERFORM_UNITTEST 0
#endif
// Copy the sign to the value *x*. Equivalent to `sign ? -x : x`.
static uinteger_t copySign(uinteger_t x, bool sign)
{
// return sign ? -x : x;
return (x - sign) ^ -sign;
}
#ifndef UINT64_MAX
#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
#endif
//==================== SignExtendedNumber ======================================
SignExtendedNumber SignExtendedNumber::fromInteger(uinteger_t value_)
{
return SignExtendedNumber(value_, value_ >> 63);
}
bool SignExtendedNumber::operator==(const SignExtendedNumber& a) const
{
return value == a.value && negative == a.negative;
}
bool SignExtendedNumber::operator<(const SignExtendedNumber& a) const
{
return (negative && !a.negative)
|| (negative == a.negative && value < a.value);
}
SignExtendedNumber SignExtendedNumber::extreme(bool minimum)
{
return SignExtendedNumber(minimum-1, minimum);
}
SignExtendedNumber SignExtendedNumber::max()
{
return SignExtendedNumber(UINT64_MAX, false);
}
SignExtendedNumber SignExtendedNumber::operator-() const
{
if (value == 0)
return SignExtendedNumber(-negative);
else
return SignExtendedNumber(-value, !negative);
}
SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) const
{
uinteger_t sum = value + a.value;
bool carry = sum < value && sum < a.value;
if (negative != a.negative)
return SignExtendedNumber(sum, !carry);
else if (negative)
return SignExtendedNumber(carry ? sum : 0, true);
else
return SignExtendedNumber(carry ? UINT64_MAX : sum, false);
}
SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const
{
if (a.isMinimum())
return negative ? SignExtendedNumber(value, false) : max();
else
return *this + (-a);
}
SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) const
{
// perform *saturated* multiplication, otherwise we may get bogus ranges
// like 0x10 * 0x10 == 0x100 == 0.
/* Special handling for zeros:
INT65_MIN * 0 = 0
INT65_MIN * + = INT65_MIN
INT65_MIN * - = INT65_MAX
0 * anything = 0
*/
if (value == 0)
{
if (!negative)
return *this;
else if (a.negative)
return max();
else
return a.value == 0 ? a : *this;
}
else if (a.value == 0)
return a * *this; // don't duplicate the symmetric case.
SignExtendedNumber rv;
// these are != 0 now surely.
uinteger_t tAbs = copySign(value, negative);
uinteger_t aAbs = copySign(a.value, a.negative);
rv.negative = negative != a.negative;
if (UINT64_MAX / tAbs < aAbs)
rv.value = rv.negative-1;
else
rv.value = copySign(tAbs * aAbs, rv.negative);
return rv;
}
SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) const
{
/* special handling for zeros:
INT65_MIN / INT65_MIN = 1
anything / INT65_MIN = 0
+ / 0 = INT65_MAX (eh?)
- / 0 = INT65_MIN (eh?)
*/
if (a.value == 0)
{
if (a.negative)
return SignExtendedNumber(value == 0 && negative);
else
return extreme(negative);
}
uinteger_t aAbs = copySign(a.value, a.negative);
uinteger_t rvVal;
if (!isMinimum())
rvVal = copySign(value, negative) / aAbs;
// Special handling for INT65_MIN
// if the denominator is not a power of 2, it is same as UINT64_MAX / x.
else if (aAbs & (aAbs-1))
rvVal = UINT64_MAX / aAbs;
// otherwise, it's the same as reversing the bits of x.
else
{
if (aAbs == 1)
return extreme(!a.negative);
rvVal = 1ULL << 63;
aAbs >>= 1;
if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
if (aAbs & 0xCCCCCCCCCCCCCCCCULL) rvVal >>= 2;
if (aAbs & 0xF0F0F0F0F0F0F0F0ULL) rvVal >>= 4;
if (aAbs & 0xFF00FF00FF00FF00ULL) rvVal >>= 8;
if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
}
bool rvNeg = negative != a.negative;
rvVal = copySign(rvVal, rvNeg);
return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
}
SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) const
{
if (a.value == 0)
return !a.negative ? a : isMinimum() ? SignExtendedNumber(0) : *this;
uinteger_t aAbs = copySign(a.value, a.negative);
uinteger_t rvVal;
// a % b == sgn(a) * abs(a) % abs(b).
if (!isMinimum())
rvVal = copySign(value, negative) % aAbs;
// Special handling for INT65_MIN
// if the denominator is not a power of 2, it is same as UINT64_MAX%x + 1.
else if (aAbs & (aAbs - 1))
rvVal = UINT64_MAX % aAbs + 1;
// otherwise, the modulus is trivially zero.
else
rvVal = 0;
rvVal = copySign(rvVal, negative);
return SignExtendedNumber(rvVal, rvVal != 0 && negative);
}
SignExtendedNumber& SignExtendedNumber::operator++()
{
if (value != UINT64_MAX)
++ value;
else if (negative)
{
value = 0;
negative = false;
}
return *this;
}
SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) const
{
// assume left-shift the shift-amount is always unsigned. Thus negative
// shifts will give huge result.
if (value == 0)
return *this;
else if (a.negative)
return extreme(negative);
uinteger_t v = copySign(value, negative);
// compute base-2 log of 'v' to determine the maximum allowed bits to shift.
// Ref: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
size_t r, s;
r = (v > 0xFFFFFFFFULL) << 5; v >>= r;
s = (v > 0xFFFFULL ) << 4; v >>= s; r |= s;
s = (v > 0xFFULL ) << 3; v >>= s; r |= s;
s = (v > 0xFULL ) << 2; v >>= s; r |= s;
s = (v > 0x3ULL ) << 1; v >>= s; r |= s;
r |= (v >> 1);
uinteger_t allowableShift = 63 - r;
if (a.value > allowableShift)
return extreme(negative);
else
return SignExtendedNumber(value << a.value, negative);
}
SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const
{
if (a.negative || a.value > 64)
return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
else if (isMinimum())
return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true);
uinteger_t x = value ^ -negative;
x >>= a.value;
return SignExtendedNumber(x ^ -negative, negative);
}
//==================== IntRange ================================================
IntRange IntRange::widest()
{
return IntRange(SignExtendedNumber::min(), SignExtendedNumber::max());
}
#if !PERFORM_UNITTEST
IntRange IntRange::fromType(Type *type)
{
return fromType(type, type->isunsigned());
}
IntRange IntRange::fromType(Type *type, bool isUnsigned)
{
if (!type->isintegral())
return widest();
uinteger_t mask = type->sizemask();
SignExtendedNumber lower(0), upper(mask);
if (type->toBasetype()->ty == Tdchar)
upper.value = 0x10FFFFULL;
else if (!isUnsigned)
{
lower.value = ~(mask >> 1);
lower.negative = true;
upper.value = (mask >> 1);
}
return IntRange(lower, upper);
}
#endif
IntRange IntRange::fromNumbers2(const SignExtendedNumber numbers[2])
{
if (numbers[0] < numbers[1])
return IntRange(numbers[0], numbers[1]);
else
return IntRange(numbers[1], numbers[0]);
}
IntRange IntRange::fromNumbers4(const SignExtendedNumber numbers[4])
{
IntRange ab = fromNumbers2(numbers);
IntRange cd = fromNumbers2(numbers + 2);
if (cd.imin < ab.imin)
ab.imin = cd.imin;
if (cd.imax > ab.imax)
ab.imax = cd.imax;
return ab;
}
bool IntRange::contains(const IntRange& a) const
{
return imin <= a.imin && imax >= a.imax;
}
bool IntRange::containsZero() const
{
return (imin.negative && !imax.negative)
|| (!imin.negative && imin.value == 0);
}
IntRange& IntRange::castUnsigned(uinteger_t mask)
{
// .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 ....
//
// regular unsigned type. We just need to see if ir steps across the
// boundary of validRange. If yes, ir will represent the whole validRange,
// otherwise, we just take the modulus.
// e.g. [0x105, 0x107] & 0xff == [5, 7]
// [0x105, 0x207] & 0xff == [0, 0xff]
uinteger_t minChunk = imin.value & ~mask;
uinteger_t maxChunk = imax.value & ~mask;
if (minChunk == maxChunk && imin.negative == imax.negative)
{
imin.value &= mask;
imax.value &= mask;
}
else
{
imin.value = 0;
imax.value = mask;
}
imin.negative = imax.negative = false;
return *this;
}
IntRange& IntRange::castSigned(uinteger_t mask)
{
// .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 ....
//
// regular signed type. We use a technique similar to the unsigned version,
// but the chunk has to be offset by 1/2 of the range.
uinteger_t halfChunkMask = mask >> 1;
uinteger_t minHalfChunk = imin.value & ~halfChunkMask;
uinteger_t maxHalfChunk = imax.value & ~halfChunkMask;
int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max
int maxHalfChunkNegativity = imax.negative;
if (minHalfChunk & mask)
{
minHalfChunk += halfChunkMask+1;
if (minHalfChunk == 0)
-- minHalfChunkNegativity;
}
if (maxHalfChunk & mask)
{
maxHalfChunk += halfChunkMask+1;
if (maxHalfChunk == 0)
-- maxHalfChunkNegativity;
}
if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity)
{
imin.value &= mask;
imax.value &= mask;
// sign extend if necessary.
imin.negative = imin.value & ~halfChunkMask;
imax.negative = imax.value & ~halfChunkMask;
halfChunkMask += 1;
imin.value = (imin.value ^ halfChunkMask) - halfChunkMask;
imax.value = (imax.value ^ halfChunkMask) - halfChunkMask;
}
else
{
imin = SignExtendedNumber(~halfChunkMask, true);
imax = SignExtendedNumber(halfChunkMask, false);
}
return *this;
}
IntRange& IntRange::castDchar()
{
// special case for dchar. Casting to dchar means "I'll ignore all
// invalid characters."
castUnsigned(0xFFFFFFFFULL);
if (imin.value > 0x10FFFFULL) // ??
imin.value = 0x10FFFFULL; // ??
if (imax.value > 0x10FFFFULL)
imax.value = 0x10FFFFULL;
return *this;
}
#if !PERFORM_UNITTEST
IntRange& IntRange::cast(Type *type)
{
if (!type->isintegral())
return *this;
else if (!type->isunsigned())
return castSigned(type->sizemask());
else if (type->toBasetype()->ty == Tdchar)
return castDchar();
else
return castUnsigned(type->sizemask());
}
IntRange& IntRange::castUnsigned(Type *type)
{
if (!type->isintegral())
return castUnsigned(UINT64_MAX);
else if (type->toBasetype()->ty == Tdchar)
return castDchar();
else
return castUnsigned(type->sizemask());
}
#endif
IntRange IntRange::absNeg() const
{
if (imax.negative)
return *this;
else if (!imin.negative)
return IntRange(-imax, -imin);
else
{
SignExtendedNumber imaxAbsNeg = -imax;
return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
SignExtendedNumber(0));
}
}
IntRange IntRange::unionWith(const IntRange& other) const
{
return IntRange(imin < other.imin ? imin : other.imin,
imax > other.imax ? imax : other.imax);
}
void IntRange::unionOrAssign(const IntRange& other, bool& union_)
{
if (!union_ || imin > other.imin)
imin = other.imin;
if (!union_ || imax < other.imax)
imax = other.imax;
union_ = true;
}
void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange,
IntRange& nonNegRange, bool& hasNonNegRange) const
{
hasNegRange = imin.negative;
if (hasNegRange)
{
negRange.imin = imin;
negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true);
}
hasNonNegRange = !imax.negative;
if (hasNonNegRange)
{
nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin;
nonNegRange.imax = imax;
}
}
#if !PERFORM_UNITTEST
const IntRange& IntRange::dump(const char* funcName, Expression *e) const
{
printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
imin.negative?'-':'+', (unsigned long long)imin.value,
imax.negative?'-':'+', (unsigned long long)imax.value,
funcName, e->toChars());
return *this;
}
#endif
//------------------------------------------------------------------------------
#if PERFORM_UNITTEST
#include <cstdio>
#include <exception>
class AssertionError : public std::exception {
public:
AssertionError() : std::exception() {}
};
void _assertPred(uinteger_t x, uinteger_t y, int line) {
if (x != y) {
printf("Line %d: %#018llx != %#018llx\n", line, x, y);
throw AssertionError();
}
}
void _assertPred(const SignExtendedNumber& x, const SignExtendedNumber& y, int line) {
if (x != y) {
printf("Line %d: (%c)%#018llx != (%c)%#018llx\n", line,
x.negative?'-':'+', x.value,
y.negative?'-':'+', y.value);
throw AssertionError();
}
}
void _assertPred(bool x, bool y, int line) {
if (x != y) {
static const char* const names[] = {"false", "true"};
printf("Line %d: %s != %s\n", line, names[x], names[y]);
throw AssertionError();
}
}
#define assertPred(x, y) _assertPred(x, y, __LINE__)
#define RUN(testName) \
try { \
testName(); \
} catch (const AssertionError&) { \
printf("********" #testName " failed\n"); \
}
void testAssertSanity() {
int saneCount = 0;
printf("Testing 'assert' sanity. You should see 3 assertion failures below\n");
assertPred(true, true);
try {
assertPred(true, false);
} catch (const AssertionError&) {
++ saneCount;
}
assertPred(4ULL, 4ULL);
try {
assertPred(3ULL, -3ULL);
} catch (const AssertionError&) {
++ saneCount;
}
assertPred(SignExtendedNumber(5, false), SignExtendedNumber(5, false));
try {
assertPred(SignExtendedNumber(4, false), SignExtendedNumber(4, true));
} catch (const AssertionError&) {
++ saneCount;
}
printf("--------------\n");
if (saneCount != 3) throw AssertionError();
}
void testNegation() {
SignExtendedNumber s (4);
SignExtendedNumber t = -s;
assertPred(t.value, -4ULL);
assertPred(t.negative, true);
s = SignExtendedNumber::max();
t = -s;
assertPred(t.value, 1);
assertPred(t.negative, true);
s = SignExtendedNumber::fromInteger(-4);
assertPred(s.value, -4ULL);
assertPred(s.negative, true);
t = -s;
assertPred(t.value, 4);
assertPred(t.negative, false);
s = SignExtendedNumber::min();
t = -s;
assertPred(t.value, UINT64_MAX);
assertPred(t.negative, false);
s = SignExtendedNumber(0);
t = -s;
assertPred(t.value, 0);
assertPred(t.negative, false);
}
void testCompare() {
SignExtendedNumber a = SignExtendedNumber::min();
SignExtendedNumber b = SignExtendedNumber(-5, true);
SignExtendedNumber c = SignExtendedNumber(0, false);
SignExtendedNumber d = SignExtendedNumber(5, false);
SignExtendedNumber e = SignExtendedNumber::max();
assertPred(a == a, true);
assertPred(a != a, false);
assertPred(a < b, true);
assertPred(b < c, true);
assertPred(c < d, true);
assertPred(d < e, true);
assertPred(a < c, true);
assertPred(c < e, true);
assertPred(b < d, true);
assertPred(b < a, false);
assertPred(c < b, false);
assertPred(d < c, false);
assertPred(e < d, false);
assertPred(e < c, false);
assertPred(d < b, false);
assertPred(c < a, false);
assertPred(a, a);
assertPred(SignExtendedNumber::extreme(false), SignExtendedNumber::max());
assertPred(SignExtendedNumber::extreme(true), SignExtendedNumber::min());
}
void testAddition() {
assertPred(SignExtendedNumber(4, false) + SignExtendedNumber(8, false),
SignExtendedNumber(12, false));
assertPred(SignExtendedNumber(4, false) + SignExtendedNumber(-9, true),
SignExtendedNumber(-5, true));
assertPred(SignExtendedNumber(-9, true) + SignExtendedNumber(4, false),
SignExtendedNumber(-5, true));
assertPred(SignExtendedNumber(-4, true) + SignExtendedNumber(9, false),
SignExtendedNumber(5, false));
assertPred(SignExtendedNumber(9, false) + SignExtendedNumber(-4, true),
SignExtendedNumber(5, false));
assertPred(SignExtendedNumber(9, true) + SignExtendedNumber(-4, false),
SignExtendedNumber(5, false));
assertPred(SignExtendedNumber(-4, true) + SignExtendedNumber(-6, true),
SignExtendedNumber(-10, true));
assertPred(SignExtendedNumber::max() + SignExtendedNumber(1, false),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(UINT64_MAX/2+1, false) + SignExtendedNumber(UINT64_MAX/2+1, false),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::max() + SignExtendedNumber::min(),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber::min() + SignExtendedNumber(-1, true),
SignExtendedNumber::min());
assertPred(SignExtendedNumber::max() + SignExtendedNumber::max(),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::min() + SignExtendedNumber::min(),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(1, true) + SignExtendedNumber(1, true),
SignExtendedNumber::min());
SignExtendedNumber x(0);
assertPred(++x, SignExtendedNumber(1));
x = SignExtendedNumber(-1, true);
assertPred(++x, SignExtendedNumber(0));
x = SignExtendedNumber::min();
assertPred(++x, SignExtendedNumber(1, true));
x = SignExtendedNumber::max();
assertPred(++x, SignExtendedNumber::max());
}
void testSubtraction() {
assertPred(SignExtendedNumber(4, false) - SignExtendedNumber(8, false),
SignExtendedNumber(-4, true));
assertPred(SignExtendedNumber(4, false) - SignExtendedNumber(-9, true),
SignExtendedNumber(13, false));
assertPred(SignExtendedNumber(-9, true) - SignExtendedNumber(4, false),
SignExtendedNumber(-13, true));
assertPred(SignExtendedNumber(-4, true) - SignExtendedNumber(9, false),
SignExtendedNumber(-13, true));
assertPred(SignExtendedNumber(9, false) - SignExtendedNumber(-4, true),
SignExtendedNumber(13, false));
assertPred(SignExtendedNumber(9, true) - SignExtendedNumber(-4, false),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(-4, true) - SignExtendedNumber(-6, true),
SignExtendedNumber(2, false));
assertPred(SignExtendedNumber::max() - SignExtendedNumber(-1, true),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::max() - SignExtendedNumber::max(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::max() - SignExtendedNumber::min(),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::min() - SignExtendedNumber(1, false),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(1, false) - SignExtendedNumber::min(),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::min() - SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(1, true) - SignExtendedNumber::min(),
SignExtendedNumber(1, false));
}
void testMultiplication() {
assertPred(SignExtendedNumber(4, false) * SignExtendedNumber(8, false),
SignExtendedNumber(32, false));
assertPred(SignExtendedNumber(4, false) * SignExtendedNumber(-9, true),
SignExtendedNumber(-36, true));
assertPred(SignExtendedNumber(-9, true) * SignExtendedNumber(4, false),
SignExtendedNumber(-36, true));
assertPred(SignExtendedNumber(-4, true) * SignExtendedNumber(9, false),
SignExtendedNumber(-36, true));
assertPred(SignExtendedNumber(9, false) * SignExtendedNumber(-4, true),
SignExtendedNumber(-36, true));
assertPred(SignExtendedNumber(9, true) * SignExtendedNumber(-4, false),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(-4, true) * SignExtendedNumber(-6, true),
SignExtendedNumber(24, false));
assertPred(SignExtendedNumber::max() * SignExtendedNumber::max(),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::max() * SignExtendedNumber(0),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::max() * SignExtendedNumber::min(),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(0) * SignExtendedNumber::max(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) * SignExtendedNumber(0),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) * SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() * SignExtendedNumber::max(),
SignExtendedNumber::min());
assertPred(SignExtendedNumber::min() * SignExtendedNumber(0),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() * SignExtendedNumber::min(),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(-6, false) * SignExtendedNumber(2, false),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(-6, false) * SignExtendedNumber(-2, true),
SignExtendedNumber::min());
assertPred(SignExtendedNumber::max() * SignExtendedNumber(-1, true),
SignExtendedNumber(1, true));
assertPred(SignExtendedNumber::max() * SignExtendedNumber(-2, true),
SignExtendedNumber::min());
assertPred(SignExtendedNumber::max() * SignExtendedNumber(2, false),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::min() * SignExtendedNumber(2, false),
SignExtendedNumber::min());
assertPred(SignExtendedNumber::min() * SignExtendedNumber(-1, true),
SignExtendedNumber::max());
}
void testDivision() {
assertPred(SignExtendedNumber(4, false) / SignExtendedNumber(8, false),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(8, false) / SignExtendedNumber(4, false),
SignExtendedNumber(2, false));
assertPred(SignExtendedNumber(4, false) / SignExtendedNumber(-9, true),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(-9, true) / SignExtendedNumber(4, false),
SignExtendedNumber(-2, true));
assertPred(SignExtendedNumber(-4, true) / SignExtendedNumber(9, false),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(9, false) / SignExtendedNumber(-4, true),
SignExtendedNumber(-2, true));
assertPred(SignExtendedNumber(4, true) / SignExtendedNumber(-9, false),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber(-6, true) / SignExtendedNumber(-4, true),
SignExtendedNumber(1, false));
assertPred(SignExtendedNumber::max() / SignExtendedNumber::max(),
SignExtendedNumber(1));
assertPred(SignExtendedNumber::max() / SignExtendedNumber(0),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::max() / SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) / SignExtendedNumber::max(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) / SignExtendedNumber(0),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(0) / SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() / SignExtendedNumber::max(),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber::min() / SignExtendedNumber(0),
SignExtendedNumber::min());
assertPred(SignExtendedNumber::min() / SignExtendedNumber::min(),
SignExtendedNumber(1));
assertPred(SignExtendedNumber(-6, false) / SignExtendedNumber(2, false),
SignExtendedNumber((~5ULL)>>1));
assertPred(SignExtendedNumber(-6, false) / SignExtendedNumber(-2, true),
SignExtendedNumber(3 | 1ULL<<63, true));
assertPred(SignExtendedNumber::max() / SignExtendedNumber(-1, true),
SignExtendedNumber(1, true));
assertPred(SignExtendedNumber::min() / SignExtendedNumber(-1, true),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::max() / SignExtendedNumber(1, false),
SignExtendedNumber::max());
assertPred(SignExtendedNumber::min() / SignExtendedNumber(1, false),
SignExtendedNumber::min());
assertPred(SignExtendedNumber::min() / SignExtendedNumber(2, false),
SignExtendedNumber(-(1ULL << 63), true));
assertPred(SignExtendedNumber::min() / SignExtendedNumber(-1024, true),
SignExtendedNumber(1ULL << 54));
}
void testModulus() {
assertPred(SignExtendedNumber(4, false) % SignExtendedNumber(8, false),
SignExtendedNumber(4, false));
assertPred(SignExtendedNumber(8, false) % SignExtendedNumber(4, false),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(4, false) % SignExtendedNumber(-9, true),
SignExtendedNumber(4, false));
assertPred(SignExtendedNumber(-9, true) % SignExtendedNumber(4, false),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber(-4, true) % SignExtendedNumber(9, false),
SignExtendedNumber(-4, true));
assertPred(SignExtendedNumber(9, false) % SignExtendedNumber(-4, true),
SignExtendedNumber(1, false));
assertPred(SignExtendedNumber(4, true) % SignExtendedNumber(-9, false),
SignExtendedNumber(-5, true));
assertPred(SignExtendedNumber(-6, true) % SignExtendedNumber(-4, true),
SignExtendedNumber(-2, true));
assertPred(SignExtendedNumber::max() % SignExtendedNumber::max(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::max() % SignExtendedNumber(0),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::max() % SignExtendedNumber::min(),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(0) % SignExtendedNumber::max(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) % SignExtendedNumber(0),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) % SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() % SignExtendedNumber::max(),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber::min() % SignExtendedNumber(0),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() % SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(-6, false) % SignExtendedNumber(2, false),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(-6, false) % SignExtendedNumber(-2, true),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::max() % SignExtendedNumber(-1, true),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() % SignExtendedNumber(-1, true),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::max() % SignExtendedNumber(1, false),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() % SignExtendedNumber(1, false),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() % SignExtendedNumber(2, false),
SignExtendedNumber(0));
assertPred(SignExtendedNumber::min() % SignExtendedNumber(999, false),
SignExtendedNumber(-160, true));
}
void testShift() {
assertPred(SignExtendedNumber(0) << SignExtendedNumber(4),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) << SignExtendedNumber(74),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) << SignExtendedNumber(-5, true),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) << SignExtendedNumber::max(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) << SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(1) << SignExtendedNumber(4),
SignExtendedNumber(16));
assertPred(SignExtendedNumber(1) << SignExtendedNumber(74),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(1) << SignExtendedNumber(-5, true),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(1) << SignExtendedNumber::max(),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(1) << SignExtendedNumber::min(),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(4),
SignExtendedNumber(-16, true));
assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(74),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(-5, true),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber::max(),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber::min(),
SignExtendedNumber::min());
assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(12, false),
SignExtendedNumber(0xabcdef000ULL));
assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(40, false),
SignExtendedNumber(0xabcdef0000000000ULL));
assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(41, false),
SignExtendedNumber::max());
assertPred(SignExtendedNumber(0) >> SignExtendedNumber(4),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) >> SignExtendedNumber(74),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) >> SignExtendedNumber(-5, true),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) >> SignExtendedNumber::max(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(0) >> SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(16) >> SignExtendedNumber(4),
SignExtendedNumber(1));
assertPred(SignExtendedNumber(16) >> SignExtendedNumber(74),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(16) >> SignExtendedNumber(-5, true),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(16) >> SignExtendedNumber::max(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(16) >> SignExtendedNumber::min(),
SignExtendedNumber(0));
assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(4),
SignExtendedNumber(-2, true));
assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(74),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(-5, true),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber::max(),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber::min(),
SignExtendedNumber(-1, true));
assertPred(SignExtendedNumber(0xabcdef, false) >> SignExtendedNumber(12, false),
SignExtendedNumber(0xabcULL));
assertPred(SignExtendedNumber(0xabcdef, true) >> SignExtendedNumber(12, false),
SignExtendedNumber(0xFFF0000000000ABCULL, true));
assertPred(SignExtendedNumber::min() >> SignExtendedNumber(1, false),
SignExtendedNumber(0x8000000000000000ULL, true));
assertPred(SignExtendedNumber::min() >> SignExtendedNumber(63, false),
SignExtendedNumber(-2, true));
assertPred(SignExtendedNumber::min() >> SignExtendedNumber(65, false),
SignExtendedNumber(-1, true));
}
void testFromNumbers() {
SignExtendedNumber a[] = {
SignExtendedNumber(12, false),
SignExtendedNumber(-35, true),
SignExtendedNumber(40, false),
SignExtendedNumber(-21, true),
SignExtendedNumber::min()
};
IntRange ir1 = IntRange::fromNumbers2(a);
assertPred(ir1.imin, SignExtendedNumber(-35, true));
assertPred(ir1.imax, SignExtendedNumber(12, false));
IntRange ir2 = IntRange::fromNumbers2(a+1);
assertPred(ir2.imin, SignExtendedNumber(-35, true));
assertPred(ir2.imax, SignExtendedNumber(40, false));
IntRange ir3 = IntRange::fromNumbers4(a);
assertPred(ir3.imin, SignExtendedNumber(-35, true));
assertPred(ir3.imax, SignExtendedNumber(40, false));
IntRange ir4 = IntRange::fromNumbers4(a+1);
assertPred(ir4.imin, SignExtendedNumber::min());
assertPred(ir4.imax, SignExtendedNumber(40, false));
assertPred(ir4.contains(ir3), true);
assertPred(ir1.contains(ir2), false);
IntRange ir5 = IntRange::widest();
assertPred(ir5.imin, SignExtendedNumber::min());
assertPred(ir5.imax, SignExtendedNumber::max());
assertPred(ir5.contains(ir4), true);
}
void testContainsZero() {
IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(4));
assertPred(ir1.containsZero(), true);
IntRange ir2 (SignExtendedNumber(-4, true), SignExtendedNumber(0));
assertPred(ir2.containsZero(), true);
IntRange ir3 (SignExtendedNumber(-5, true), SignExtendedNumber(5));
assertPred(ir3.containsZero(), true);
assertPred(IntRange::widest().containsZero(), true);
IntRange ir4 (SignExtendedNumber(8), SignExtendedNumber(9));
assertPred(ir4.containsZero(), false);
IntRange ir5 (SignExtendedNumber(-5, true), SignExtendedNumber(-2, true));
assertPred(ir5.containsZero(), false);
IntRange ir6 (SignExtendedNumber(0), SignExtendedNumber(0));
assertPred(ir6.containsZero(), true);
}
void testCast() {
{
IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0xFFFF));
ir1.castUnsigned(0xFF);
assertPred(ir1.imin, SignExtendedNumber(0));
assertPred(ir1.imax, SignExtendedNumber(0xFF));
IntRange ir2 (SignExtendedNumber(0x101), SignExtendedNumber(0x105));
ir2.castUnsigned(0xFF);
assertPred(ir2.imin, SignExtendedNumber(1));
assertPred(ir2.imax, SignExtendedNumber(5));
IntRange ir3 (SignExtendedNumber(-7, true), SignExtendedNumber(7, false));
ir3.castUnsigned(0xFF);
assertPred(ir3.imin, SignExtendedNumber(0));
assertPred(ir3.imax, SignExtendedNumber(0xFF));
IntRange ir4 (SignExtendedNumber(0x997F), SignExtendedNumber(0x9999));
ir4.castUnsigned(0xFF);
assertPred(ir4.imin, SignExtendedNumber(0x7F));
assertPred(ir4.imax, SignExtendedNumber(0x99));
IntRange ir5 (SignExtendedNumber(-1, true), SignExtendedNumber(1, false));
ir5.castUnsigned(UINT64_MAX);
assertPred(ir5.imin, SignExtendedNumber(0));
assertPred(ir5.imax, SignExtendedNumber::max());
IntRange ir6 (SignExtendedNumber::min(), SignExtendedNumber(0));
ir6.castUnsigned(UINT64_MAX);
assertPred(ir6.imin, SignExtendedNumber(0));
assertPred(ir6.imax, SignExtendedNumber::max());
IntRange ir7 (SignExtendedNumber::min(), SignExtendedNumber(-0x80, true));
ir7.castUnsigned(UINT64_MAX);
assertPred(ir7.imin, SignExtendedNumber(0));
assertPred(ir7.imax, SignExtendedNumber(-0x80, false));
IntRange ir8 = IntRange::widest();
ir8.castUnsigned(0xFF);
assertPred(ir8.imin, SignExtendedNumber(0));
assertPred(ir8.imax, SignExtendedNumber(0xFF));
}
{
IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0xFFFF));
ir1.castSigned(0xFF);
assertPred(ir1.imin, SignExtendedNumber(-0x80, true));
assertPred(ir1.imax, SignExtendedNumber(0x7F, false));
IntRange ir2 (SignExtendedNumber(0x101), SignExtendedNumber(0x105));
ir2.castSigned(0xFF);
assertPred(ir2.imin, SignExtendedNumber(1));
assertPred(ir2.imax, SignExtendedNumber(5));
IntRange ir3 (SignExtendedNumber(-7, true), SignExtendedNumber(7, false));
ir3.castSigned(0xFF);
assertPred(ir3.imin, SignExtendedNumber(-7, true));
assertPred(ir3.imax, SignExtendedNumber(7, false));
IntRange ir4 (SignExtendedNumber(0x997F), SignExtendedNumber(0x9999));
ir4.castSigned(0xFF);
assertPred(ir4.imin, SignExtendedNumber(-0x80, true));
assertPred(ir4.imax, SignExtendedNumber(0x7F, false));
IntRange ir5 (SignExtendedNumber(-0xFF, true), SignExtendedNumber(-0x80, true));
ir5.castSigned(0xFF);
assertPred(ir5.imin, SignExtendedNumber(-0x80, true));
assertPred(ir5.imax, SignExtendedNumber(0x7F, false));
IntRange ir6 (SignExtendedNumber(-0x80, true), SignExtendedNumber(-0x80, true));
ir6.castSigned(0xFF);
assertPred(ir6.imin, SignExtendedNumber(-0x80, true));
assertPred(ir6.imax, SignExtendedNumber(-0x80, true));
IntRange ir7 = IntRange::widest();
ir7.castSigned(0xFFFFFFFFULL);
assertPred(ir7.imin, SignExtendedNumber(-0x80000000ULL, true));
assertPred(ir7.imax, SignExtendedNumber( 0x7FFFFFFFULL, false));
}
{
IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0x9999));
ir1.castDchar();
assertPred(ir1.imin, SignExtendedNumber(0));
assertPred(ir1.imax, SignExtendedNumber(0x9999));
IntRange ir2 (SignExtendedNumber(0xFFFF), SignExtendedNumber(0x7FFFFFFF));
ir2.castDchar();
assertPred(ir2.imin, SignExtendedNumber(0xFFFF));
assertPred(ir2.imax, SignExtendedNumber(0x10FFFF));
IntRange ir3 = IntRange::widest();
ir3.castDchar();
assertPred(ir3.imin, SignExtendedNumber(0));
assertPred(ir3.imax, SignExtendedNumber(0x10FFFF));
}
}
void testAbsNeg() {
IntRange ir1 = IntRange(SignExtendedNumber(5), SignExtendedNumber(104)).absNeg();
assertPred(ir1.imin, SignExtendedNumber(-104, true));
assertPred(ir1.imax, SignExtendedNumber(-5, true));
IntRange ir2 = IntRange(SignExtendedNumber(-46, true), SignExtendedNumber(-3, true)).absNeg();
assertPred(ir2.imin, SignExtendedNumber(-46, true));
assertPred(ir2.imax, SignExtendedNumber(-3, true));
IntRange ir3 = IntRange(SignExtendedNumber(-7, true), SignExtendedNumber(9)).absNeg();
assertPred(ir3.imin, SignExtendedNumber(-9, true));
assertPred(ir3.imax, SignExtendedNumber(0));
IntRange ir4 = IntRange(SignExtendedNumber(-12, true), SignExtendedNumber(2)).absNeg();
assertPred(ir4.imin, SignExtendedNumber(-12, true));
assertPred(ir4.imax, SignExtendedNumber(0));
IntRange ir5 = IntRange::widest().absNeg();
assertPred(ir5.imin, SignExtendedNumber::min());
assertPred(ir5.imax, SignExtendedNumber(0));
IntRange ir6 = IntRange(SignExtendedNumber(0), SignExtendedNumber::max()).absNeg();
assertPred(ir6.imin, SignExtendedNumber(1, true));
assertPred(ir6.imax, SignExtendedNumber(0));
}
int main() {
RUN(testAssertSanity);
RUN(testNegation);
RUN(testCompare);
RUN(testAddition);
RUN(testSubtraction);
RUN(testMultiplication);
RUN(testDivision);
RUN(testModulus);
RUN(testShift);
RUN(testFromNumbers);
RUN(testContainsZero);
RUN(testCast);
RUN(testAbsNeg);
printf("Finished all tests.\n");
}
#endif