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 The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository. merge done from the dlang/dmd repository.
...@@ -446,13 +446,13 @@ UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2) ...@@ -446,13 +446,13 @@ UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2)
if (n2 == -1 && !type->isunsigned()) if (n2 == -1 && !type->isunsigned())
{ {
// Check for int.min / -1 // 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"); e2->error("integer overflow: int.min / -1");
new(&ue) ErrorExp(); new(&ue) ErrorExp();
return ue; 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"); e2->error("integer overflow: long.min / -1");
new(&ue) ErrorExp(); new(&ue) ErrorExp();
......
...@@ -986,6 +986,19 @@ MATCH implicitConvTo(Expression *e, Type *t) ...@@ -986,6 +986,19 @@ MATCH implicitConvTo(Expression *e, Type *t)
visit((Expression *)e); 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) void visit(OrExp *e)
{ {
visit((Expression *)e); visit((Expression *)e);
...@@ -3381,74 +3394,6 @@ IntRange getIntRange(Expression *e) ...@@ -3381,74 +3394,6 @@ IntRange getIntRange(Expression *e)
{ {
class IntRangeVisitor : public Visitor 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: public:
IntRange range; IntRange range;
...@@ -3471,14 +3416,14 @@ IntRange getIntRange(Expression *e) ...@@ -3471,14 +3416,14 @@ IntRange getIntRange(Expression *e)
{ {
IntRange ir1 = getIntRange(e->e1); IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2); 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) void visit(MinExp *e)
{ {
IntRange ir1 = getIntRange(e->e1); IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2); 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) void visit(DivExp *e)
...@@ -3486,20 +3431,7 @@ IntRange getIntRange(Expression *e) ...@@ -3486,20 +3431,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1); IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2); IntRange ir2 = getIntRange(e->e2);
// Should we ignore the possibility of div-by-0??? range = (ir1 / ir2).cast(e->type);
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);
} }
void visit(MulExp *e) void visit(MulExp *e)
...@@ -3507,107 +3439,38 @@ IntRange getIntRange(Expression *e) ...@@ -3507,107 +3439,38 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1); IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2); IntRange ir2 = getIntRange(e->e2);
// [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)] range = (ir1 * ir2).cast(e->type);
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);
} }
void visit(ModExp *e) void visit(ModExp *e)
{ {
IntRange irNum = getIntRange(e->e1); IntRange ir1 = getIntRange(e->e1);
IntRange irDen = getIntRange(e->e2).absNeg(); IntRange ir2 = getIntRange(e->e2);
/*
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.
*/
// Modding on 0 is invalid anyway. // Modding on 0 is invalid anyway.
if (!irDen.imin.negative) if (!ir2.absNeg().imin.negative)
{ {
visit((Expression *)e); visit((Expression *)e);
return; return;
} }
range = (ir1 % ir2).cast(e->type);
++ 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);
} }
void visit(AndExp *e) 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; IntRange result;
bool hasResult = false; bool hasResult = false;
if (has1pos && has2pos) result.unionOrAssign(getIntRange(e->e1) & getIntRange(e->e2), hasResult);
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);
assert(hasResult); assert(hasResult);
range = result.cast(e->type); range = result.cast(e->type);
} }
void visit(OrExp *e) 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; IntRange result;
bool hasResult = false; bool hasResult = false;
if (has1pos && has2pos) result.unionOrAssign(getIntRange(e->e1) | getIntRange(e->e2), hasResult);
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);
assert(hasResult); assert(hasResult);
range = result.cast(e->type); range = result.cast(e->type);
...@@ -3615,25 +3478,9 @@ IntRange getIntRange(Expression *e) ...@@ -3615,25 +3478,9 @@ IntRange getIntRange(Expression *e)
void visit(XorExp *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; IntRange result;
bool hasResult = false; bool hasResult = false;
if (has1pos && has2pos) result.unionOrAssign(getIntRange(e->e1) ^ getIntRange(e->e2), hasResult);
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);
assert(hasResult); assert(hasResult);
range = result.cast(e->type); range = result.cast(e->type);
...@@ -3644,13 +3491,7 @@ IntRange getIntRange(Expression *e) ...@@ -3644,13 +3491,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1); IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2); IntRange ir2 = getIntRange(e->e2);
if (ir2.imin.negative) range = (ir1 << ir2).cast(e->type);
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);
} }
void visit(ShrExp *e) void visit(ShrExp *e)
...@@ -3658,13 +3499,7 @@ IntRange getIntRange(Expression *e) ...@@ -3658,13 +3499,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1); IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2); IntRange ir2 = getIntRange(e->e2);
if (ir2.imin.negative) range = (ir1 >> ir2).cast(e->type);
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);
} }
void visit(UshrExp *e) void visit(UshrExp *e)
...@@ -3672,10 +3507,7 @@ IntRange getIntRange(Expression *e) ...@@ -3672,10 +3507,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1).castUnsigned(e->e1->type); IntRange ir1 = getIntRange(e->e1).castUnsigned(e->e1->type);
IntRange ir2 = getIntRange(e->e2); IntRange ir2 = getIntRange(e->e2);
if (ir2.imin.negative) range = (ir1 >> ir2).cast(e->type);
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
range = IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(e->type);
} }
void visit(AssignExp *e) void visit(AssignExp *e)
...@@ -3719,7 +3551,7 @@ IntRange getIntRange(Expression *e) ...@@ -3719,7 +3551,7 @@ IntRange getIntRange(Expression *e)
void visit(NegExp *e) void visit(NegExp *e)
{ {
IntRange ir = getIntRange(e->e1); 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) ...@@ -1191,12 +1191,12 @@ void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
static void bitArraySet(BitArray *array, size_t idx) 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) 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) static void bitArrayLength(BitArray *array, size_t len)
......
...@@ -54,6 +54,26 @@ SignExtendedNumber SignExtendedNumber::max() ...@@ -54,6 +54,26 @@ SignExtendedNumber SignExtendedNumber::max()
return SignExtendedNumber(UINT64_MAX, false); 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 SignExtendedNumber SignExtendedNumber::operator-() const
{ {
if (value == 0) if (value == 0)
...@@ -62,11 +82,26 @@ SignExtendedNumber SignExtendedNumber::operator-() const ...@@ -62,11 +82,26 @@ SignExtendedNumber SignExtendedNumber::operator-() const
return SignExtendedNumber(-value, !negative); return SignExtendedNumber(-value, !negative);
} }
SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) const SignExtendedNumber SignExtendedNumber::operator&(const SignExtendedNumber& rhs) const
{ {
uinteger_t sum = value + a.value; return SignExtendedNumber(value & rhs.value);
bool carry = sum < value && sum < a.value; }
if (negative != a.negative)
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); return SignExtendedNumber(sum, !carry);
else if (negative) else if (negative)
return SignExtendedNumber(carry ? sum : 0, true); return SignExtendedNumber(carry ? sum : 0, true);
...@@ -74,16 +109,15 @@ SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) co ...@@ -74,16 +109,15 @@ SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) co
return SignExtendedNumber(carry ? UINT64_MAX : sum, false); 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(); return negative ? SignExtendedNumber(value, false) : max();
else else
return *this + (-a); return *this + (-rhs);
} }
SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& rhs) const
SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) const
{ {
// perform *saturated* multiplication, otherwise we may get bogus ranges // perform *saturated* multiplication, otherwise we may get bogus ranges
// like 0x10 * 0x10 == 0x100 == 0. // like 0x10 * 0x10 == 0x100 == 0.
...@@ -98,19 +132,19 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co ...@@ -98,19 +132,19 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co
{ {
if (!negative) if (!negative)
return *this; return *this;
else if (a.negative) else if (rhs.negative)
return max(); return max();
else else
return a.value == 0 ? a : *this; return rhs.value == 0 ? rhs : *this;
} }
else if (a.value == 0) else if (rhs.value == 0)
return a * *this; // don't duplicate the symmetric case. return rhs * *this; // don't duplicate the symmetric case.
SignExtendedNumber rv; SignExtendedNumber rv;
// these are != 0 now surely. // these are != 0 now surely.
uinteger_t tAbs = copySign(value, negative); uinteger_t tAbs = copySign(value, negative);
uinteger_t aAbs = copySign(a.value, a.negative); uinteger_t aAbs = copySign(rhs.value, rhs.negative);
rv.negative = negative != a.negative; rv.negative = negative != rhs.negative;
if (UINT64_MAX / tAbs < aAbs) if (UINT64_MAX / tAbs < aAbs)
rv.value = rv.negative-1; rv.value = rv.negative-1;
else else
...@@ -118,7 +152,7 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co ...@@ -118,7 +152,7 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co
return rv; return rv;
} }
SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) const SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& rhs) const
{ {
/* special handling for zeros: /* special handling for zeros:
INT65_MIN / INT65_MIN = 1 INT65_MIN / INT65_MIN = 1
...@@ -126,15 +160,15 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co ...@@ -126,15 +160,15 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
+ / 0 = INT65_MAX (eh?) + / 0 = INT65_MAX (eh?)
- / 0 = INT65_MIN (eh?) - / 0 = INT65_MIN (eh?)
*/ */
if (a.value == 0) if (rhs.value == 0)
{ {
if (a.negative) if (rhs.negative)
return SignExtendedNumber(value == 0 && negative); return SignExtendedNumber(value == 0 && negative);
else else
return extreme(negative); return extreme(negative);
} }
uinteger_t aAbs = copySign(a.value, a.negative); uinteger_t aAbs = copySign(rhs.value, rhs.negative);
uinteger_t rvVal; uinteger_t rvVal;
if (!isMinimum()) if (!isMinimum())
...@@ -147,7 +181,7 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co ...@@ -147,7 +181,7 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
else else
{ {
if (aAbs == 1) if (aAbs == 1)
return extreme(!a.negative); return extreme(!rhs.negative);
rvVal = 1ULL << 63; rvVal = 1ULL << 63;
aAbs >>= 1; aAbs >>= 1;
if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1; if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
...@@ -157,18 +191,18 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co ...@@ -157,18 +191,18 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16; if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32; if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
} }
bool rvNeg = negative != a.negative; bool rvNeg = negative != rhs.negative;
rvVal = copySign(rvVal, rvNeg); rvVal = copySign(rvVal, rvNeg);
return SignExtendedNumber(rvVal, rvVal != 0 && 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) if (rhs.value == 0)
return !a.negative ? a : isMinimum() ? SignExtendedNumber(0) : *this; 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; uinteger_t rvVal;
// a % b == sgn(a) * abs(a) % abs(b). // a % b == sgn(a) * abs(a) % abs(b).
...@@ -186,25 +220,13 @@ SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) co ...@@ -186,25 +220,13 @@ SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) co
return SignExtendedNumber(rvVal, rvVal != 0 && negative); return SignExtendedNumber(rvVal, rvVal != 0 && negative);
} }
SignExtendedNumber& SignExtendedNumber::operator++() SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& rhs) const
{
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 // assume left-shift the shift-amount is always unsigned. Thus negative
// shifts will give huge result. // shifts will give huge result.
if (value == 0) if (value == 0)
return *this; return *this;
else if (a.negative) else if (rhs.negative)
return extreme(negative); return extreme(negative);
uinteger_t v = copySign(value, negative); uinteger_t v = copySign(value, negative);
...@@ -223,21 +245,21 @@ SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) c ...@@ -223,21 +245,21 @@ SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) c
r |= (v >> 1); r |= (v >> 1);
uinteger_t allowableShift = 63 - r; uinteger_t allowableShift = 63 - r;
if (a.value > allowableShift) if (rhs.value > allowableShift)
return extreme(negative); return extreme(negative);
else 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); return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
else if (isMinimum()) 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; uinteger_t x = value ^ -negative;
x >>= a.value; x >>= rhs.value;
return SignExtendedNumber(x ^ -negative, negative); return SignExtendedNumber(x ^ -negative, negative);
} }
...@@ -448,6 +470,364 @@ void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange, ...@@ -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 const IntRange& IntRange::dump(const char* funcName, Expression *e) const
{ {
......
...@@ -60,13 +60,23 @@ struct SignExtendedNumber ...@@ -60,13 +60,23 @@ struct SignExtendedNumber
bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); } bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); } 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. /// Compute the saturated negation of a sign-extended number.
SignExtendedNumber operator-() const; 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. /// Compute the saturated sum of two sign-extended number.
SignExtendedNumber operator+(const SignExtendedNumber&) const; SignExtendedNumber operator+(const SignExtendedNumber&) const;
/// Compute the saturated difference of two sign-extended number. /// 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. /// Compute the saturated product of two sign-extended number.
SignExtendedNumber operator*(const SignExtendedNumber&) const; SignExtendedNumber operator*(const SignExtendedNumber&) const;
/// Compute the saturated quotient of two sign-extended number. /// Compute the saturated quotient of two sign-extended number.
...@@ -74,9 +84,6 @@ struct SignExtendedNumber ...@@ -74,9 +84,6 @@ struct SignExtendedNumber
/// Compute the saturated modulus of two sign-extended number. /// Compute the saturated modulus of two sign-extended number.
SignExtendedNumber operator%(const SignExtendedNumber&) const; SignExtendedNumber operator%(const SignExtendedNumber&) const;
/// Increase the sign-extended number by 1 (saturated).
SignExtendedNumber& operator++();
/// Compute the saturated shifts of two sign-extended number. /// Compute the saturated shifts of two sign-extended number.
SignExtendedNumber operator<<(const SignExtendedNumber&) const; SignExtendedNumber operator<<(const SignExtendedNumber&) const;
SignExtendedNumber operator>>(const SignExtendedNumber&) const; SignExtendedNumber operator>>(const SignExtendedNumber&) const;
...@@ -146,4 +153,25 @@ struct IntRange ...@@ -146,4 +153,25 @@ struct IntRange
/// Split the range into two nonnegative- and negative-only subintervals. /// Split the range into two nonnegative- and negative-only subintervals.
void splitBySign(IntRange& negRange, bool& hasNegRange, void splitBySign(IntRange& negRange, bool& hasNegRange,
IntRange& nonNegRange, bool& hasNonNegRange) const; 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) ...@@ -3832,6 +3832,7 @@ MATCH TypeVector::implicitConvTo(Type *to)
//printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars()); //printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to) if (this == to)
return MATCHexact; return MATCHexact;
#ifdef IN_GCC
if (to->ty == Tvector) if (to->ty == Tvector)
{ {
TypeVector *tv = (TypeVector *)to; TypeVector *tv = (TypeVector *)to;
...@@ -3848,6 +3849,10 @@ MATCH TypeVector::implicitConvTo(Type *to) ...@@ -3848,6 +3849,10 @@ MATCH TypeVector::implicitConvTo(Type *to)
// Otherwise implicitly convertible only if basetypes are. // Otherwise implicitly convertible only if basetypes are.
return basetype->implicitConvTo(tv->basetype); return basetype->implicitConvTo(tv->basetype);
} }
#else
if (ty == to->ty)
return MATCHconvert;
#endif
return MATCHnomatch; return MATCHnomatch;
} }
......
// PERMUTE_ARGS: -O -inline // PERMUTE_ARGS: -O -inline
// Test value-range propagation. // 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; byte x, y;
short a = x + y; short a = x + y;
} }
void leftShift() { void leftShift()
{
byte x, y; byte x, y;
short z = x << 1; short z = x << 1;
} }
void leftShiftFail() { void leftShiftFail()
ubyte x, y; {
ushort z; {
static assert(!__traits(compiles, z = x << y)); ubyte x, y;
// 1 << 31 surely overflows the range of 'ushort'. 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() { void rightShiftFail()
short x; {
byte y, z; {
static assert(!__traits(compiles, z = x >> y)); short x;
// [this passes in 2.053.] 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; ushort x;
ubyte y = x >> 16; ubyte y = x >> 16;
} }
void unsignedRightShiftFail() { void unsignedRightShiftFail()
{
int x; int x;
ubyte y; ubyte y;
static assert(!__traits(compiles, y = x >>> 2)); static assert(!__traits(compiles, y = x >>> 2));
// [this passes in 2.053.] // [this passes in 2.053.]
} }
void subtract() { void subtract()
{
ubyte x, y; ubyte x, y;
short z = x - y; short z = x - y;
} }
void multiply() { void multiply()
{
byte x, y; byte x, y;
short z = x * y; short z = x * y;
} }
void subMulFail() { void subMulFail()
{
ubyte x, y; ubyte x, y;
ubyte z; ubyte z;
static assert(!__traits(compiles, z = x - y)); static assert(!__traits(compiles, z = x - y));
...@@ -57,65 +82,82 @@ void subMulFail() { ...@@ -57,65 +82,82 @@ void subMulFail() {
// [these pass in 2.053.] // [these pass in 2.053.]
} }
void multiplyNeg1() { void multiplyNeg1()
{
byte b; byte b;
b = -1 + (b * -1); b = -1 + (b * -1);
static assert(!__traits(compiles, b = -1 + b * ulong.max)); static assert(!__traits(compiles, b = -1 + b * ulong.max));
} }
void divide() { void divide()
{
short w; short w;
byte y = w / 300; byte y = w / 300;
} }
void divideFail() { void divideFail()
{
short w; short w;
byte y; byte y;
static assert(!__traits(compiles, y = w / -1)); static assert(!__traits(compiles, y = w / -1));
} }
void plus1Fail() { void plus1Fail()
{
byte u, v; byte u, v;
static assert(!__traits(compiles, v = u + 1)); static assert(!__traits(compiles, v = u + 1));
// [these pass in 2.053.] // [these pass in 2.053.]
} }
void modulus() { void modulus()
{
int x; int x;
byte u = x % 128; byte u = x % 128;
} }
void modulus_bug6000a() { void modulus_bug6000a()
{
ulong t; ulong t;
uint u = t % 16; uint u = t % 16;
} }
void modulus_bug6000b() { void modulus_bug6000b()
{
long n = 10520; long n = 10520;
ubyte b; ubyte b;
static assert(!__traits(compiles, b = n % 10)); static assert(!__traits(compiles, b = n % 10));
} }
void modulus2() { void modulus2()
{
short s; short s;
byte b = byte.max; byte b = byte.max;
byte c = s % b; byte c = s % b;
} }
void modulus3() { void modulus3()
{
int i; int i;
short s = short.max; short s = short.max;
short t = i % s; short t = i % s;
} }
void modulus4() { void modulus4()
{
uint i; uint i;
ushort s; ushort s;
short t; short t;
static assert(!__traits(compiles, t = i % s)); static assert(!__traits(compiles, t = i % s));
} }
void modulusFail() { void modulus5()
{
short a;
byte foo = (a - short.max - 1) % 127;
}
void modulusFail()
{
int i; int i;
short s; short s;
byte b; byte b;
...@@ -124,7 +166,8 @@ void modulusFail() { ...@@ -124,7 +166,8 @@ void modulusFail() {
// [these pass in 2.053.] // [these pass in 2.053.]
} }
void bitwise() { void bitwise()
{
ubyte a, b, c; ubyte a, b, c;
uint d; uint d;
c = a & b; c = a & b;
...@@ -134,56 +177,159 @@ void bitwise() { ...@@ -134,56 +177,159 @@ void bitwise() {
// [these pass in 2.053.] // [these pass in 2.053.]
} }
void bitAnd() { void bitAnd()
{
byte c; byte c;
int d; int d;
c = (0x3ff_ffffU << (0&c)) & (0x4000_0000U << (0&c)); c = (0x3ff_ffffU << (0&c)) & (0x4000_0000U << (0&c));
// the result of the above is always 0 :). // the result of the above is always 0 :).
} }
void bitOrFail() { void bitAndTest()
ubyte c; {
static assert(!__traits(compiles, c = c | 0x100)); {
// [this passes in 2.053.] 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; ubyte c;
c = (c | 0x1000) & ~0x1000; c = (c | 0x1000) & ~0x1000;
} }
void bitAndFail() { void bitOrTest()
int d; {
short s; {
byte c; // Tests condition for different signs between min & max
static assert(!__traits(compiles, c = d & s)); // ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1
static assert(!__traits(compiles, c = d & 256)); ushort a, b;
// [these pass in 2.053.] 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() { void bitAndFail()
ushort s; {
ubyte c; {
c = (0xffff << (s&0)) ^ 0xff00; 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; int i;
ubyte b = ~(i | ~0xff); ubyte b = ~(i | ~0xff);
} }
void bitComplementFail() { void bitComplementFail()
{
ubyte b; ubyte b;
static assert(!__traits(compiles, b = ~(b | 1))); static assert(!__traits(compiles, b = ~(b | 1)));
// [this passes in 2.053.] // [this passes in 2.053.]
} }
void negation() { void negation()
{
int x; int x;
byte b = -(x & 0x7); byte b = -(x & 0x7);
} }
void negationFail() { void negationFail()
{
int x; int x;
byte b; byte b;
static assert(!__traits(compiles, b = -(x & 255))); static assert(!__traits(compiles, b = -(x & 255)));
...@@ -200,7 +346,8 @@ short bug1977_comment5(byte i) { ...@@ -200,7 +346,8 @@ short bug1977_comment5(byte i) {
return o; return o;
} }
void testDchar() { void testDchar()
{
dchar d; dchar d;
uint i; uint i;
/+ /+
...@@ -210,13 +357,15 @@ void testDchar() { ...@@ -210,13 +357,15 @@ void testDchar() {
d = i % 0x110000; d = i % 0x110000;
} }
void bug1977_comment11() { void bug1977_comment11()
{
uint a; uint a;
byte b = a & 1; byte b = a & 1;
// [this passes in 2.053.] // [this passes in 2.053.]
} }
void bug1977_comment20() { void bug1977_comment20()
{
long a; long a;
int b = a % 1000; int b = a % 1000;
} }
...@@ -329,3 +478,32 @@ void test13001(bool unknown) ...@@ -329,3 +478,32 @@ void test13001(bool unknown)
static assert(!__traits(compiles, b = i + 254)); 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