diff mbox series

[d] Committd merge with upstream dmd

Message ID CABOHX+c6omQtjOSbyGdmFyXS5Z211T6QH8OTO_enHnzoY3k3Gw@mail.gmail.com
State New
Headers show
Series [d] Committd merge with upstream dmd | expand

Commit Message

Iain Buclaw Dec. 9, 2018, 3:06 p.m. UTC
Hi,

This patch merges the D front-end implementation with 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',
fixing https://gcc.gnu.org/PR88366.

Bootstrapped and tested on x86_64-linux-gnu --with-build-config=bootstrap-ubsan

Committed to trunk as r266925.
diff mbox series

Patch

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 223ffbdc358..a1a1fa0efd1 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-5220ad51eebe06754e6881d9bd5aab89dba2b065
+e2fe2687b817a201528abaa3aa882333e04db01b
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/constfold.c b/gcc/d/dmd/constfold.c
index 4b5dceba62e..c3df013d802 100644
--- a/gcc/d/dmd/constfold.c
+++ b/gcc/d/dmd/constfold.c
@@ -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();
diff --git a/gcc/d/dmd/dcast.c b/gcc/d/dmd/dcast.c
index 39471665e4a..9606c994482 100644
--- a/gcc/d/dmd/dcast.c
+++ b/gcc/d/dmd/dcast.c
@@ -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);
         }
     };
 
diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c
index b511b79c7e0..d0678a06c74 100644
--- a/gcc/d/dmd/dsymbol.c
+++ b/gcc/d/dmd/dsymbol.c
@@ -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)
diff --git a/gcc/d/dmd/intrange.c b/gcc/d/dmd/intrange.c
index 966b9a2986e..dd794d98a8c 100644
--- a/gcc/d/dmd/intrange.c
+++ b/gcc/d/dmd/intrange.c
@@ -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
 {
diff --git a/gcc/d/dmd/intrange.h b/gcc/d/dmd/intrange.h
index 69111586e8d..aee773a14a0 100644
--- a/gcc/d/dmd/intrange.h
+++ b/gcc/d/dmd/intrange.h
@@ -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;
 };
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
index dedaf7dc83e..b35b7af3201 100644
--- a/gcc/d/dmd/mtype.c
+++ b/gcc/d/dmd/mtype.c
@@ -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;
 }
 
diff --git a/gcc/testsuite/gdc.test/compilable/testVRP.d b/gcc/testsuite/gdc.test/compilable/testVRP.d
index 96a499fa4ac..954b5019b83 100644
--- a/gcc/testsuite/gdc.test/compilable/testVRP.d
+++ b/gcc/testsuite/gdc.test/compilable/testVRP.d
@@ -1,55 +1,80 @@ 
 // 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));
+}