Commit 9d7d33ac by Iain Buclaw

Merge dmd upstream e2fe2687b

Backports VRP fixes from the D front-end implementation to the C++ port,
and fixes errors reported by ubsan build where the conversion from D
didn't include adjusting integer suffixes from 'UL' to 'ULL'.

Fixes https://gcc.gnu.org/PR88366

Reviewed-on: https://github.com/dlang/dmd/pull/9046

From-SVN: r266925
parent 5d62bfc3
5220ad51eebe06754e6881d9bd5aab89dba2b065
e2fe2687b817a201528abaa3aa882333e04db01b
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
......@@ -446,13 +446,13 @@ UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2)
if (n2 == -1 && !type->isunsigned())
{
// Check for int.min / -1
if ((dinteger_t)n1 == 0xFFFFFFFF80000000UL && type->toBasetype()->ty != Tint64)
if ((dinteger_t)n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64)
{
e2->error("integer overflow: int.min / -1");
new(&ue) ErrorExp();
return ue;
}
else if ((dinteger_t)n1 == 0x8000000000000000L) // long.min / -1
else if ((dinteger_t)n1 == 0x8000000000000000LL) // long.min / -1
{
e2->error("integer overflow: long.min / -1");
new(&ue) ErrorExp();
......
......@@ -986,6 +986,19 @@ MATCH implicitConvTo(Expression *e, Type *t)
visit((Expression *)e);
}
void visit(AndExp *e)
{
visit((Expression *)e);
if (result != MATCHnomatch)
return;
MATCH m1 = e->e1->implicitConvTo(t);
MATCH m2 = e->e2->implicitConvTo(t);
// Pick the worst match
result = (m1 < m2) ? m1 : m2;
}
void visit(OrExp *e)
{
visit((Expression *)e);
......@@ -3381,74 +3394,6 @@ IntRange getIntRange(Expression *e)
{
class IntRangeVisitor : public Visitor
{
private:
static uinteger_t getMask(uinteger_t v)
{
// Ref: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
return v;
}
// The algorithms for &, |, ^ are not yet the best! Sometimes they will produce
// not the tightest bound. See
// https://github.com/D-Programming-Language/dmd/pull/116
// for detail.
static IntRange unsignedBitwiseAnd(const IntRange& a, const IntRange& b)
{
// the DiffMasks stores the mask of bits which are variable in the range.
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
// Since '&' computes the digitwise-minimum, the we could set all varying
// digits to 0 to get a lower bound, and set all varying digits to 1 to get
// an upper bound.
IntRange result;
result.imin.value = (a.imin.value & ~aDiffMask) & (b.imin.value & ~bDiffMask);
result.imax.value = (a.imax.value | aDiffMask) & (b.imax.value | bDiffMask);
// Sometimes the upper bound is overestimated. The upper bound will never
// exceed the input.
if (result.imax.value > a.imax.value)
result.imax.value = a.imax.value;
if (result.imax.value > b.imax.value)
result.imax.value = b.imax.value;
result.imin.negative = result.imax.negative = a.imin.negative && b.imin.negative;
return result;
}
static IntRange unsignedBitwiseOr(const IntRange& a, const IntRange& b)
{
// the DiffMasks stores the mask of bits which are variable in the range.
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
// The imax algorithm by Adam D. Ruppe.
// http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=108796
IntRange result;
result.imin.value = (a.imin.value & ~aDiffMask) | (b.imin.value & ~bDiffMask);
result.imax.value = a.imax.value | b.imax.value | getMask(a.imax.value & b.imax.value);
// Sometimes the lower bound is underestimated. The lower bound will never
// less than the input.
if (result.imin.value < a.imin.value)
result.imin.value = a.imin.value;
if (result.imin.value < b.imin.value)
result.imin.value = b.imin.value;
result.imin.negative = result.imax.negative = a.imin.negative || b.imin.negative;
return result;
}
static IntRange unsignedBitwiseXor(const IntRange& a, const IntRange& b)
{
// the DiffMasks stores the mask of bits which are variable in the range.
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
IntRange result;
result.imin.value = (a.imin.value ^ b.imin.value) & ~(aDiffMask | bDiffMask);
result.imax.value = (a.imax.value ^ b.imax.value) | (aDiffMask | bDiffMask);
result.imin.negative = result.imax.negative = a.imin.negative != b.imin.negative;
return result;
}
public:
IntRange range;
......@@ -3471,14 +3416,14 @@ IntRange getIntRange(Expression *e)
{
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
range = IntRange(ir1.imin + ir2.imin, ir1.imax + ir2.imax).cast(e->type);
range = (ir1 + ir2).cast(e->type);
}
void visit(MinExp *e)
{
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
range = IntRange(ir1.imin - ir2.imax, ir1.imax - ir2.imin).cast(e->type);
range = (ir1 - ir2).cast(e->type);
}
void visit(DivExp *e)
......@@ -3486,20 +3431,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
// Should we ignore the possibility of div-by-0???
if (ir2.containsZero())
{
visit((Expression *)e);
return;
}
// [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
SignExtendedNumber bdy[4];
bdy[0] = ir1.imin / ir2.imin;
bdy[1] = ir1.imin / ir2.imax;
bdy[2] = ir1.imax / ir2.imin;
bdy[3] = ir1.imax / ir2.imax;
range = IntRange::fromNumbers4(bdy).cast(e->type);
range = (ir1 / ir2).cast(e->type);
}
void visit(MulExp *e)
......@@ -3507,107 +3439,38 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
// [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
SignExtendedNumber bdy[4];
bdy[0] = ir1.imin * ir2.imin;
bdy[1] = ir1.imin * ir2.imax;
bdy[2] = ir1.imax * ir2.imin;
bdy[3] = ir1.imax * ir2.imax;
range = IntRange::fromNumbers4(bdy).cast(e->type);
range = (ir1 * ir2).cast(e->type);
}
void visit(ModExp *e)
{
IntRange irNum = getIntRange(e->e1);
IntRange irDen = getIntRange(e->e2).absNeg();
/*
due to the rules of D (C)'s % operator, we need to consider the cases
separately in different range of signs.
case 1. [500, 1700] % [7, 23] (numerator is always positive)
= [0, 22]
case 2. [-500, 1700] % [7, 23] (numerator can be negative)
= [-22, 22]
case 3. [-1700, -500] % [7, 23] (numerator is always negative)
= [-22, 0]
the number 22 is the maximum absolute value in the denomator's range. We
don't care about divide by zero.
*/
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
// Modding on 0 is invalid anyway.
if (!irDen.imin.negative)
if (!ir2.absNeg().imin.negative)
{
visit((Expression *)e);
return;
}
++ irDen.imin;
irDen.imax = -irDen.imin;
if (!irNum.imin.negative)
irNum.imin.value = 0;
else if (irNum.imin < irDen.imin)
irNum.imin = irDen.imin;
if (irNum.imax.negative)
{
irNum.imax.negative = false;
irNum.imax.value = 0;
}
else if (irNum.imax > irDen.imax)
irNum.imax = irDen.imax;
range = irNum.cast(e->type);
range = (ir1 % ir2).cast(e->type);
}
void visit(AndExp *e)
{
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
bool has1neg, has1pos, has2neg, has2pos;
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
IntRange result;
bool hasResult = false;
if (has1pos && has2pos)
result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2pos), hasResult);
if (has1pos && has2neg)
result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2neg), hasResult);
if (has1neg && has2pos)
result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2pos), hasResult);
if (has1neg && has2neg)
result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2neg), hasResult);
result.unionOrAssign(getIntRange(e->e1) & getIntRange(e->e2), hasResult);
assert(hasResult);
range = result.cast(e->type);
}
void visit(OrExp *e)
{
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
bool has1neg, has1pos, has2neg, has2pos;
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
IntRange result;
bool hasResult = false;
if (has1pos && has2pos)
result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2pos), hasResult);
if (has1pos && has2neg)
result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2neg), hasResult);
if (has1neg && has2pos)
result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2pos), hasResult);
if (has1neg && has2neg)
result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2neg), hasResult);
result.unionOrAssign(getIntRange(e->e1) | getIntRange(e->e2), hasResult);
assert(hasResult);
range = result.cast(e->type);
......@@ -3615,25 +3478,9 @@ IntRange getIntRange(Expression *e)
void visit(XorExp *e)
{
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
bool has1neg, has1pos, has2neg, has2pos;
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
IntRange result;
bool hasResult = false;
if (has1pos && has2pos)
result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2pos), hasResult);
if (has1pos && has2neg)
result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2neg), hasResult);
if (has1neg && has2pos)
result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2pos), hasResult);
if (has1neg && has2neg)
result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2neg), hasResult);
result.unionOrAssign(getIntRange(e->e1) ^ getIntRange(e->e2), hasResult);
assert(hasResult);
range = result.cast(e->type);
......@@ -3644,13 +3491,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
if (ir2.imin.negative)
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
SignExtendedNumber lower = ir1.imin << (ir1.imin.negative ? ir2.imax : ir2.imin);
SignExtendedNumber upper = ir1.imax << (ir1.imax.negative ? ir2.imin : ir2.imax);
range = IntRange(lower, upper).cast(e->type);
range = (ir1 << ir2).cast(e->type);
}
void visit(ShrExp *e)
......@@ -3658,13 +3499,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
if (ir2.imin.negative)
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
SignExtendedNumber lower = ir1.imin >> (ir1.imin.negative ? ir2.imin : ir2.imax);
SignExtendedNumber upper = ir1.imax >> (ir1.imax.negative ? ir2.imax : ir2.imin);
range = IntRange(lower, upper).cast(e->type);
range = (ir1 >> ir2).cast(e->type);
}
void visit(UshrExp *e)
......@@ -3672,10 +3507,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1).castUnsigned(e->e1->type);
IntRange ir2 = getIntRange(e->e2);
if (ir2.imin.negative)
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
range = IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(e->type);
range = (ir1 >> ir2).cast(e->type);
}
void visit(AssignExp *e)
......@@ -3719,7 +3551,7 @@ IntRange getIntRange(Expression *e)
void visit(NegExp *e)
{
IntRange ir = getIntRange(e->e1);
range = IntRange(-ir.imax, -ir.imin).cast(e->type);
range = (-ir).cast(e->type);
}
};
......
......@@ -1191,12 +1191,12 @@ void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
static void bitArraySet(BitArray *array, size_t idx)
{
array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] |= 1 << (idx & (sizeof(size_t) * CHAR_BIT - 1));
array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] |= 1ULL << (idx & (sizeof(size_t) * CHAR_BIT - 1));
}
static bool bitArrayGet(BitArray *array, size_t idx)
{
return (array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] & (1 << (idx & (sizeof(size_t) * CHAR_BIT - 1)))) != 0;
return (array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] & (1ULL << (idx & (sizeof(size_t) * CHAR_BIT - 1)))) != 0;
}
static void bitArrayLength(BitArray *array, size_t len)
......
......@@ -54,6 +54,26 @@ SignExtendedNumber SignExtendedNumber::max()
return SignExtendedNumber(UINT64_MAX, false);
}
SignExtendedNumber& SignExtendedNumber::operator++()
{
if (value != UINT64_MAX)
++value;
else if (negative)
{
value = 0;
negative = false;
}
return *this;
}
SignExtendedNumber SignExtendedNumber::operator~() const
{
if (~value == 0)
return SignExtendedNumber(~value);
else
return SignExtendedNumber(~value, !negative);
}
SignExtendedNumber SignExtendedNumber::operator-() const
{
if (value == 0)
......@@ -62,11 +82,26 @@ SignExtendedNumber SignExtendedNumber::operator-() const
return SignExtendedNumber(-value, !negative);
}
SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) const
SignExtendedNumber SignExtendedNumber::operator&(const SignExtendedNumber& rhs) const
{
uinteger_t sum = value + a.value;
bool carry = sum < value && sum < a.value;
if (negative != a.negative)
return SignExtendedNumber(value & rhs.value);
}
SignExtendedNumber SignExtendedNumber::operator|(const SignExtendedNumber& rhs) const
{
return SignExtendedNumber(value | rhs.value);
}
SignExtendedNumber SignExtendedNumber::operator^(const SignExtendedNumber& rhs) const
{
return SignExtendedNumber(value ^ rhs.value);
}
SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& rhs) const
{
uinteger_t sum = value + rhs.value;
bool carry = sum < value && sum < rhs.value;
if (negative != rhs.negative)
return SignExtendedNumber(sum, !carry);
else if (negative)
return SignExtendedNumber(carry ? sum : 0, true);
......@@ -74,16 +109,15 @@ SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) co
return SignExtendedNumber(carry ? UINT64_MAX : sum, false);
}
SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const
SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& rhs) const
{
if (a.isMinimum())
if (rhs.isMinimum())
return negative ? SignExtendedNumber(value, false) : max();
else
return *this + (-a);
return *this + (-rhs);
}
SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) const
SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& rhs) const
{
// perform *saturated* multiplication, otherwise we may get bogus ranges
// like 0x10 * 0x10 == 0x100 == 0.
......@@ -98,19 +132,19 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co
{
if (!negative)
return *this;
else if (a.negative)
else if (rhs.negative)
return max();
else
return a.value == 0 ? a : *this;
return rhs.value == 0 ? rhs : *this;
}
else if (a.value == 0)
return a * *this; // don't duplicate the symmetric case.
else if (rhs.value == 0)
return rhs * *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;
uinteger_t aAbs = copySign(rhs.value, rhs.negative);
rv.negative = negative != rhs.negative;
if (UINT64_MAX / tAbs < aAbs)
rv.value = rv.negative-1;
else
......@@ -118,7 +152,7 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co
return rv;
}
SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) const
SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& rhs) const
{
/* special handling for zeros:
INT65_MIN / INT65_MIN = 1
......@@ -126,15 +160,15 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
+ / 0 = INT65_MAX (eh?)
- / 0 = INT65_MIN (eh?)
*/
if (a.value == 0)
if (rhs.value == 0)
{
if (a.negative)
if (rhs.negative)
return SignExtendedNumber(value == 0 && negative);
else
return extreme(negative);
}
uinteger_t aAbs = copySign(a.value, a.negative);
uinteger_t aAbs = copySign(rhs.value, rhs.negative);
uinteger_t rvVal;
if (!isMinimum())
......@@ -147,7 +181,7 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
else
{
if (aAbs == 1)
return extreme(!a.negative);
return extreme(!rhs.negative);
rvVal = 1ULL << 63;
aAbs >>= 1;
if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
......@@ -157,18 +191,18 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
}
bool rvNeg = negative != a.negative;
bool rvNeg = negative != rhs.negative;
rvVal = copySign(rvVal, rvNeg);
return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
}
SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) const
SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& rhs) const
{
if (a.value == 0)
return !a.negative ? a : isMinimum() ? SignExtendedNumber(0) : *this;
if (rhs.value == 0)
return !rhs.negative ? rhs : isMinimum() ? SignExtendedNumber(0) : *this;
uinteger_t aAbs = copySign(a.value, a.negative);
uinteger_t aAbs = copySign(rhs.value, rhs.negative);
uinteger_t rvVal;
// a % b == sgn(a) * abs(a) % abs(b).
......@@ -186,25 +220,13 @@ SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) co
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
SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& rhs) 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)
else if (rhs.negative)
return extreme(negative);
uinteger_t v = copySign(value, negative);
......@@ -223,21 +245,21 @@ SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) c
r |= (v >> 1);
uinteger_t allowableShift = 63 - r;
if (a.value > allowableShift)
if (rhs.value > allowableShift)
return extreme(negative);
else
return SignExtendedNumber(value << a.value, negative);
return SignExtendedNumber(value << rhs.value, negative);
}
SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const
SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& rhs) const
{
if (a.negative || a.value > 64)
if (rhs.negative || rhs.value > 63)
return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
else if (isMinimum())
return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true);
return rhs.value == 0 ? *this : SignExtendedNumber(-1ULL << (64 - rhs.value), true);
uinteger_t x = value ^ -negative;
x >>= a.value;
x >>= rhs.value;
return SignExtendedNumber(x ^ -negative, negative);
}
......@@ -448,6 +470,364 @@ void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange,
}
}
IntRange IntRange::operator~() const
{
return IntRange(~imax, ~imin);
}
IntRange IntRange::operator-() const
{
return IntRange(-imax, -imin);
}
IntRange IntRange::operator&(const IntRange& rhs) const
{
// unsigned or identical sign bits
if ((imin.negative ^ imax.negative) != 1 && (rhs.imin.negative ^ rhs.imax.negative) != 1)
{
return IntRange(minAnd(*this, rhs), maxAnd(*this, rhs));
}
IntRange l = IntRange(*this);
IntRange r = IntRange(rhs);
// both intervals span [-1,0]
if ((l.imin.negative ^ l.imax.negative) == 1 && (r.imin.negative ^ r.imax.negative) == 1)
{
// cannot be larger than either l.max or r.max, set the other one to -1
SignExtendedNumber max = l.imax.value > r.imax.value ? l.imax : r.imax;
// only negative numbers for minimum
l.imax.value = -1;
l.imax.negative = true;
r.imax.value = -1;
r.imax.negative = true;
return IntRange(minAnd(l, r), max);
}
else
{
// only one interval spans [-1,0]
if ((l.imin.negative ^ l.imax.negative) == 1)
{
swap(l, r); // r spans [-1,0]
}
SignExtendedNumber minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
SignExtendedNumber minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
SignExtendedNumber maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
SignExtendedNumber maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
SignExtendedNumber min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
SignExtendedNumber max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
return IntRange(min, max);
}
}
IntRange IntRange::operator|(const IntRange& rhs) const
{
// unsigned or identical sign bits:
if ((imin.negative ^ imax.negative) == 0 && (rhs.imin.negative ^ rhs.imax.negative) == 0)
{
return IntRange(minOr(*this, rhs), maxOr(*this, rhs));
}
IntRange l = IntRange(*this);
IntRange r = IntRange(rhs);
// both intervals span [-1,0]
if ((l.imin.negative ^ l.imax.negative) == 1 && (r.imin.negative ^ r.imax.negative) == 1)
{
// cannot be smaller than either l.min or r.min, set the other one to 0
SignExtendedNumber min = l.imin.value < r.imin.value ? l.imin : r.imin;
// only negative numbers for minimum
l.imin.value = 0;
l.imin.negative = false;
r.imin.value = 0;
r.imin.negative = false;
return IntRange(min, maxOr(l, r));
}
else
{
// only one interval spans [-1,0]
if ((imin.negative ^ imax.negative) == 1)
{
swap(l, r); // r spans [-1,0]
}
SignExtendedNumber minOrNeg = minOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
SignExtendedNumber minOrPos = minOr(l, IntRange(SignExtendedNumber(0), r.imax));
SignExtendedNumber maxOrNeg = maxOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
SignExtendedNumber maxOrPos = maxOr(l, IntRange(SignExtendedNumber(0), r.imax));
SignExtendedNumber min = minOrNeg < minOrPos ? minOrNeg : minOrPos;
SignExtendedNumber max = maxOrNeg > maxOrPos ? maxOrNeg : maxOrPos;
return IntRange(min, max);
}
}
IntRange IntRange::operator^(const IntRange& rhs) const
{
return (*this & (~rhs)) | (~(*this) & rhs);
}
IntRange IntRange::operator+(const IntRange& rhs) const
{
return IntRange(imin + rhs.imin, imax + rhs.imax);
}
IntRange IntRange::operator-(const IntRange& rhs) const
{
return IntRange(imin - rhs.imax, imax - rhs.imin);
}
IntRange IntRange::operator*(const IntRange& rhs) const
{
// [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
SignExtendedNumber bdy[4];
bdy[0] = imin * rhs.imin;
bdy[1] = imin * rhs.imax;
bdy[2] = imax * rhs.imin;
bdy[3] = imax * rhs.imax;
return IntRange::fromNumbers4(bdy);
}
IntRange IntRange::operator/(const IntRange& rhs) const
{
// Handle divide by 0
if (rhs.imax.value == 0 && rhs.imin.value == 0)
return widest();
IntRange r = IntRange(rhs);
// Don't treat the whole range as divide by 0 if only one end of a range is 0.
// Issue 15289
if (r.imax.value == 0)
{
r.imax.value--;
}
else if(r.imin.value == 0)
{
r.imin.value++;
}
if (!imin.negative && !imax.negative && !r.imin.negative && !r.imax.negative)
{
return IntRange(imin / r.imax, imax / r.imin);
}
else
{
// [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
SignExtendedNumber bdy[4];
bdy[0] = imin / r.imin;
bdy[1] = imin / r.imax;
bdy[2] = imax / r.imin;
bdy[3] = imax / r.imax;
return IntRange::fromNumbers4(bdy);
}
}
IntRange IntRange::operator%(const IntRange& rhs) const
{
IntRange irNum = *this;
IntRange irDen = rhs.absNeg();
/*
due to the rules of D (C)'s % operator, we need to consider the cases
separately in different range of signs.
case 1. [500, 1700] % [7, 23] (numerator is always positive)
= [0, 22]
case 2. [-500, 1700] % [7, 23] (numerator can be negative)
= [-22, 22]
case 3. [-1700, -500] % [7, 23] (numerator is always negative)
= [-22, 0]
the number 22 is the maximum absolute value in the denomator's range. We
don't care about divide by zero.
*/
irDen.imin = irDen.imin + SignExtendedNumber(1);
irDen.imax = -irDen.imin;
if (!irNum.imin.negative)
{
irNum.imin.value = 0;
}
else if (irNum.imin < irDen.imin)
{
irNum.imin = irDen.imin;
}
if (irNum.imax.negative)
{
irNum.imax.negative = false;
irNum.imax.value = 0;
}
else if (irNum.imax > irDen.imax)
{
irNum.imax = irDen.imax;
}
return irNum;
}
IntRange IntRange::operator<<(const IntRange& rhs) const
{
IntRange r = IntRange(rhs);
if (r.imin.negative)
{
r = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
}
SignExtendedNumber lower = imin << (imin.negative ? r.imax : r.imin);
SignExtendedNumber upper = imax << (imax.negative ? r.imin : r.imax);
return IntRange(lower, upper);
}
IntRange IntRange::operator>>(const IntRange& rhs) const
{
IntRange r = IntRange(rhs);
if (r.imin.negative)
{
r = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
}
SignExtendedNumber lower = imin >> (imin.negative ? r.imin : r.imax);
SignExtendedNumber upper = imax >> (imax.negative ? r.imax : r.imin);
return IntRange(lower, upper);
}
SignExtendedNumber IntRange::maxOr(const IntRange& lhs, const IntRange& rhs)
{
uinteger_t x = 0;
bool sign = false;
uinteger_t xorvalue = lhs.imax.value ^ rhs.imax.value;
uinteger_t andvalue = lhs.imax.value & rhs.imax.value;
IntRange lhsc = IntRange(lhs);
IntRange rhsc = IntRange(rhs);
// Sign bit not part of the .value so we need an extra iteration
if (lhsc.imax.negative ^ rhsc.imax.negative)
{
sign = true;
if (lhsc.imax.negative)
{
if (!lhsc.imin.negative)
{
lhsc.imin.value = 0;
}
if (!rhsc.imin.negative)
{
rhsc.imin.value = 0;
}
}
}
else if (lhsc.imin.negative & rhsc.imin.negative)
{
sign = true;
}
else if (lhsc.imax.negative & rhsc.imax.negative)
{
return SignExtendedNumber(-1, false);
}
for (uinteger_t d = 1ULL << (8 * sizeof(uinteger_t) - 1); d; d >>= 1)
{
if (xorvalue & d)
{
x |= d;
if (lhsc.imax.value & d)
{
if (~lhsc.imin.value & d)
{
lhsc.imin.value = 0;
}
}
else
{
if (~rhsc.imin.value & d)
{
rhsc.imin.value = 0;
}
}
}
else if (lhsc.imin.value & rhsc.imin.value & d)
{
x |= d;
}
else if (andvalue & d)
{
x |= (d << 1) - 1;
break;
}
}
return SignExtendedNumber(x, sign);
}
SignExtendedNumber IntRange::minOr(const IntRange& lhs, const IntRange& rhs)
{
return ~maxAnd(~lhs, ~rhs);
}
SignExtendedNumber IntRange::maxAnd(const IntRange& lhs, const IntRange& rhs)
{
uinteger_t x = 0;
bool sign = false;
IntRange lhsc = IntRange(lhs);
IntRange rhsc = IntRange(rhs);
if (lhsc.imax.negative & rhsc.imax.negative)
{
sign = true;
}
for (uinteger_t d = 1ULL << (8 * sizeof(uinteger_t) - 1); d; d >>= 1)
{
if (lhsc.imax.value & rhsc.imax.value & d)
{
x |= d;
if (~lhsc.imin.value & d)
{
lhsc.imin.value = 0;
}
if (~rhsc.imin.value & d)
{
rhsc.imin.value = 0;
}
}
else if (~lhsc.imin.value & d && lhsc.imax.value & d)
{
lhsc.imax.value |= d - 1;
}
else if (~rhsc.imin.value & d && rhsc.imax.value & d)
{
rhsc.imax.value |= d - 1;
}
}
return SignExtendedNumber(x, sign);
}
SignExtendedNumber IntRange::minAnd(const IntRange& lhs, const IntRange& rhs)
{
return ~maxOr(~lhs, ~rhs);
}
void IntRange::swap(IntRange& a, IntRange& b)
{
IntRange aux = a;
a = b;
b = aux;
}
const IntRange& IntRange::dump(const char* funcName, Expression *e) const
{
......
......@@ -60,13 +60,23 @@ struct SignExtendedNumber
bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); }
/// Increase the sign-extended number by 1 (saturated).
SignExtendedNumber& operator++();
/// Compute the saturated complement of a sign-extended number.
SignExtendedNumber operator~() const;
/// Compute the saturated negation of a sign-extended number.
SignExtendedNumber operator-() const;
/// Compute the saturated binary and of two sign-extended number.
SignExtendedNumber operator&(const SignExtendedNumber&) const;
/// Compute the saturated binary or of two sign-extended number.
SignExtendedNumber operator|(const SignExtendedNumber&) const;
/// Compute the saturated binary xor of two sign-extended number.
SignExtendedNumber operator^(const SignExtendedNumber&) const;
/// Compute the saturated sum of two sign-extended number.
SignExtendedNumber operator+(const SignExtendedNumber&) const;
/// Compute the saturated difference of two sign-extended number.
SignExtendedNumber operator-(const SignExtendedNumber& a) const;
SignExtendedNumber operator-(const SignExtendedNumber&) const;
/// Compute the saturated product of two sign-extended number.
SignExtendedNumber operator*(const SignExtendedNumber&) const;
/// Compute the saturated quotient of two sign-extended number.
......@@ -74,9 +84,6 @@ struct SignExtendedNumber
/// Compute the saturated modulus of two sign-extended number.
SignExtendedNumber operator%(const SignExtendedNumber&) const;
/// Increase the sign-extended number by 1 (saturated).
SignExtendedNumber& operator++();
/// Compute the saturated shifts of two sign-extended number.
SignExtendedNumber operator<<(const SignExtendedNumber&) const;
SignExtendedNumber operator>>(const SignExtendedNumber&) const;
......@@ -146,4 +153,25 @@ struct IntRange
/// Split the range into two nonnegative- and negative-only subintervals.
void splitBySign(IntRange& negRange, bool& hasNegRange,
IntRange& nonNegRange, bool& hasNonNegRange) const;
/// Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
/// https://github.com/tgehr/d-compiler/blob/master/vrange.d
static SignExtendedNumber maxOr(const IntRange&, const IntRange&);
static SignExtendedNumber minOr(const IntRange&, const IntRange&);
static SignExtendedNumber maxAnd(const IntRange&, const IntRange&);
static SignExtendedNumber minAnd(const IntRange&, const IntRange&);
static void swap(IntRange&, IntRange&);
IntRange operator~() const;
IntRange operator-() const;
IntRange operator&(const IntRange&) const;
IntRange operator|(const IntRange&) const;
IntRange operator^(const IntRange&) const;
IntRange operator+(const IntRange&) const;
IntRange operator-(const IntRange&) const;
IntRange operator*(const IntRange&) const;
IntRange operator/(const IntRange&) const;
IntRange operator%(const IntRange&) const;
IntRange operator<<(const IntRange&) const;
IntRange operator>>(const IntRange&) const;
};
......@@ -3832,6 +3832,7 @@ MATCH TypeVector::implicitConvTo(Type *to)
//printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to)
return MATCHexact;
#ifdef IN_GCC
if (to->ty == Tvector)
{
TypeVector *tv = (TypeVector *)to;
......@@ -3848,6 +3849,10 @@ MATCH TypeVector::implicitConvTo(Type *to)
// Otherwise implicitly convertible only if basetypes are.
return basetype->implicitConvTo(tv->basetype);
}
#else
if (ty == to->ty)
return MATCHconvert;
#endif
return MATCHnomatch;
}
......
// PERMUTE_ARGS: -O -inline
// Test value-range propagation.
// See Bug 3147, Bug 6000, Bug 5225.
// https://issues.dlang.org/show_bug.cgi?id=3147
// https://issues.dlang.org/show_bug.cgi?id=6000
// https://issues.dlang.org/show_bug.cgi?id=5225
void add() {
void add()
{
byte x, y;
short a = x + y;
}
void leftShift() {
void leftShift()
{
byte x, y;
short z = x << 1;
}
void leftShiftFail() {
ubyte x, y;
ushort z;
static assert(!__traits(compiles, z = x << y));
// 1 << 31 surely overflows the range of 'ushort'.
void leftShiftFail()
{
{
ubyte x, y;
ushort z;
static assert(!__traits(compiles, z = x << y));
// 1 << 31 surely overflows the range of 'ushort'.
}
{
ulong a, b;
int res;
static assert(!__traits(compiles, res = a << (b % 65U)));
}
}
void rightShiftFail() {
short x;
byte y, z;
static assert(!__traits(compiles, z = x >> y));
// [this passes in 2.053.]
void rightShiftFail()
{
{
short x;
byte y, z;
static assert(!__traits(compiles, z = x >> y));
// [this passes in 2.053.]
}
{
ulong a, b;
int res;
static assert(!__traits(compiles, res = a >> (b % 65U)));
}
}
void rightShift() {
void rightShift()
{
ushort x;
ubyte y = x >> 16;
}
void unsignedRightShiftFail() {
void unsignedRightShiftFail()
{
int x;
ubyte y;
static assert(!__traits(compiles, y = x >>> 2));
// [this passes in 2.053.]
}
void subtract() {
void subtract()
{
ubyte x, y;
short z = x - y;
}
void multiply() {
void multiply()
{
byte x, y;
short z = x * y;
}
void subMulFail() {
void subMulFail()
{
ubyte x, y;
ubyte z;
static assert(!__traits(compiles, z = x - y));
......@@ -57,65 +82,82 @@ void subMulFail() {
// [these pass in 2.053.]
}
void multiplyNeg1() {
void multiplyNeg1()
{
byte b;
b = -1 + (b * -1);
static assert(!__traits(compiles, b = -1 + b * ulong.max));
}
void divide() {
void divide()
{
short w;
byte y = w / 300;
}
void divideFail() {
void divideFail()
{
short w;
byte y;
static assert(!__traits(compiles, y = w / -1));
}
void plus1Fail() {
void plus1Fail()
{
byte u, v;
static assert(!__traits(compiles, v = u + 1));
// [these pass in 2.053.]
}
void modulus() {
void modulus()
{
int x;
byte u = x % 128;
}
void modulus_bug6000a() {
void modulus_bug6000a()
{
ulong t;
uint u = t % 16;
}
void modulus_bug6000b() {
void modulus_bug6000b()
{
long n = 10520;
ubyte b;
static assert(!__traits(compiles, b = n % 10));
}
void modulus2() {
void modulus2()
{
short s;
byte b = byte.max;
byte c = s % b;
}
void modulus3() {
void modulus3()
{
int i;
short s = short.max;
short t = i % s;
}
void modulus4() {
void modulus4()
{
uint i;
ushort s;
short t;
static assert(!__traits(compiles, t = i % s));
}
void modulusFail() {
void modulus5()
{
short a;
byte foo = (a - short.max - 1) % 127;
}
void modulusFail()
{
int i;
short s;
byte b;
......@@ -124,7 +166,8 @@ void modulusFail() {
// [these pass in 2.053.]
}
void bitwise() {
void bitwise()
{
ubyte a, b, c;
uint d;
c = a & b;
......@@ -134,56 +177,159 @@ void bitwise() {
// [these pass in 2.053.]
}
void bitAnd() {
void bitAnd()
{
byte c;
int d;
c = (0x3ff_ffffU << (0&c)) & (0x4000_0000U << (0&c));
// the result of the above is always 0 :).
}
void bitOrFail() {
ubyte c;
static assert(!__traits(compiles, c = c | 0x100));
// [this passes in 2.053.]
void bitAndTest()
{
{
ushort a, b;
byte res = ((a % 7) - 6) & ((b % 7) - 6);
}
{
// rhs[-128..127] outside range of lhs[0..255]
// -> calls byte.implicitConvTo(ubyte) => MATCH.convert
byte a, b;
ubyte res;
res = cast(byte)(a + 5) & b;
res = cast(byte)(a - 5) & b;
res = cast(byte)(a / 5) & b;
res = cast(byte)(a * 5) & b;
res = cast(byte)(a % 5) & b;
}
}
void bitOrFail()
{
{
ubyte c;
static assert(!__traits(compiles, c = c | 0x100));
// [this passes in 2.053.]
}
{
byte a, b;
ubyte res;
static assert(!__traits(compiles, res = (a + 5) | b)); // [-128..255]
static assert(!__traits(compiles, res = (a - 5) | b)); // [-133..127]
static assert(!__traits(compiles, res = (a / 5) | b)); // [-128..127]
static assert(!__traits(compiles, res = (a * 5) | b)); // [-640..639]
static assert(!__traits(compiles, res = (a % 5) | b)); // [-128..127]
}
}
void bitAndOr() {
void bitAndOr()
{
ubyte c;
c = (c | 0x1000) & ~0x1000;
}
void bitAndFail() {
int d;
short s;
byte c;
static assert(!__traits(compiles, c = d & s));
static assert(!__traits(compiles, c = d & 256));
// [these pass in 2.053.]
void bitOrTest()
{
{
// Tests condition for different signs between min & max
// ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1
ushort a, b;
byte res = ((a % 127) - 126) | ((b % 6) - 5);
}
{
// rhs[-128..127] outside range of lhs[0..255]
// -> calls byte.implicitConvTo(ubyte) => MATCH.convert
byte a, b, c;
ubyte res;
res = cast(byte)(a + 5) | b;
res = cast(byte)(a - 5) | b;
res = cast(byte)(a / 5) | b;
res = cast(byte)(a * 5) | b;
res = cast(byte)(a % 5) | b;
}
}
void bitXor() {
ushort s;
ubyte c;
c = (0xffff << (s&0)) ^ 0xff00;
void bitAndFail()
{
{
int d;
short s;
byte c;
static assert(!__traits(compiles, c = d & s));
static assert(!__traits(compiles, c = d & 256));
// [these pass in 2.053.]
}
{
byte a, b;
ubyte res;
static assert(!__traits(compiles, res = (a + 5) & b)); // [-128..132]
static assert(!__traits(compiles, res = (a - 5) & b)); // [-256..127]
static assert(!__traits(compiles, res = (a / 5) & b)); // [-128..127]
static assert(!__traits(compiles, res = (a * 5) & b)); // [-640..635]
static assert(!__traits(compiles, res = (a % 5) & b)); // [-128..127]
}
}
void bitXor()
{
{
ushort s;
ubyte c;
c = (0xffff << (s & 0)) ^ 0xff00;
}
{
// rhs[-128..127] outside range of lhs[0..255]
// -> calls byte.implicitConvTo(ubyte) => MATCH.convert
byte a, b, c;
ubyte res;
res = cast(byte)(a + 5) ^ b;
res = cast(byte)(a - 5) ^ b;
res = cast(byte)(a / 5) ^ b;
res = cast(byte)(a * 5) ^ b;
res = cast(byte)(a % 5) ^ b;
}
}
void bitComplement() {
void bitXorFail()
{
{
byte a, b;
ubyte res;
static assert(!__traits(compiles, res = (a + 5) ^ b)); // [-256..255]
static assert(!__traits(compiles, res = (a - 5) ^ b)); // [-256..255]
static assert(!__traits(compiles, res = (a / 5) ^ b)); // [-128..127]
static assert(!__traits(compiles, res = (a * 5) ^ b)); // [-640..1023]
static assert(!__traits(compiles, res = (a % 5) ^ b)); // [-128..127]
}
}
void bitComplement()
{
int i;
ubyte b = ~(i | ~0xff);
}
void bitComplementFail() {
void bitComplementFail()
{
ubyte b;
static assert(!__traits(compiles, b = ~(b | 1)));
// [this passes in 2.053.]
}
void negation() {
void negation()
{
int x;
byte b = -(x & 0x7);
}
void negationFail() {
void negationFail()
{
int x;
byte b;
static assert(!__traits(compiles, b = -(x & 255)));
......@@ -200,7 +346,8 @@ short bug1977_comment5(byte i) {
return o;
}
void testDchar() {
void testDchar()
{
dchar d;
uint i;
/+
......@@ -210,13 +357,15 @@ void testDchar() {
d = i % 0x110000;
}
void bug1977_comment11() {
void bug1977_comment11()
{
uint a;
byte b = a & 1;
// [this passes in 2.053.]
}
void bug1977_comment20() {
void bug1977_comment20()
{
long a;
int b = a % 1000;
}
......@@ -329,3 +478,32 @@ void test13001(bool unknown)
static assert(!__traits(compiles, b = i + 254));
}
}
void test10310()
{
int y;
ubyte x = ((y & 252) ^ 2) + 1;
}
// https://issues.dlang.org/show_bug.cgi?id=15289
void test15289a()
{
int [] arr = [1, 2, 3, 4];
uint foo = 50 / arr.length;
}
void test15289b()
{
int [] arr = [1, 2, 3, 4];
uint foo = 50 % arr.length;
}
void testShiftRightOnNegative()
{
int neg = -1;
uint[] arr = [1, 2, 3];
ubyte b;
// Shift with negative value returns value in range [0, ulong.max]
static assert(!__traits(compiles, b = arr.length >> neg));
static assert(!__traits(compiles, b = arr.length << neg));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment