1 2 /********************************************** 3 * This module implements integral arithmetic primitives that check 4 * for out-of-range results. 5 * 6 * Integral arithmetic operators operate on fixed width types. 7 * Results that are not representable in those fixed widths are silently 8 * truncated to fit. 9 * This module offers integral arithmetic primitives that produce the 10 * same results, but set an 'overflow' flag when such truncation occurs. 11 * The setting is sticky, meaning that numerous operations can be cascaded 12 * and then the flag need only be checked at the end. 13 * Whether the operation is signed or unsigned is indicated by an 's' or 'u' 14 * suffix, respectively. While this could be achieved without such suffixes by 15 * using overloading on the signedness of the types, the suffix makes it clear 16 * which is happening without needing to examine the types. 17 * 18 * While the generic versions of these functions are computationally expensive 19 * relative to the cost of the operation itself, compiler implementations are free 20 * to recognize them and generate equivalent and faster code. 21 * 22 * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks) 23 * License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0) 24 * Authors: Walter Bright 25 * Source: $(DRUNTIMESRC core/_checkedint.d) 26 */ 27 28 module mir.checkedint; 29 30 version (GNU) 31 { 32 // GDC uses intrinsics for core.checkedint functions. 33 public import core.checkedint : adds, addu, subs, subu, muls, mulu, negs; 34 } 35 else: 36 37 version (LDC) 38 { 39 import ldc.intrinsics; 40 41 // llvm.(u)mul.with.overflow.i64 might fall back to a software implementation 42 // in the form of __mulodi4, which only exists in compiler-rt and not 43 // libgcc. Thus, we need to be sure not to emit it for now (see GitHub #818). 44 version (X86_64) 45 version = LDC_HasNativeI64Mul; 46 } 47 48 nothrow: 49 @safe: 50 @nogc: 51 pure: 52 53 /******************************* 54 * Add two signed integers, checking for overflow. 55 * 56 * The overflow is sticky, meaning a sequence of operations can 57 * be done and overflow need only be checked at the end. 58 * Params: 59 * x = left operand 60 * y = right operand 61 * overflow = set if an overflow occurs, is not affected otherwise 62 * Returns: 63 * the sum 64 */ 65 66 pragma(inline, true) 67 int adds(int x, int y, scope ref bool overflow) 68 { 69 version (LDC) 70 { 71 if (!__ctfe) 72 { 73 auto res = llvm_sadd_with_overflow(x, y); 74 overflow |= res.overflow; 75 return res.result; 76 } 77 } 78 long r = cast(long)x + cast(long)y; 79 if (r < int.min || r > int.max) 80 overflow = true; 81 return cast(int)r; 82 } 83 84 version(mir_core_test) unittest 85 { 86 bool overflow; 87 assert(adds(2, 3, overflow) == 5); 88 assert(!overflow); 89 assert(adds(1, int.max - 1, overflow) == int.max); 90 assert(!overflow); 91 assert(adds(int.min + 1, -1, overflow) == int.min); 92 assert(!overflow); 93 assert(adds(int.max, 1, overflow) == int.min); 94 assert(overflow); 95 overflow = false; 96 assert(adds(int.min, -1, overflow) == int.max); 97 assert(overflow); 98 assert(adds(0, 0, overflow) == 0); 99 assert(overflow); // sticky 100 } 101 102 /// ditto 103 pragma(inline, true) 104 long adds(long x, long y, scope ref bool overflow) 105 { 106 version (LDC) 107 { 108 if (!__ctfe) 109 { 110 auto res = llvm_sadd_with_overflow(x, y); 111 overflow |= res.overflow; 112 return res.result; 113 } 114 } 115 long r = cast(ulong)x + cast(ulong)y; 116 if (x < 0 && y < 0 && r >= 0 || 117 x >= 0 && y >= 0 && r < 0) 118 overflow = true; 119 return r; 120 } 121 122 version(mir_core_test) unittest 123 { 124 bool overflow; 125 assert(adds(2L, 3L, overflow) == 5); 126 assert(!overflow); 127 assert(adds(1L, long.max - 1, overflow) == long.max); 128 assert(!overflow); 129 assert(adds(long.min + 1, -1, overflow) == long.min); 130 assert(!overflow); 131 assert(adds(long.max, 1, overflow) == long.min); 132 assert(overflow); 133 overflow = false; 134 assert(adds(long.min, -1, overflow) == long.max); 135 assert(overflow); 136 assert(adds(0L, 0L, overflow) == 0); 137 assert(overflow); // sticky 138 } 139 140 static if (is(cent)) 141 { 142 /// ditto 143 pragma(inline, true) 144 cent adds(cent x, cent y, scope ref bool overflow) 145 { 146 version (LDC) 147 { 148 if (!__ctfe) 149 { 150 auto res = llvm_sadd_with_overflow(x, y); 151 overflow |= res.overflow; 152 return res.result; 153 } 154 } 155 cent r = cast(ucent)x + cast(ucent)y; 156 if (x < 0 && y < 0 && r >= 0 || 157 x >= 0 && y >= 0 && r < 0) 158 overflow = true; 159 return r; 160 } 161 162 version(mir_core_test) unittest 163 { 164 bool overflow; 165 assert(adds(cast(cent)2L, 3L, overflow) == 5); 166 assert(!overflow); 167 assert(adds(1L, cent.max - 1, overflow) == cent.max); 168 assert(!overflow); 169 assert(adds(cent.min + 1, -1, overflow) == cent.min); 170 assert(!overflow); 171 assert(adds(cent.max, 1, overflow) == cent.min); 172 assert(overflow); 173 overflow = false; 174 assert(adds(cent.min, -1, overflow) == cent.max); 175 assert(overflow); 176 assert(adds(cast(cent)0L, 0L, overflow) == 0); 177 assert(overflow); // sticky 178 } 179 } 180 181 182 /******************************* 183 * Add two unsigned integers, checking for overflow (aka carry). 184 * 185 * The overflow is sticky, meaning a sequence of operations can 186 * be done and overflow need only be checked at the end. 187 * Params: 188 * x = left operand 189 * y = right operand 190 * overflow = set if an overflow occurs, is not affected otherwise 191 * Returns: 192 * the sum 193 */ 194 195 pragma(inline, true) 196 uint addu(uint x, uint y, scope ref bool overflow) 197 { 198 version (LDC) 199 { 200 if (!__ctfe) 201 { 202 auto res = llvm_uadd_with_overflow(x, y); 203 overflow |= res.overflow; 204 return res.result; 205 } 206 } 207 immutable uint r = x + y; 208 if (r < x || r < y) 209 overflow = true; 210 return r; 211 } 212 213 version(mir_core_test) unittest 214 { 215 bool overflow; 216 assert(addu(2, 3, overflow) == 5); 217 assert(!overflow); 218 assert(addu(1, uint.max - 1, overflow) == uint.max); 219 assert(!overflow); 220 assert(addu(uint.min, -1, overflow) == uint.max); 221 assert(!overflow); 222 assert(addu(uint.max, 1, overflow) == uint.min); 223 assert(overflow); 224 overflow = false; 225 assert(addu(uint.min + 1, -1, overflow) == uint.min); 226 assert(overflow); 227 assert(addu(0, 0, overflow) == 0); 228 assert(overflow); // sticky 229 } 230 231 /// ditto 232 pragma(inline, true) 233 ulong addu(ulong x, ulong y, scope ref bool overflow) 234 { 235 version (LDC) 236 { 237 if (!__ctfe) 238 { 239 auto res = llvm_uadd_with_overflow(x, y); 240 overflow |= res.overflow; 241 return res.result; 242 } 243 } 244 immutable ulong r = x + y; 245 if (r < x || r < y) 246 overflow = true; 247 return r; 248 } 249 250 version(mir_core_test) unittest 251 { 252 bool overflow; 253 assert(addu(2L, 3L, overflow) == 5); 254 assert(!overflow); 255 assert(addu(1, ulong.max - 1, overflow) == ulong.max); 256 assert(!overflow); 257 assert(addu(ulong.min, -1L, overflow) == ulong.max); 258 assert(!overflow); 259 assert(addu(ulong.max, 1, overflow) == ulong.min); 260 assert(overflow); 261 overflow = false; 262 assert(addu(ulong.min + 1, -1L, overflow) == ulong.min); 263 assert(overflow); 264 assert(addu(0L, 0L, overflow) == 0); 265 assert(overflow); // sticky 266 } 267 268 static if (is(ucent)) 269 { 270 /// ditto 271 pragma(inline, true) 272 ucent addu(ucent x, ucent y, scope ref bool overflow) 273 { 274 version (LDC) 275 { 276 if (!__ctfe) 277 { 278 auto res = llvm_uadd_with_overflow(x, y); 279 overflow |= res.overflow; 280 return res.result; 281 } 282 } 283 immutable ucent r = x + y; 284 if (r < x || r < y) 285 overflow = true; 286 return r; 287 } 288 289 version(mir_core_test) unittest 290 { 291 bool overflow; 292 assert(addu(cast(ucent)2L, 3L, overflow) == 5); 293 assert(!overflow); 294 assert(addu(1, ucent.max - 1, overflow) == ucent.max); 295 assert(!overflow); 296 assert(addu(ucent.min, -1L, overflow) == ucent.max); 297 assert(!overflow); 298 assert(addu(ucent.max, 1, overflow) == ucent.min); 299 assert(overflow); 300 overflow = false; 301 assert(addu(ucent.min + 1, -1L, overflow) == ucent.min); 302 assert(overflow); 303 assert(addu(cast(ucent)0L, 0L, overflow) == 0); 304 assert(overflow); // sticky 305 } 306 } 307 308 309 /******************************* 310 * Subtract two signed integers, checking for overflow. 311 * 312 * The overflow is sticky, meaning a sequence of operations can 313 * be done and overflow need only be checked at the end. 314 * Params: 315 * x = left operand 316 * y = right operand 317 * overflow = set if an overflow occurs, is not affected otherwise 318 * Returns: 319 * the difference 320 */ 321 322 pragma(inline, true) 323 int subs(int x, int y, scope ref bool overflow) 324 { 325 version (LDC) 326 { 327 if (!__ctfe) 328 { 329 auto res = llvm_ssub_with_overflow(x, y); 330 overflow |= res.overflow; 331 return res.result; 332 } 333 } 334 immutable long r = cast(long)x - cast(long)y; 335 if (r < int.min || r > int.max) 336 overflow = true; 337 return cast(int)r; 338 } 339 340 version(mir_core_test) unittest 341 { 342 bool overflow; 343 assert(subs(2, -3, overflow) == 5); 344 assert(!overflow); 345 assert(subs(1, -int.max + 1, overflow) == int.max); 346 assert(!overflow); 347 assert(subs(int.min + 1, 1, overflow) == int.min); 348 assert(!overflow); 349 assert(subs(int.max, -1, overflow) == int.min); 350 assert(overflow); 351 overflow = false; 352 assert(subs(int.min, 1, overflow) == int.max); 353 assert(overflow); 354 assert(subs(0, 0, overflow) == 0); 355 assert(overflow); // sticky 356 } 357 358 /// ditto 359 pragma(inline, true) 360 long subs(long x, long y, scope ref bool overflow) 361 { 362 version (LDC) 363 { 364 if (!__ctfe) 365 { 366 auto res = llvm_ssub_with_overflow(x, y); 367 overflow |= res.overflow; 368 return res.result; 369 } 370 } 371 immutable long r = cast(ulong)x - cast(ulong)y; 372 if (x < 0 && y >= 0 && r >= 0 || 373 x >= 0 && y < 0 && (r < 0 || y == long.min)) 374 overflow = true; 375 return r; 376 } 377 378 version(mir_core_test) unittest 379 { 380 bool overflow; 381 assert(subs(2L, -3L, overflow) == 5); 382 assert(!overflow); 383 assert(subs(1L, -long.max + 1, overflow) == long.max); 384 assert(!overflow); 385 assert(subs(long.min + 1, 1, overflow) == long.min); 386 assert(!overflow); 387 assert(subs(-1L, long.min, overflow) == long.max); 388 assert(!overflow); 389 assert(subs(long.max, -1, overflow) == long.min); 390 assert(overflow); 391 overflow = false; 392 assert(subs(long.min, 1, overflow) == long.max); 393 assert(overflow); 394 assert(subs(0L, 0L, overflow) == 0); 395 assert(overflow); // sticky 396 } 397 398 static if (is(cent)) 399 { 400 /// ditto 401 pragma(inline, true) 402 cent subs(cent x, cent y, scope ref bool overflow) 403 { 404 version (LDC) 405 { 406 if (!__ctfe) 407 { 408 auto res = llvm_ssub_with_overflow(x, y); 409 overflow |= res.overflow; 410 return res.result; 411 } 412 } 413 immutable cent r = cast(ucent)x - cast(ucent)y; 414 if (x < 0 && y >= 0 && r >= 0 || 415 x >= 0 && y < 0 && (r < 0 || y == long.min)) 416 overflow = true; 417 return r; 418 } 419 420 version(mir_core_test) unittest 421 { 422 bool overflow; 423 assert(subs(cast(cent)2L, -3L, overflow) == 5); 424 assert(!overflow); 425 assert(subs(1L, -cent.max + 1, overflow) == cent.max); 426 assert(!overflow); 427 assert(subs(cent.min + 1, 1, overflow) == cent.min); 428 assert(!overflow); 429 assert(subs(-1L, cent.min, overflow) == cent.max); 430 assert(!overflow); 431 assert(subs(cent.max, -1, overflow) == cent.min); 432 assert(overflow); 433 overflow = false; 434 assert(subs(cent.min, 1, overflow) == cent.max); 435 assert(overflow); 436 assert(subs(cast(cent)0L, 0L, overflow) == 0); 437 assert(overflow); // sticky 438 } 439 } 440 441 442 /******************************* 443 * Subtract two unsigned integers, checking for overflow (aka borrow). 444 * 445 * The overflow is sticky, meaning a sequence of operations can 446 * be done and overflow need only be checked at the end. 447 * Params: 448 * x = left operand 449 * y = right operand 450 * overflow = set if an overflow occurs, is not affected otherwise 451 * Returns: 452 * the difference 453 */ 454 455 pragma(inline, true) 456 uint subu(uint x, uint y, scope ref bool overflow) 457 { 458 version (LDC) 459 { 460 if (!__ctfe) 461 { 462 auto res = llvm_usub_with_overflow(x, y); 463 overflow |= res.overflow; 464 return res.result; 465 } 466 } 467 if (x < y) 468 overflow = true; 469 return x - y; 470 } 471 472 version(mir_core_test) unittest 473 { 474 bool overflow; 475 assert(subu(3, 2, overflow) == 1); 476 assert(!overflow); 477 assert(subu(uint.max, 1, overflow) == uint.max - 1); 478 assert(!overflow); 479 assert(subu(1, 1, overflow) == uint.min); 480 assert(!overflow); 481 assert(subu(0, 1, overflow) == uint.max); 482 assert(overflow); 483 overflow = false; 484 assert(subu(uint.max - 1, uint.max, overflow) == uint.max); 485 assert(overflow); 486 assert(subu(0, 0, overflow) == 0); 487 assert(overflow); // sticky 488 } 489 490 491 /// ditto 492 pragma(inline, true) 493 ulong subu(ulong x, ulong y, scope ref bool overflow) 494 { 495 version (LDC) 496 { 497 if (!__ctfe) 498 { 499 auto res = llvm_usub_with_overflow(x, y); 500 overflow |= res.overflow; 501 return res.result; 502 } 503 } 504 if (x < y) 505 overflow = true; 506 return x - y; 507 } 508 509 version(mir_core_test) unittest 510 { 511 bool overflow; 512 assert(subu(3UL, 2UL, overflow) == 1); 513 assert(!overflow); 514 assert(subu(ulong.max, 1, overflow) == ulong.max - 1); 515 assert(!overflow); 516 assert(subu(1UL, 1UL, overflow) == ulong.min); 517 assert(!overflow); 518 assert(subu(0UL, 1UL, overflow) == ulong.max); 519 assert(overflow); 520 overflow = false; 521 assert(subu(ulong.max - 1, ulong.max, overflow) == ulong.max); 522 assert(overflow); 523 assert(subu(0UL, 0UL, overflow) == 0); 524 assert(overflow); // sticky 525 } 526 527 static if (is(ucent)) 528 { 529 /// ditto 530 pragma(inline, true) 531 ucent subu(ucent x, ucent y, scope ref bool overflow) 532 { 533 version (LDC) 534 { 535 if (!__ctfe) 536 { 537 auto res = llvm_usub_with_overflow(x, y); 538 overflow |= res.overflow; 539 return res.result; 540 } 541 } 542 if (x < y) 543 overflow = true; 544 return x - y; 545 } 546 547 version(mir_core_test) unittest 548 { 549 bool overflow; 550 assert(subu(cast(ucent)3UL, 2UL, overflow) == 1); 551 assert(!overflow); 552 assert(subu(ucent.max, 1, overflow) == ucent.max - 1); 553 assert(!overflow); 554 assert(subu(1UL, 1UL, overflow) == ucent.min); 555 assert(!overflow); 556 assert(subu(cast(ucent)0UL, 1UL, overflow) == ucent.max); 557 assert(overflow); 558 overflow = false; 559 assert(subu(ucent.max - 1, ucent.max, overflow) == ucent.max); 560 assert(overflow); 561 assert(subu(cast(ucent)0UL, 0UL, overflow) == 0); 562 assert(overflow); // sticky 563 } 564 } 565 566 567 /*********************************************** 568 * Negate an integer. 569 * 570 * Params: 571 * x = operand 572 * overflow = set if x cannot be negated, is not affected otherwise 573 * Returns: 574 * the negation of x 575 */ 576 577 pragma(inline, true) 578 int negs(int x, scope ref bool overflow) 579 { 580 if (x == int.min) 581 overflow = true; 582 return -x; 583 } 584 585 version(mir_core_test) unittest 586 { 587 bool overflow; 588 assert(negs(0, overflow) == -0); 589 assert(!overflow); 590 assert(negs(1234, overflow) == -1234); 591 assert(!overflow); 592 assert(negs(-5678, overflow) == 5678); 593 assert(!overflow); 594 assert(negs(int.min, overflow) == -int.min); 595 assert(overflow); 596 assert(negs(0, overflow) == -0); 597 assert(overflow); // sticky 598 } 599 600 /// ditto 601 pragma(inline, true) 602 long negs(long x, scope ref bool overflow) 603 { 604 if (x == long.min) 605 overflow = true; 606 return -x; 607 } 608 609 version(mir_core_test) unittest 610 { 611 bool overflow; 612 assert(negs(0L, overflow) == -0); 613 assert(!overflow); 614 assert(negs(1234L, overflow) == -1234); 615 assert(!overflow); 616 assert(negs(-5678L, overflow) == 5678); 617 assert(!overflow); 618 assert(negs(long.min, overflow) == -long.min); 619 assert(overflow); 620 assert(negs(0L, overflow) == -0); 621 assert(overflow); // sticky 622 } 623 624 static if (is(cent)) 625 { 626 /// ditto 627 pragma(inline, true) 628 cent negs(cent x, scope ref bool overflow) 629 { 630 if (x == cent.min) 631 overflow = true; 632 return -x; 633 } 634 635 version(mir_core_test) unittest 636 { 637 bool overflow; 638 assert(negs(cast(cent)0L, overflow) == -0); 639 assert(!overflow); 640 assert(negs(cast(cent)1234L, overflow) == -1234); 641 assert(!overflow); 642 assert(negs(cast(cent)-5678L, overflow) == 5678); 643 assert(!overflow); 644 assert(negs(cent.min, overflow) == -cent.min); 645 assert(overflow); 646 assert(negs(cast(cent)0L, overflow) == -0); 647 assert(overflow); // sticky 648 } 649 } 650 651 652 /******************************* 653 * Multiply two signed integers, checking for overflow. 654 * 655 * The overflow is sticky, meaning a sequence of operations can 656 * be done and overflow need only be checked at the end. 657 * Params: 658 * x = left operand 659 * y = right operand 660 * overflow = set if an overflow occurs, is not affected otherwise 661 * Returns: 662 * the product 663 */ 664 665 pragma(inline, true) 666 int muls(int x, int y, scope ref bool overflow) 667 { 668 version (LDC) 669 { 670 if (!__ctfe) 671 { 672 auto res = llvm_smul_with_overflow(x, y); 673 overflow |= res.overflow; 674 return res.result; 675 } 676 } 677 long r = cast(long)x * cast(long)y; 678 if (r < int.min || r > int.max) 679 overflow = true; 680 return cast(int)r; 681 } 682 683 version(mir_core_test) unittest 684 { 685 bool overflow; 686 assert(muls(2, 3, overflow) == 6); 687 assert(!overflow); 688 assert(muls(-200, 300, overflow) == -60_000); 689 assert(!overflow); 690 assert(muls(1, int.max, overflow) == int.max); 691 assert(!overflow); 692 assert(muls(int.min, 1, overflow) == int.min); 693 assert(!overflow); 694 assert(muls(int.max, 2, overflow) == (int.max * 2)); 695 assert(overflow); 696 overflow = false; 697 assert(muls(int.min, -1, overflow) == int.min); 698 assert(overflow); 699 assert(muls(0, 0, overflow) == 0); 700 assert(overflow); // sticky 701 } 702 703 /// ditto 704 pragma(inline, true) 705 long muls(long x, long y, scope ref bool overflow) 706 { 707 version (LDC_HasNativeI64Mul) 708 { 709 if (!__ctfe) 710 { 711 auto res = llvm_smul_with_overflow(x, y); 712 overflow |= res.overflow; 713 return res.result; 714 } 715 } 716 immutable long r = cast(ulong)x * cast(ulong)y; 717 enum not0or1 = ~1L; 718 if ((x & not0or1) && ((r == y)? r : (r / x) != y)) 719 overflow = true; 720 return r; 721 } 722 723 version(mir_core_test) unittest 724 { 725 bool overflow; 726 assert(muls(2L, 3L, overflow) == 6); 727 assert(!overflow); 728 assert(muls(-200L, 300L, overflow) == -60_000); 729 assert(!overflow); 730 assert(muls(1, long.max, overflow) == long.max); 731 assert(!overflow); 732 assert(muls(long.min, 1L, overflow) == long.min); 733 assert(!overflow); 734 assert(muls(long.max, 2L, overflow) == (long.max * 2)); 735 assert(overflow); 736 overflow = false; 737 assert(muls(-1L, long.min, overflow) == long.min); 738 assert(overflow); 739 overflow = false; 740 assert(muls(long.min, -1L, overflow) == long.min); 741 assert(overflow); 742 assert(muls(0L, 0L, overflow) == 0); 743 assert(overflow); // sticky 744 } 745 746 static if (is(cent)) 747 { 748 /// ditto 749 pragma(inline, true) 750 cent muls(cent x, cent y, scope ref bool overflow) 751 { 752 version (LDC_HasNativeI64Mul) 753 { 754 if (!__ctfe) 755 { 756 auto res = llvm_smul_with_overflow(x, y); 757 overflow |= res.overflow; 758 return res.result; 759 } 760 } 761 immutable cent r = cast(ucent)x * cast(ucent)y; 762 enum not0or1 = ~1L; 763 if ((x & not0or1) && ((r == y)? r : (r / x) != y)) 764 overflow = true; 765 return r; 766 } 767 768 version(mir_core_test) unittest 769 { 770 bool overflow; 771 assert(muls(cast(cent)2L, 3L, overflow) == 6); 772 assert(!overflow); 773 assert(muls(cast(cent)-200L, 300L, overflow) == -60_000); 774 assert(!overflow); 775 assert(muls(1, cent.max, overflow) == cent.max); 776 assert(!overflow); 777 assert(muls(cent.min, 1L, overflow) == cent.min); 778 assert(!overflow); 779 assert(muls(cent.max, 2L, overflow) == (cent.max * 2)); 780 assert(overflow); 781 overflow = false; 782 assert(muls(-1L, cent.min, overflow) == cent.min); 783 assert(overflow); 784 overflow = false; 785 assert(muls(cent.min, -1L, overflow) == cent.min); 786 assert(overflow); 787 assert(muls(cast(cent)0L, 0L, overflow) == 0); 788 assert(overflow); // sticky 789 } 790 } 791 792 793 /******************************* 794 * Multiply two unsigned integers, checking for overflow (aka carry). 795 * 796 * The overflow is sticky, meaning a sequence of operations can 797 * be done and overflow need only be checked at the end. 798 * Params: 799 * x = left operand 800 * y = right operand 801 * overflow = set if an overflow occurs, is not affected otherwise 802 * Returns: 803 * the product 804 */ 805 806 pragma(inline, true) 807 uint mulu(uint x, uint y, scope ref bool overflow) 808 { 809 version (LDC) 810 { 811 if (!__ctfe) 812 { 813 auto res = llvm_umul_with_overflow(x, y); 814 overflow |= res.overflow; 815 return res.result; 816 } 817 } 818 immutable ulong r = ulong(x) * ulong(y); 819 if (r >> 32) 820 overflow = true; 821 return cast(uint) r; 822 } 823 824 version(mir_core_test) unittest 825 { 826 void test(uint x, uint y, uint r, bool overflow) @nogc nothrow 827 { 828 bool o; 829 assert(mulu(x, y, o) == r); 830 assert(o == overflow); 831 } 832 test(2, 3, 6, false); 833 test(1, uint.max, uint.max, false); 834 test(0, 1, 0, false); 835 test(0, uint.max, 0, false); 836 test(uint.max, 2, 2 * uint.max, true); 837 test(1 << 16, 1U << 16, 0, true); 838 839 bool overflow = true; 840 assert(mulu(0, 0, overflow) == 0); 841 assert(overflow); // sticky 842 } 843 844 /// ditto 845 pragma(inline, true) 846 ulong mulu(ulong x, uint y, scope ref bool overflow) 847 { 848 ulong r = x * y; 849 if (x >> 32 && 850 r / x != y) 851 overflow = true; 852 return r; 853 } 854 855 /// ditto 856 pragma(inline, true) 857 ulong mulu(ulong x, ulong y, scope ref bool overflow) 858 { 859 version (LDC_HasNativeI64Mul) 860 { 861 if (!__ctfe) 862 { 863 auto res = llvm_umul_with_overflow(x, y); 864 overflow |= res.overflow; 865 return res.result; 866 } 867 } 868 immutable ulong r = x * y; 869 if ((x | y) >> 32 && 870 x && 871 r / x != y) 872 overflow = true; 873 return r; 874 } 875 876 version(mir_core_test) unittest 877 { 878 void test(T, U)(T x, U y, ulong r, bool overflow) @nogc nothrow 879 { 880 bool o; 881 assert(mulu(x, y, o) == r); 882 assert(o == overflow); 883 } 884 // One operand is zero 885 test(0, 3, 0, false); 886 test(0UL, 3, 0, false); 887 test(0UL, 3UL, 0, false); 888 test(3, 0, 0, false); 889 test(3UL, 0, 0, false); 890 test(3UL, 0UL, 0, false); 891 // Small numbers 892 test(2, 3, 6, false); 893 test(2UL, 3, 6, false); 894 test(2UL, 3UL, 6, false); 895 // At the 32/64 border 896 test(1, ulong(uint.max), uint.max, false); 897 test(1UL, ulong(uint.max), uint.max, false); 898 test(ulong(uint.max), 1, uint.max, false); 899 test(ulong(uint.max), 1UL, uint.max, false); 900 test(1, 1 + ulong(uint.max), 1 + ulong(uint.max), false); 901 test(1UL, 1 + ulong(uint.max), 1 + ulong(uint.max), false); 902 test(1 + ulong(uint.max), 1, 1 + ulong(uint.max), false); 903 test(1 + ulong(uint.max), 1UL, 1 + ulong(uint.max), false); 904 // At the limit 905 test(1, ulong.max, ulong.max, false); 906 test(1UL, ulong.max, ulong.max, false); 907 test(ulong.max, 1, ulong.max, false); 908 test(ulong.max, 1UL, ulong.max, false); 909 // Miscellaneous 910 test(0, 1, 0, false); 911 test(0, ulong.max, 0, false); 912 test(ulong.max, 2, 2 * ulong.max, true); 913 test(1UL << 32, 1UL << 32, 0, true); 914 // Must be sticky 915 bool overflow = true; 916 assert(mulu(0UL, 0UL, overflow) == 0); 917 assert(overflow); // sticky 918 } 919 920 static if (is(ucent)) 921 { 922 /// ditto 923 pragma(inline, true) 924 ucent mulu(ucent x, ucent y, scope ref bool overflow) 925 { 926 version (LDC_HasNativeI64Mul) 927 { 928 if (!__ctfe) 929 { 930 auto res = llvm_umul_with_overflow(x, y); 931 overflow |= res.overflow; 932 return res.result; 933 } 934 } 935 immutable ucent r = x * y; 936 if (x && (r / x) != y) 937 overflow = true; 938 return r; 939 } 940 941 version(mir_core_test) unittest 942 { 943 void test(ucent x, ucent y, ucent r, bool overflow) @nogc nothrow 944 { 945 bool o; 946 assert(mulu(x, y, o) == r); 947 assert(o == overflow); 948 } 949 test(2, 3, 6, false); 950 test(1, ucent.max, ucent.max, false); 951 test(0, 1, 0, false); 952 test(0, ucent.max, 0, false); 953 test(ucent.max, 2, 2 * ucent.max, true); 954 test(cast(ucent)1UL << 64, cast(ucent)1UL << 64, 0, true); 955 956 bool overflow = true; 957 assert(mulu(0UL, 0UL, overflow) == 0); 958 assert(overflow); // sticky 959 } 960 }