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