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  * 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 }