Home | History | Annotate | Line # | Download | only in dmd
intrange.d revision 1.1.1.1
      1  1.1  mrg /**
      2  1.1  mrg  * Implement $(LINK2 https://digitalmars.com/articles/b62.html, Value Range Propagation).
      3  1.1  mrg  *
      4  1.1  mrg  * Copyright:   Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
      5  1.1  mrg  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
      6  1.1  mrg  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
      7  1.1  mrg  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d, _intrange.d)
      8  1.1  mrg  * Documentation:  https://dlang.org/phobos/dmd_intrange.html
      9  1.1  mrg  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/intrange.d
     10  1.1  mrg  */
     11  1.1  mrg 
     12  1.1  mrg module dmd.intrange;
     13  1.1  mrg 
     14  1.1  mrg import core.stdc.stdio;
     15  1.1  mrg 
     16  1.1  mrg import dmd.astenums;
     17  1.1  mrg import dmd.mtype;
     18  1.1  mrg import dmd.expression;
     19  1.1  mrg import dmd.globals;
     20  1.1  mrg 
     21  1.1  mrg private uinteger_t copySign(uinteger_t x, bool sign)
     22  1.1  mrg {
     23  1.1  mrg     // return sign ? -x : x;
     24  1.1  mrg     return (x - cast(uinteger_t)sign) ^ -cast(uinteger_t)sign;
     25  1.1  mrg }
     26  1.1  mrg 
     27  1.1  mrg struct SignExtendedNumber
     28  1.1  mrg {
     29  1.1  mrg     uinteger_t value;
     30  1.1  mrg     bool negative;
     31  1.1  mrg 
     32  1.1  mrg     static SignExtendedNumber fromInteger(uinteger_t value_)
     33  1.1  mrg     {
     34  1.1  mrg         return SignExtendedNumber(value_, value_ >> 63);
     35  1.1  mrg     }
     36  1.1  mrg 
     37  1.1  mrg     static SignExtendedNumber extreme(bool minimum)
     38  1.1  mrg     {
     39  1.1  mrg         return SignExtendedNumber(minimum - 1, minimum);
     40  1.1  mrg     }
     41  1.1  mrg 
     42  1.1  mrg     static SignExtendedNumber max()
     43  1.1  mrg     {
     44  1.1  mrg         return SignExtendedNumber(ulong.max, false);
     45  1.1  mrg     }
     46  1.1  mrg 
     47  1.1  mrg     static SignExtendedNumber min()
     48  1.1  mrg     {
     49  1.1  mrg         return SignExtendedNumber(0, true);
     50  1.1  mrg     }
     51  1.1  mrg 
     52  1.1  mrg     bool isMinimum() const
     53  1.1  mrg     {
     54  1.1  mrg         return negative && value == 0;
     55  1.1  mrg     }
     56  1.1  mrg 
     57  1.1  mrg     bool opEquals(const ref SignExtendedNumber a) const
     58  1.1  mrg     {
     59  1.1  mrg         return value == a.value && negative == a.negative;
     60  1.1  mrg     }
     61  1.1  mrg 
     62  1.1  mrg     int opCmp(const ref SignExtendedNumber a) const
     63  1.1  mrg     {
     64  1.1  mrg         if (negative != a.negative)
     65  1.1  mrg         {
     66  1.1  mrg             if (negative)
     67  1.1  mrg                 return -1;
     68  1.1  mrg             else
     69  1.1  mrg                 return 1;
     70  1.1  mrg         }
     71  1.1  mrg         if (value < a.value)
     72  1.1  mrg             return -1;
     73  1.1  mrg         else if (value > a.value)
     74  1.1  mrg             return 1;
     75  1.1  mrg         else
     76  1.1  mrg             return 0;
     77  1.1  mrg     }
     78  1.1  mrg 
     79  1.1  mrg     SignExtendedNumber opUnary(string op : "++")()
     80  1.1  mrg     {
     81  1.1  mrg         if (value != ulong.max)
     82  1.1  mrg             ++value;
     83  1.1  mrg         else if (negative)
     84  1.1  mrg         {
     85  1.1  mrg             value = 0;
     86  1.1  mrg             negative = false;
     87  1.1  mrg         }
     88  1.1  mrg         return this;
     89  1.1  mrg     }
     90  1.1  mrg 
     91  1.1  mrg     SignExtendedNumber opUnary(string op : "~")() const
     92  1.1  mrg     {
     93  1.1  mrg         if (~value == 0)
     94  1.1  mrg             return SignExtendedNumber(~value);
     95  1.1  mrg         else
     96  1.1  mrg             return SignExtendedNumber(~value, !negative);
     97  1.1  mrg     }
     98  1.1  mrg 
     99  1.1  mrg     SignExtendedNumber opUnary(string op : "-")() const
    100  1.1  mrg     {
    101  1.1  mrg         if (value == 0)
    102  1.1  mrg             return SignExtendedNumber(-cast(ulong)negative);
    103  1.1  mrg         else
    104  1.1  mrg             return SignExtendedNumber(-value, !negative);
    105  1.1  mrg     }
    106  1.1  mrg 
    107  1.1  mrg     SignExtendedNumber opBinary(string op : "&")(SignExtendedNumber rhs) const
    108  1.1  mrg     {
    109  1.1  mrg         return SignExtendedNumber(value & rhs.value);
    110  1.1  mrg     }
    111  1.1  mrg 
    112  1.1  mrg     SignExtendedNumber opBinary(string op : "|")(SignExtendedNumber rhs)
    113  1.1  mrg     {
    114  1.1  mrg         return SignExtendedNumber(value | rhs.value);
    115  1.1  mrg     }
    116  1.1  mrg 
    117  1.1  mrg     SignExtendedNumber opBinary(string op : "^")(SignExtendedNumber rhs)
    118  1.1  mrg     {
    119  1.1  mrg         return SignExtendedNumber(value ^ rhs.value);
    120  1.1  mrg     }
    121  1.1  mrg 
    122  1.1  mrg     SignExtendedNumber opBinary(string op : "+")(SignExtendedNumber rhs)
    123  1.1  mrg     {
    124  1.1  mrg         uinteger_t sum = value + rhs.value;
    125  1.1  mrg         bool carry = sum < value && sum < rhs.value;
    126  1.1  mrg         if (negative != rhs.negative)
    127  1.1  mrg             return SignExtendedNumber(sum, !carry);
    128  1.1  mrg         else if (negative)
    129  1.1  mrg             return SignExtendedNumber(carry ? sum : 0, true);
    130  1.1  mrg         else
    131  1.1  mrg             return SignExtendedNumber(carry ? ulong.max : sum, false);
    132  1.1  mrg     }
    133  1.1  mrg 
    134  1.1  mrg 
    135  1.1  mrg     SignExtendedNumber opBinary(string op : "-")(SignExtendedNumber rhs)
    136  1.1  mrg     {
    137  1.1  mrg         if (rhs.isMinimum())
    138  1.1  mrg             return negative ? SignExtendedNumber(value, false) : max();
    139  1.1  mrg         else
    140  1.1  mrg             return this + (-rhs);
    141  1.1  mrg     }
    142  1.1  mrg 
    143  1.1  mrg     SignExtendedNumber opBinary(string op : "*")(SignExtendedNumber rhs)
    144  1.1  mrg     {
    145  1.1  mrg         // perform *saturated* multiplication, otherwise we may get bogus ranges
    146  1.1  mrg         //  like 0x10 * 0x10 == 0x100 == 0.
    147  1.1  mrg 
    148  1.1  mrg         /* Special handling for zeros:
    149  1.1  mrg             INT65_MIN * 0 = 0
    150  1.1  mrg             INT65_MIN * + = INT65_MIN
    151  1.1  mrg             INT65_MIN * - = INT65_MAX
    152  1.1  mrg             0 * anything = 0
    153  1.1  mrg         */
    154  1.1  mrg         if (value == 0)
    155  1.1  mrg         {
    156  1.1  mrg             if (!negative)
    157  1.1  mrg                 return this;
    158  1.1  mrg             else if (rhs.negative)
    159  1.1  mrg                 return max();
    160  1.1  mrg             else
    161  1.1  mrg                 return rhs.value == 0 ? rhs : this;
    162  1.1  mrg         }
    163  1.1  mrg         else if (rhs.value == 0)
    164  1.1  mrg             return rhs * this; // don't duplicate the symmetric case.
    165  1.1  mrg 
    166  1.1  mrg         SignExtendedNumber rv;
    167  1.1  mrg         // these are != 0 now surely.
    168  1.1  mrg         uinteger_t tAbs = copySign(value, negative);
    169  1.1  mrg         uinteger_t aAbs = copySign(rhs.value, rhs.negative);
    170  1.1  mrg         rv.negative = negative != rhs.negative;
    171  1.1  mrg         if (ulong.max / tAbs < aAbs)
    172  1.1  mrg             rv.value = rv.negative - 1;
    173  1.1  mrg         else
    174  1.1  mrg             rv.value = copySign(tAbs * aAbs, rv.negative);
    175  1.1  mrg         return rv;
    176  1.1  mrg     }
    177  1.1  mrg 
    178  1.1  mrg     SignExtendedNumber opBinary(string op : "/")(SignExtendedNumber rhs)
    179  1.1  mrg     {
    180  1.1  mrg         /* special handling for zeros:
    181  1.1  mrg             INT65_MIN / INT65_MIN = 1
    182  1.1  mrg             anything / INT65_MIN = 0
    183  1.1  mrg             + / 0 = INT65_MAX  (eh?)
    184  1.1  mrg             - / 0 = INT65_MIN  (eh?)
    185  1.1  mrg         */
    186  1.1  mrg         if (rhs.value == 0)
    187  1.1  mrg         {
    188  1.1  mrg             if (rhs.negative)
    189  1.1  mrg                 return SignExtendedNumber(value == 0 && negative);
    190  1.1  mrg             else
    191  1.1  mrg                 return extreme(negative);
    192  1.1  mrg         }
    193  1.1  mrg 
    194  1.1  mrg         uinteger_t aAbs = copySign(rhs.value, rhs.negative);
    195  1.1  mrg         uinteger_t rvVal;
    196  1.1  mrg 
    197  1.1  mrg         if (!isMinimum())
    198  1.1  mrg             rvVal = copySign(value, negative) / aAbs;
    199  1.1  mrg         // Special handling for INT65_MIN
    200  1.1  mrg         //  if the denominator is not a power of 2, it is same as ulong.max / x.
    201  1.1  mrg         else if (aAbs & (aAbs - 1))
    202  1.1  mrg             rvVal = ulong.max / aAbs;
    203  1.1  mrg         // otherwise, it's the same as reversing the bits of x.
    204  1.1  mrg         else
    205  1.1  mrg         {
    206  1.1  mrg             if (aAbs == 1)
    207  1.1  mrg                 return extreme(!rhs.negative);
    208  1.1  mrg             rvVal = 1UL << 63;
    209  1.1  mrg             aAbs >>= 1;
    210  1.1  mrg             if (aAbs & 0xAAAAAAAAAAAAAAAAUL) rvVal >>= 1;
    211  1.1  mrg             if (aAbs & 0xCCCCCCCCCCCCCCCCUL) rvVal >>= 2;
    212  1.1  mrg             if (aAbs & 0xF0F0F0F0F0F0F0F0UL) rvVal >>= 4;
    213  1.1  mrg             if (aAbs & 0xFF00FF00FF00FF00UL) rvVal >>= 8;
    214  1.1  mrg             if (aAbs & 0xFFFF0000FFFF0000UL) rvVal >>= 16;
    215  1.1  mrg             if (aAbs & 0xFFFFFFFF00000000UL) rvVal >>= 32;
    216  1.1  mrg         }
    217  1.1  mrg         bool rvNeg = negative != rhs.negative;
    218  1.1  mrg         rvVal = copySign(rvVal, rvNeg);
    219  1.1  mrg 
    220  1.1  mrg         return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
    221  1.1  mrg     }
    222  1.1  mrg 
    223  1.1  mrg     SignExtendedNumber opBinary(string op : "%")(SignExtendedNumber rhs)
    224  1.1  mrg     {
    225  1.1  mrg         if (rhs.value == 0)
    226  1.1  mrg             return !rhs.negative ? rhs : isMinimum() ? SignExtendedNumber(0) : this;
    227  1.1  mrg 
    228  1.1  mrg         uinteger_t aAbs = copySign(rhs.value, rhs.negative);
    229  1.1  mrg         uinteger_t rvVal;
    230  1.1  mrg 
    231  1.1  mrg         // a % b == sgn(a) * abs(a) % abs(b).
    232  1.1  mrg         if (!isMinimum())
    233  1.1  mrg             rvVal = copySign(value, negative) % aAbs;
    234  1.1  mrg         // Special handling for INT65_MIN
    235  1.1  mrg         //  if the denominator is not a power of 2, it is same as ulong.max % x + 1.
    236  1.1  mrg         else if (aAbs & (aAbs - 1))
    237  1.1  mrg             rvVal = ulong.max % aAbs + 1;
    238  1.1  mrg         //  otherwise, the modulus is trivially zero.
    239  1.1  mrg         else
    240  1.1  mrg             rvVal = 0;
    241  1.1  mrg 
    242  1.1  mrg         rvVal = copySign(rvVal, negative);
    243  1.1  mrg         return SignExtendedNumber(rvVal, rvVal != 0 && negative);
    244  1.1  mrg     }
    245  1.1  mrg 
    246  1.1  mrg     SignExtendedNumber opBinary(string op : "<<")(SignExtendedNumber rhs)
    247  1.1  mrg     {
    248  1.1  mrg         // assume left-shift the shift-amount is always unsigned. Thus negative
    249  1.1  mrg         //  shifts will give huge result.
    250  1.1  mrg         if (value == 0)
    251  1.1  mrg             return this;
    252  1.1  mrg         else if (rhs.negative)
    253  1.1  mrg             return extreme(negative);
    254  1.1  mrg 
    255  1.1  mrg         uinteger_t v = copySign(value, negative);
    256  1.1  mrg 
    257  1.1  mrg         // compute base-2 log of 'v' to determine the maximum allowed bits to shift.
    258  1.1  mrg         // Ref: https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
    259  1.1  mrg 
    260  1.1  mrg         // Why is this a size_t? Looks like a bug.
    261  1.1  mrg         size_t r, s;
    262  1.1  mrg 
    263  1.1  mrg         r = (v > 0xFFFFFFFFUL) << 5; v >>= r;
    264  1.1  mrg         s = (v > 0xFFFFUL    ) << 4; v >>= s; r |= s;
    265  1.1  mrg         s = (v > 0xFFUL      ) << 3; v >>= s; r |= s;
    266  1.1  mrg         s = (v > 0xFUL       ) << 2; v >>= s; r |= s;
    267  1.1  mrg         s = (v > 0x3UL       ) << 1; v >>= s; r |= s;
    268  1.1  mrg                                                r |= (v >> 1);
    269  1.1  mrg 
    270  1.1  mrg         uinteger_t allowableShift = 63 - r;
    271  1.1  mrg         if (rhs.value > allowableShift)
    272  1.1  mrg             return extreme(negative);
    273  1.1  mrg         else
    274  1.1  mrg             return SignExtendedNumber(value << rhs.value, negative);
    275  1.1  mrg     }
    276  1.1  mrg 
    277  1.1  mrg     SignExtendedNumber opBinary(string op : ">>")(SignExtendedNumber rhs)
    278  1.1  mrg     {
    279  1.1  mrg         if (rhs.negative || rhs.value > 63)
    280  1.1  mrg             return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
    281  1.1  mrg         else if (isMinimum())
    282  1.1  mrg             return rhs.value == 0 ? this : SignExtendedNumber(-1UL << (64 - rhs.value), true);
    283  1.1  mrg 
    284  1.1  mrg         uinteger_t x = value ^ -cast(int)negative;
    285  1.1  mrg         x >>= rhs.value;
    286  1.1  mrg         return SignExtendedNumber(x ^ -cast(int)negative, negative);
    287  1.1  mrg     }
    288  1.1  mrg 
    289  1.1  mrg     SignExtendedNumber opBinary(string op : "^^")(SignExtendedNumber rhs)
    290  1.1  mrg     {
    291  1.1  mrg         // Not yet implemented
    292  1.1  mrg         assert(0);
    293  1.1  mrg     }
    294  1.1  mrg }
    295  1.1  mrg 
    296  1.1  mrg struct IntRange
    297  1.1  mrg {
    298  1.1  mrg     SignExtendedNumber imin, imax;
    299  1.1  mrg 
    300  1.1  mrg     this(IntRange another)
    301  1.1  mrg     {
    302  1.1  mrg         imin = another.imin;
    303  1.1  mrg         imax = another.imax;
    304  1.1  mrg     }
    305  1.1  mrg 
    306  1.1  mrg     this(SignExtendedNumber a)
    307  1.1  mrg     {
    308  1.1  mrg         imin = a;
    309  1.1  mrg         imax = a;
    310  1.1  mrg     }
    311  1.1  mrg 
    312  1.1  mrg     this(SignExtendedNumber lower, SignExtendedNumber upper)
    313  1.1  mrg     {
    314  1.1  mrg         imin = lower;
    315  1.1  mrg         imax = upper;
    316  1.1  mrg     }
    317  1.1  mrg 
    318  1.1  mrg     static IntRange fromType(Type type)
    319  1.1  mrg     {
    320  1.1  mrg         return fromType(type, type.isunsigned());
    321  1.1  mrg     }
    322  1.1  mrg 
    323  1.1  mrg     static IntRange fromType(Type type, bool isUnsigned)
    324  1.1  mrg     {
    325  1.1  mrg         if (!type.isintegral() || type.toBasetype().ty == Tvector)
    326  1.1  mrg             return widest();
    327  1.1  mrg 
    328  1.1  mrg         uinteger_t mask = type.sizemask();
    329  1.1  mrg         auto lower = SignExtendedNumber(0);
    330  1.1  mrg         auto upper = SignExtendedNumber(mask);
    331  1.1  mrg         if (type.toBasetype().ty == Tdchar)
    332  1.1  mrg             upper.value = 0x10FFFFUL;
    333  1.1  mrg         else if (!isUnsigned)
    334  1.1  mrg         {
    335  1.1  mrg             lower.value = ~(mask >> 1);
    336  1.1  mrg             lower.negative = true;
    337  1.1  mrg             upper.value = (mask >> 1);
    338  1.1  mrg         }
    339  1.1  mrg         return IntRange(lower, upper);
    340  1.1  mrg     }
    341  1.1  mrg 
    342  1.1  mrg     static IntRange fromNumbers2(SignExtendedNumber* numbers)
    343  1.1  mrg     {
    344  1.1  mrg         if (numbers[0] < numbers[1])
    345  1.1  mrg             return IntRange(numbers[0], numbers[1]);
    346  1.1  mrg         else
    347  1.1  mrg             return IntRange(numbers[1], numbers[0]);
    348  1.1  mrg     }
    349  1.1  mrg 
    350  1.1  mrg     static IntRange fromNumbers4(SignExtendedNumber* numbers)
    351  1.1  mrg     {
    352  1.1  mrg         IntRange ab = fromNumbers2(numbers);
    353  1.1  mrg         IntRange cd = fromNumbers2(numbers + 2);
    354  1.1  mrg         if (cd.imin < ab.imin)
    355  1.1  mrg             ab.imin = cd.imin;
    356  1.1  mrg         if (cd.imax > ab.imax)
    357  1.1  mrg             ab.imax = cd.imax;
    358  1.1  mrg         return ab;
    359  1.1  mrg     }
    360  1.1  mrg 
    361  1.1  mrg     static IntRange widest()
    362  1.1  mrg     {
    363  1.1  mrg         return IntRange(SignExtendedNumber.min(), SignExtendedNumber.max());
    364  1.1  mrg     }
    365  1.1  mrg 
    366  1.1  mrg     IntRange castSigned(uinteger_t mask)
    367  1.1  mrg     {
    368  1.1  mrg         // .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 ....
    369  1.1  mrg         //
    370  1.1  mrg         // regular signed type. We use a technique similar to the unsigned version,
    371  1.1  mrg         //  but the chunk has to be offset by 1/2 of the range.
    372  1.1  mrg         uinteger_t halfChunkMask = mask >> 1;
    373  1.1  mrg         uinteger_t minHalfChunk = imin.value & ~halfChunkMask;
    374  1.1  mrg         uinteger_t maxHalfChunk = imax.value & ~halfChunkMask;
    375  1.1  mrg         int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max
    376  1.1  mrg         int maxHalfChunkNegativity = imax.negative;
    377  1.1  mrg         if (minHalfChunk & mask)
    378  1.1  mrg         {
    379  1.1  mrg             minHalfChunk += halfChunkMask + 1;
    380  1.1  mrg             if (minHalfChunk == 0)
    381  1.1  mrg                 --minHalfChunkNegativity;
    382  1.1  mrg         }
    383  1.1  mrg         if (maxHalfChunk & mask)
    384  1.1  mrg         {
    385  1.1  mrg             maxHalfChunk += halfChunkMask + 1;
    386  1.1  mrg             if (maxHalfChunk == 0)
    387  1.1  mrg                 --maxHalfChunkNegativity;
    388  1.1  mrg         }
    389  1.1  mrg         if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity)
    390  1.1  mrg         {
    391  1.1  mrg             imin.value &= mask;
    392  1.1  mrg             imax.value &= mask;
    393  1.1  mrg             // sign extend if necessary.
    394  1.1  mrg             imin.negative = (imin.value & ~halfChunkMask) != 0;
    395  1.1  mrg             imax.negative = (imax.value & ~halfChunkMask) != 0;
    396  1.1  mrg             halfChunkMask += 1;
    397  1.1  mrg             imin.value = (imin.value ^ halfChunkMask) - halfChunkMask;
    398  1.1  mrg             imax.value = (imax.value ^ halfChunkMask) - halfChunkMask;
    399  1.1  mrg         }
    400  1.1  mrg         else
    401  1.1  mrg         {
    402  1.1  mrg             imin = SignExtendedNumber(~halfChunkMask, true);
    403  1.1  mrg             imax = SignExtendedNumber(halfChunkMask, false);
    404  1.1  mrg         }
    405  1.1  mrg         return this;
    406  1.1  mrg     }
    407  1.1  mrg 
    408  1.1  mrg     IntRange castUnsigned(uinteger_t mask)
    409  1.1  mrg     {
    410  1.1  mrg         // .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 ....
    411  1.1  mrg         //
    412  1.1  mrg         // regular unsigned type. We just need to see if ir steps across the
    413  1.1  mrg         //  boundary of validRange. If yes, ir will represent the whole validRange,
    414  1.1  mrg         //  otherwise, we just take the modulus.
    415  1.1  mrg         // e.g. [0x105, 0x107] & 0xff == [5, 7]
    416  1.1  mrg         //      [0x105, 0x207] & 0xff == [0, 0xff]
    417  1.1  mrg         uinteger_t minChunk = imin.value & ~mask;
    418  1.1  mrg         uinteger_t maxChunk = imax.value & ~mask;
    419  1.1  mrg         if (minChunk == maxChunk && imin.negative == imax.negative)
    420  1.1  mrg         {
    421  1.1  mrg             imin.value &= mask;
    422  1.1  mrg             imax.value &= mask;
    423  1.1  mrg         }
    424  1.1  mrg         else
    425  1.1  mrg         {
    426  1.1  mrg             imin.value = 0;
    427  1.1  mrg             imax.value = mask;
    428  1.1  mrg         }
    429  1.1  mrg         imin.negative = imax.negative = false;
    430  1.1  mrg         return this;
    431  1.1  mrg     }
    432  1.1  mrg 
    433  1.1  mrg     IntRange castDchar()
    434  1.1  mrg     {
    435  1.1  mrg         // special case for dchar. Casting to dchar means "I'll ignore all
    436  1.1  mrg         //  invalid characters."
    437  1.1  mrg         castUnsigned(0xFFFFFFFFUL);
    438  1.1  mrg         if (imin.value > 0x10FFFFUL) // ??
    439  1.1  mrg             imin.value = 0x10FFFFUL; // ??
    440  1.1  mrg         if (imax.value > 0x10FFFFUL)
    441  1.1  mrg             imax.value = 0x10FFFFUL;
    442  1.1  mrg         return this;
    443  1.1  mrg     }
    444  1.1  mrg 
    445  1.1  mrg     IntRange _cast(Type type)
    446  1.1  mrg     {
    447  1.1  mrg         if (!type.isintegral() || type.toBasetype().ty == Tvector)
    448  1.1  mrg             return this;
    449  1.1  mrg         else if (!type.isunsigned())
    450  1.1  mrg             return castSigned(type.sizemask());
    451  1.1  mrg         else if (type.toBasetype().ty == Tdchar)
    452  1.1  mrg             return castDchar();
    453  1.1  mrg         else
    454  1.1  mrg             return castUnsigned(type.sizemask());
    455  1.1  mrg     }
    456  1.1  mrg 
    457  1.1  mrg     IntRange castUnsigned(Type type)
    458  1.1  mrg     {
    459  1.1  mrg         if (!type.isintegral() || type.toBasetype().ty == Tvector)
    460  1.1  mrg             return castUnsigned(ulong.max);
    461  1.1  mrg         else if (type.toBasetype().ty == Tdchar)
    462  1.1  mrg             return castDchar();
    463  1.1  mrg         else
    464  1.1  mrg             return castUnsigned(type.sizemask());
    465  1.1  mrg     }
    466  1.1  mrg 
    467  1.1  mrg     bool contains(IntRange a)
    468  1.1  mrg     {
    469  1.1  mrg         return imin <= a.imin && imax >= a.imax;
    470  1.1  mrg     }
    471  1.1  mrg 
    472  1.1  mrg     bool containsZero() const
    473  1.1  mrg     {
    474  1.1  mrg         return (imin.negative && !imax.negative)
    475  1.1  mrg             || (!imin.negative && imin.value == 0);
    476  1.1  mrg     }
    477  1.1  mrg 
    478  1.1  mrg     IntRange absNeg() const
    479  1.1  mrg     {
    480  1.1  mrg         if (imax.negative)
    481  1.1  mrg             return this;
    482  1.1  mrg         else if (!imin.negative)
    483  1.1  mrg             return IntRange(-imax, -imin);
    484  1.1  mrg         else
    485  1.1  mrg         {
    486  1.1  mrg             SignExtendedNumber imaxAbsNeg = -imax;
    487  1.1  mrg             return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
    488  1.1  mrg                             SignExtendedNumber(0));
    489  1.1  mrg         }
    490  1.1  mrg     }
    491  1.1  mrg 
    492  1.1  mrg     IntRange unionWith(const ref IntRange other) const
    493  1.1  mrg     {
    494  1.1  mrg         return IntRange(imin < other.imin ? imin : other.imin,
    495  1.1  mrg                         imax > other.imax ? imax : other.imax);
    496  1.1  mrg     }
    497  1.1  mrg 
    498  1.1  mrg     void unionOrAssign(IntRange other, ref bool union_)
    499  1.1  mrg     {
    500  1.1  mrg         if (!union_ || imin > other.imin)
    501  1.1  mrg             imin = other.imin;
    502  1.1  mrg         if (!union_ || imax < other.imax)
    503  1.1  mrg             imax = other.imax;
    504  1.1  mrg         union_ = true;
    505  1.1  mrg     }
    506  1.1  mrg 
    507  1.1  mrg     ref const(IntRange) dump(const(char)* funcName, Expression e) const return
    508  1.1  mrg     {
    509  1.1  mrg         printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
    510  1.1  mrg                imin.negative?'-':'+', cast(ulong)imin.value,
    511  1.1  mrg                imax.negative?'-':'+', cast(ulong)imax.value,
    512  1.1  mrg                funcName, e.toChars());
    513  1.1  mrg         return this;
    514  1.1  mrg     }
    515  1.1  mrg 
    516  1.1  mrg     void splitBySign(ref IntRange negRange, ref bool hasNegRange, ref IntRange nonNegRange, ref bool hasNonNegRange) const
    517  1.1  mrg     {
    518  1.1  mrg         hasNegRange = imin.negative;
    519  1.1  mrg         if (hasNegRange)
    520  1.1  mrg         {
    521  1.1  mrg             negRange.imin = imin;
    522  1.1  mrg             negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true);
    523  1.1  mrg         }
    524  1.1  mrg         hasNonNegRange = !imax.negative;
    525  1.1  mrg         if (hasNonNegRange)
    526  1.1  mrg         {
    527  1.1  mrg             nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin;
    528  1.1  mrg             nonNegRange.imax = imax;
    529  1.1  mrg         }
    530  1.1  mrg     }
    531  1.1  mrg 
    532  1.1  mrg     IntRange opUnary(string op:"~")() const
    533  1.1  mrg     {
    534  1.1  mrg         return IntRange(~imax, ~imin);
    535  1.1  mrg     }
    536  1.1  mrg 
    537  1.1  mrg     IntRange opUnary(string op : "-")()
    538  1.1  mrg     {
    539  1.1  mrg         return IntRange(-imax, -imin);
    540  1.1  mrg     }
    541  1.1  mrg 
    542  1.1  mrg     // Credits to Timon Gehr for the algorithms for &, |
    543  1.1  mrg     // https://github.com/tgehr/d-compiler/blob/master/vrange.d
    544  1.1  mrg     IntRange opBinary(string op : "&")(IntRange rhs) const
    545  1.1  mrg     {
    546  1.1  mrg         // unsigned or identical sign bits
    547  1.1  mrg         if ((imin.negative ^ imax.negative) != 1 && (rhs.imin.negative ^ rhs.imax.negative) != 1)
    548  1.1  mrg         {
    549  1.1  mrg             return IntRange(minAnd(this, rhs), maxAnd(this, rhs));
    550  1.1  mrg         }
    551  1.1  mrg 
    552  1.1  mrg         IntRange l = IntRange(this);
    553  1.1  mrg         IntRange r = IntRange(rhs);
    554  1.1  mrg 
    555  1.1  mrg         // both intervals span [-1,0]
    556  1.1  mrg         if ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1)
    557  1.1  mrg         {
    558  1.1  mrg             // cannot be larger than either l.max or r.max, set the other one to -1
    559  1.1  mrg             SignExtendedNumber max = l.imax.value > r.imax.value ? l.imax : r.imax;
    560  1.1  mrg 
    561  1.1  mrg             // only negative numbers for minimum
    562  1.1  mrg             l.imax.value = -1;
    563  1.1  mrg             l.imax.negative = true;
    564  1.1  mrg             r.imax.value = -1;
    565  1.1  mrg             r.imax.negative = true;
    566  1.1  mrg 
    567  1.1  mrg             return IntRange(minAnd(l, r), max);
    568  1.1  mrg         }
    569  1.1  mrg         else
    570  1.1  mrg         {
    571  1.1  mrg             // only one interval spans [-1,0]
    572  1.1  mrg             if ((l.imin.negative ^ l.imax.negative) == 1)
    573  1.1  mrg             {
    574  1.1  mrg                 swap(l, r); // r spans [-1,0]
    575  1.1  mrg             }
    576  1.1  mrg 
    577  1.1  mrg             auto minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
    578  1.1  mrg             auto minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
    579  1.1  mrg             auto maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
    580  1.1  mrg             auto maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
    581  1.1  mrg 
    582  1.1  mrg             auto min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
    583  1.1  mrg             auto max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
    584  1.1  mrg 
    585  1.1  mrg             auto range = IntRange(min, max);
    586  1.1  mrg             return range;
    587  1.1  mrg         }
    588  1.1  mrg     }
    589  1.1  mrg 
    590  1.1  mrg     // Credits to Timon Gehr for the algorithms for &, |
    591  1.1  mrg     // https://github.com/tgehr/d-compiler/blob/master/vrange.d
    592  1.1  mrg     IntRange opBinary(string op : "|")(IntRange rhs) const
    593  1.1  mrg     {
    594  1.1  mrg         // unsigned or identical sign bits:
    595  1.1  mrg         if ((imin.negative ^ imax.negative) == 0 && (rhs.imin.negative ^ rhs.imax.negative) == 0)
    596  1.1  mrg         {
    597  1.1  mrg             return IntRange(minOr(this, rhs), maxOr(this, rhs));
    598  1.1  mrg         }
    599  1.1  mrg 
    600  1.1  mrg         IntRange l = IntRange(this);
    601  1.1  mrg         IntRange r = IntRange(rhs);
    602  1.1  mrg 
    603  1.1  mrg         // both intervals span [-1,0]
    604  1.1  mrg         if ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1)
    605  1.1  mrg         {
    606  1.1  mrg             // cannot be smaller than either l.min or r.min, set the other one to 0
    607  1.1  mrg             SignExtendedNumber min = l.imin.value < r.imin.value ? l.imin : r.imin;
    608  1.1  mrg 
    609  1.1  mrg             // only negative numbers for minimum
    610  1.1  mrg             l.imin.value = 0;
    611  1.1  mrg             l.imin.negative = false;
    612  1.1  mrg             r.imin.value = 0;
    613  1.1  mrg             r.imin.negative = false;
    614  1.1  mrg 
    615  1.1  mrg             return IntRange(min, maxOr(l, r));
    616  1.1  mrg         }
    617  1.1  mrg         else
    618  1.1  mrg         {
    619  1.1  mrg             // only one interval spans [-1,0]
    620  1.1  mrg             if ((imin.negative ^ imax.negative) == 1)
    621  1.1  mrg             {
    622  1.1  mrg                 swap(l, r); // r spans [-1,0]
    623  1.1  mrg             }
    624  1.1  mrg 
    625  1.1  mrg             auto minOrNeg = minOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
    626  1.1  mrg             auto minOrPos = minOr(l, IntRange(SignExtendedNumber(0), r.imax));
    627  1.1  mrg             auto maxOrNeg = maxOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
    628  1.1  mrg             auto maxOrPos = maxOr(l, IntRange(SignExtendedNumber(0), r.imax));
    629  1.1  mrg 
    630  1.1  mrg             auto min = minOrNeg < minOrPos ? minOrNeg : minOrPos;
    631  1.1  mrg             auto max = maxOrNeg > maxOrPos ? maxOrNeg : maxOrPos;
    632  1.1  mrg 
    633  1.1  mrg             auto range = IntRange(min, max);
    634  1.1  mrg             return range;
    635  1.1  mrg         }
    636  1.1  mrg     }
    637  1.1  mrg 
    638  1.1  mrg     IntRange opBinary(string op : "^")(IntRange rhs) const
    639  1.1  mrg     {
    640  1.1  mrg         return this & ~rhs | ~this & rhs;
    641  1.1  mrg     }
    642  1.1  mrg 
    643  1.1  mrg     IntRange opBinary(string op : "+")(IntRange rhs)
    644  1.1  mrg     {
    645  1.1  mrg         return IntRange(imin + rhs.imin, imax + rhs.imax);
    646  1.1  mrg     }
    647  1.1  mrg 
    648  1.1  mrg     IntRange opBinary(string op : "-")(IntRange rhs)
    649  1.1  mrg     {
    650  1.1  mrg         return IntRange(imin - rhs.imax, imax - rhs.imin);
    651  1.1  mrg     }
    652  1.1  mrg 
    653  1.1  mrg     IntRange opBinary(string op : "*")(IntRange rhs)
    654  1.1  mrg     {
    655  1.1  mrg         // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
    656  1.1  mrg         SignExtendedNumber[4] bdy;
    657  1.1  mrg         bdy[0] = imin * rhs.imin;
    658  1.1  mrg         bdy[1] = imin * rhs.imax;
    659  1.1  mrg         bdy[2] = imax * rhs.imin;
    660  1.1  mrg         bdy[3] = imax * rhs.imax;
    661  1.1  mrg         return IntRange.fromNumbers4(bdy.ptr);
    662  1.1  mrg     }
    663  1.1  mrg 
    664  1.1  mrg     IntRange opBinary(string op : "/")(IntRange rhs)
    665  1.1  mrg     {
    666  1.1  mrg         // Handle divide by 0
    667  1.1  mrg         if (rhs.imax.value == 0 && rhs.imin.value == 0)
    668  1.1  mrg             return widest();
    669  1.1  mrg 
    670  1.1  mrg         // Don't treat the whole range as divide by 0 if only one end of a range is 0.
    671  1.1  mrg         // Issue 15289
    672  1.1  mrg         if (rhs.imax.value == 0)
    673  1.1  mrg         {
    674  1.1  mrg             rhs.imax.value--;
    675  1.1  mrg         }
    676  1.1  mrg         else if(rhs.imin.value == 0)
    677  1.1  mrg         {
    678  1.1  mrg             rhs.imin.value++;
    679  1.1  mrg         }
    680  1.1  mrg 
    681  1.1  mrg         if (!imin.negative && !imax.negative && !rhs.imin.negative && !rhs.imax.negative)
    682  1.1  mrg         {
    683  1.1  mrg             return IntRange(imin / rhs.imax, imax / rhs.imin);
    684  1.1  mrg         }
    685  1.1  mrg         else
    686  1.1  mrg         {
    687  1.1  mrg             // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
    688  1.1  mrg             SignExtendedNumber[4] bdy;
    689  1.1  mrg             bdy[0] = imin / rhs.imin;
    690  1.1  mrg             bdy[1] = imin / rhs.imax;
    691  1.1  mrg             bdy[2] = imax / rhs.imin;
    692  1.1  mrg             bdy[3] = imax / rhs.imax;
    693  1.1  mrg 
    694  1.1  mrg             return IntRange.fromNumbers4(bdy.ptr);
    695  1.1  mrg         }
    696  1.1  mrg     }
    697  1.1  mrg 
    698  1.1  mrg     IntRange opBinary(string op : "%")(IntRange rhs)
    699  1.1  mrg     {
    700  1.1  mrg         IntRange irNum = this;
    701  1.1  mrg         IntRange irDen = rhs.absNeg();
    702  1.1  mrg 
    703  1.1  mrg         /*
    704  1.1  mrg          due to the rules of D (C)'s % operator, we need to consider the cases
    705  1.1  mrg          separately in different range of signs.
    706  1.1  mrg 
    707  1.1  mrg              case 1. [500, 1700] % [7, 23] (numerator is always positive)
    708  1.1  mrg                  = [0, 22]
    709  1.1  mrg              case 2. [-500, 1700] % [7, 23] (numerator can be negative)
    710  1.1  mrg                  = [-22, 22]
    711  1.1  mrg              case 3. [-1700, -500] % [7, 23] (numerator is always negative)
    712  1.1  mrg                  = [-22, 0]
    713  1.1  mrg 
    714  1.1  mrg          the number 22 is the maximum absolute value in the denomator's range. We
    715  1.1  mrg          don't care about divide by zero.
    716  1.1  mrg          */
    717  1.1  mrg 
    718  1.1  mrg         irDen.imin = irDen.imin + SignExtendedNumber(1);
    719  1.1  mrg         irDen.imax = -irDen.imin;
    720  1.1  mrg 
    721  1.1  mrg         if (!irNum.imin.negative)
    722  1.1  mrg         {
    723  1.1  mrg             irNum.imin.value = 0;
    724  1.1  mrg         }
    725  1.1  mrg         else if (irNum.imin < irDen.imin)
    726  1.1  mrg         {
    727  1.1  mrg             irNum.imin = irDen.imin;
    728  1.1  mrg         }
    729  1.1  mrg 
    730  1.1  mrg         if (irNum.imax.negative)
    731  1.1  mrg         {
    732  1.1  mrg             irNum.imax.negative = false;
    733  1.1  mrg             irNum.imax.value = 0;
    734  1.1  mrg         }
    735  1.1  mrg         else if (irNum.imax > irDen.imax)
    736  1.1  mrg         {
    737  1.1  mrg             irNum.imax = irDen.imax;
    738  1.1  mrg         }
    739  1.1  mrg 
    740  1.1  mrg         return irNum;
    741  1.1  mrg     }
    742  1.1  mrg 
    743  1.1  mrg     IntRange opBinary(string op : "<<")(IntRange rhs)
    744  1.1  mrg     {
    745  1.1  mrg         if (rhs.imin.negative)
    746  1.1  mrg         {
    747  1.1  mrg             rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
    748  1.1  mrg         }
    749  1.1  mrg 
    750  1.1  mrg         SignExtendedNumber lower = imin << (imin.negative ? rhs.imax : rhs.imin);
    751  1.1  mrg         SignExtendedNumber upper = imax << (imax.negative ? rhs.imin : rhs.imax);
    752  1.1  mrg 
    753  1.1  mrg         return IntRange(lower, upper);
    754  1.1  mrg     }
    755  1.1  mrg 
    756  1.1  mrg     IntRange opBinary(string op : ">>")(IntRange rhs)
    757  1.1  mrg     {
    758  1.1  mrg         if (rhs.imin.negative)
    759  1.1  mrg         {
    760  1.1  mrg             rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
    761  1.1  mrg         }
    762  1.1  mrg 
    763  1.1  mrg         SignExtendedNumber lower = imin >> (imin.negative ? rhs.imin : rhs.imax);
    764  1.1  mrg         SignExtendedNumber upper = imax >> (imax.negative ? rhs.imax : rhs.imin);
    765  1.1  mrg 
    766  1.1  mrg         return IntRange(lower, upper);
    767  1.1  mrg     }
    768  1.1  mrg 
    769  1.1  mrg     IntRange opBinary(string op : ">>>")(IntRange rhs)
    770  1.1  mrg     {
    771  1.1  mrg         if (rhs.imin.negative)
    772  1.1  mrg         {
    773  1.1  mrg             rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
    774  1.1  mrg         }
    775  1.1  mrg 
    776  1.1  mrg         return IntRange(imin >> rhs.imax, imax >> rhs.imin);
    777  1.1  mrg     }
    778  1.1  mrg 
    779  1.1  mrg     IntRange opBinary(string op : "^^")(IntRange rhs)
    780  1.1  mrg     {
    781  1.1  mrg         // Not yet implemented
    782  1.1  mrg         assert(0);
    783  1.1  mrg     }
    784  1.1  mrg 
    785  1.1  mrg private:
    786  1.1  mrg     // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
    787  1.1  mrg     // https://github.com/tgehr/d-compiler/blob/master/vrange.d
    788  1.1  mrg     static SignExtendedNumber maxOr(const IntRange lhs, const IntRange rhs)
    789  1.1  mrg     {
    790  1.1  mrg         uinteger_t x = 0;
    791  1.1  mrg         auto sign = false;
    792  1.1  mrg         auto xor = lhs.imax.value ^ rhs.imax.value;
    793  1.1  mrg         auto and = lhs.imax.value & rhs.imax.value;
    794  1.1  mrg         auto lhsc = IntRange(lhs);
    795  1.1  mrg         auto rhsc = IntRange(rhs);
    796  1.1  mrg 
    797  1.1  mrg         // Sign bit not part of the .value so we need an extra iteration
    798  1.1  mrg         if (lhsc.imax.negative ^ rhsc.imax.negative)
    799  1.1  mrg         {
    800  1.1  mrg             sign = true;
    801  1.1  mrg             if (lhsc.imax.negative)
    802  1.1  mrg             {
    803  1.1  mrg                 if (!lhsc.imin.negative)
    804  1.1  mrg                 {
    805  1.1  mrg                     lhsc.imin.value = 0;
    806  1.1  mrg                 }
    807  1.1  mrg                 if (!rhsc.imin.negative)
    808  1.1  mrg                 {
    809  1.1  mrg                     rhsc.imin.value = 0;
    810  1.1  mrg                 }
    811  1.1  mrg             }
    812  1.1  mrg         }
    813  1.1  mrg         else if (lhsc.imin.negative & rhsc.imin.negative)
    814  1.1  mrg         {
    815  1.1  mrg             sign = true;
    816  1.1  mrg         }
    817  1.1  mrg         else if (lhsc.imax.negative & rhsc.imax.negative)
    818  1.1  mrg         {
    819  1.1  mrg             return SignExtendedNumber(-1, false);
    820  1.1  mrg         }
    821  1.1  mrg 
    822  1.1  mrg         for (uinteger_t d = 1LU << (8 * uinteger_t.sizeof - 1); d; d >>= 1)
    823  1.1  mrg         {
    824  1.1  mrg             if (xor & d)
    825  1.1  mrg             {
    826  1.1  mrg                 x |= d;
    827  1.1  mrg                 if (lhsc.imax.value & d)
    828  1.1  mrg                 {
    829  1.1  mrg                     if (~lhsc.imin.value & d)
    830  1.1  mrg                     {
    831  1.1  mrg                         lhsc.imin.value = 0;
    832  1.1  mrg                     }
    833  1.1  mrg                 }
    834  1.1  mrg                 else
    835  1.1  mrg                 {
    836  1.1  mrg                     if (~rhsc.imin.value & d)
    837  1.1  mrg                     {
    838  1.1  mrg                         rhsc.imin.value = 0;
    839  1.1  mrg                     }
    840  1.1  mrg                 }
    841  1.1  mrg             }
    842  1.1  mrg             else if (lhsc.imin.value & rhsc.imin.value & d)
    843  1.1  mrg             {
    844  1.1  mrg                 x |= d;
    845  1.1  mrg             }
    846  1.1  mrg             else if (and & d)
    847  1.1  mrg             {
    848  1.1  mrg                 x |= (d << 1) - 1;
    849  1.1  mrg                 break;
    850  1.1  mrg             }
    851  1.1  mrg         }
    852  1.1  mrg 
    853  1.1  mrg         auto range = SignExtendedNumber(x, sign);
    854  1.1  mrg         return range;
    855  1.1  mrg     }
    856  1.1  mrg 
    857  1.1  mrg     // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
    858  1.1  mrg     // https://github.com/tgehr/d-compiler/blob/master/vrange.d
    859  1.1  mrg     static SignExtendedNumber minOr(const IntRange lhs, const IntRange rhs)
    860  1.1  mrg     {
    861  1.1  mrg         return ~maxAnd(~lhs, ~rhs);
    862  1.1  mrg     }
    863  1.1  mrg 
    864  1.1  mrg     // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
    865  1.1  mrg     // https://github.com/tgehr/d-compiler/blob/master/vrange.d
    866  1.1  mrg     static SignExtendedNumber maxAnd(const IntRange lhs, const IntRange rhs)
    867  1.1  mrg     {
    868  1.1  mrg         uinteger_t x = 0;
    869  1.1  mrg         bool sign = false;
    870  1.1  mrg         auto lhsc = IntRange(lhs);
    871  1.1  mrg         auto rhsc = IntRange(rhs);
    872  1.1  mrg 
    873  1.1  mrg         if (lhsc.imax.negative & rhsc.imax.negative)
    874  1.1  mrg         {
    875  1.1  mrg             sign = true;
    876  1.1  mrg         }
    877  1.1  mrg 
    878  1.1  mrg         for (uinteger_t d = 1LU << (8 * uinteger_t.sizeof - 1); d; d >>= 1)
    879  1.1  mrg         {
    880  1.1  mrg             if (lhsc.imax.value & rhsc.imax.value & d)
    881  1.1  mrg             {
    882  1.1  mrg                 x |= d;
    883  1.1  mrg                 if (~lhsc.imin.value & d)
    884  1.1  mrg                 {
    885  1.1  mrg                     lhsc.imin.value = 0;
    886  1.1  mrg                 }
    887  1.1  mrg                 if (~rhsc.imin.value & d)
    888  1.1  mrg                 {
    889  1.1  mrg                     rhsc.imin.value = 0;
    890  1.1  mrg                 }
    891  1.1  mrg             }
    892  1.1  mrg             else if (~lhsc.imin.value & d && lhsc.imax.value & d)
    893  1.1  mrg             {
    894  1.1  mrg                 lhsc.imax.value |= d - 1;
    895  1.1  mrg             }
    896  1.1  mrg             else if (~rhsc.imin.value & d && rhsc.imax.value & d)
    897  1.1  mrg             {
    898  1.1  mrg                 rhsc.imax.value |= d - 1;
    899  1.1  mrg             }
    900  1.1  mrg         }
    901  1.1  mrg 
    902  1.1  mrg         auto range = SignExtendedNumber(x, sign);
    903  1.1  mrg         return range;
    904  1.1  mrg     }
    905  1.1  mrg 
    906  1.1  mrg     // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
    907  1.1  mrg     // https://github.com/tgehr/d-compiler/blob/master/vrange.d
    908  1.1  mrg     static SignExtendedNumber minAnd(const IntRange lhs, const IntRange rhs)
    909  1.1  mrg     {
    910  1.1  mrg         return ~maxOr(~lhs, ~rhs);
    911  1.1  mrg     }
    912  1.1  mrg 
    913  1.1  mrg     static swap(ref IntRange a, ref IntRange b)
    914  1.1  mrg     {
    915  1.1  mrg         auto aux = a;
    916  1.1  mrg         a = b;
    917  1.1  mrg         b = aux;
    918  1.1  mrg     }
    919  1.1  mrg }
    920