The OpenD Programming Language

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 }