From patchwork Sun Dec 9 15:06:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1009978 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-491966-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gdcproject.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="QSmEPSZP"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43CV1d3N8yz9s3l for ; Mon, 10 Dec 2018 02:07:30 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=vrsEDQOQzyd2N38A/JLyet6prY3OUC9HuDkWGTCo/ghd+D FrKNBL4HLNvWsXueLQaZdtFI+XaZo66MFMTsg5GzDcFEJe+gJ3m4A8x/WmyiAgJM Yhugbwjkfu7vmqRcTDvlEKqIIL7t1u5nfVHCEm3Q4RHXtRjTljjkAflRMwnDo= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=jm5Lba5e9T15/Xrh2QNOs4bG1do=; b=QSmEPSZPKeYUcKw3rW4F Lk58q8CH56bedMPO8NlzxnWp4zfDpKMzr41eJuTSpnqT322fbfCxzkmgdBRiwgV6 bi3Tt4BNU1nY50k7VD2mo/e3jODHbd2HloGcnMoPVk191tAK/yIdRT/61kAzKagi /cd77AMDrNumrYLW5DR+E+I= Received: (qmail 49370 invoked by alias); 9 Dec 2018 15:07:22 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 49346 invoked by uid 89); 9 Dec 2018 15:07:20 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.0 required=5.0 tests=BAYES_20, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS, TIME_LIMIT_EXCEEDED autolearn=unavailable version=3.3.2 spammy=tabs, ab, 7416, cd X-HELO: mail-qt1-f172.google.com Received: from mail-qt1-f172.google.com (HELO mail-qt1-f172.google.com) (209.85.160.172) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 09 Dec 2018 15:07:09 +0000 Received: by mail-qt1-f172.google.com with SMTP id p17so9659036qtl.5 for ; Sun, 09 Dec 2018 07:07:08 -0800 (PST) MIME-Version: 1.0 From: Iain Buclaw Date: Sun, 9 Dec 2018 16:06:55 +0100 Message-ID: Subject: [PATCH, d] Committd merge with upstream dmd To: gcc-patches X-IsSubscribed: yes 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 --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)); +}