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