xref: /openbsd-src/gnu/llvm/compiler-rt/lib/builtins/udivmoddi4.c (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file implements __udivmoddi4 for the compiler_rt library.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick 
133cab2bb3Spatrick #include "int_lib.h"
143cab2bb3Spatrick 
153cab2bb3Spatrick // Effects: if rem != 0, *rem = a % b
163cab2bb3Spatrick // Returns: a / b
173cab2bb3Spatrick 
183cab2bb3Spatrick // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
193cab2bb3Spatrick 
203cab2bb3Spatrick #if defined(_MSC_VER) && !defined(__clang__)
213cab2bb3Spatrick // MSVC throws a warning about mod 0 here, disable it for builds that
223cab2bb3Spatrick // warn-as-error
233cab2bb3Spatrick #pragma warning(push)
24*810390e3Srobert #pragma warning(disable : 4723 4724)
253cab2bb3Spatrick #endif
263cab2bb3Spatrick 
__udivmoddi4(du_int a,du_int b,du_int * rem)273cab2bb3Spatrick COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) {
283cab2bb3Spatrick   const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
293cab2bb3Spatrick   const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
303cab2bb3Spatrick   udwords n;
313cab2bb3Spatrick   n.all = a;
323cab2bb3Spatrick   udwords d;
333cab2bb3Spatrick   d.all = b;
343cab2bb3Spatrick   udwords q;
353cab2bb3Spatrick   udwords r;
363cab2bb3Spatrick   unsigned sr;
373cab2bb3Spatrick   // special cases, X is unknown, K != 0
383cab2bb3Spatrick   if (n.s.high == 0) {
393cab2bb3Spatrick     if (d.s.high == 0) {
403cab2bb3Spatrick       // 0 X
413cab2bb3Spatrick       // ---
423cab2bb3Spatrick       // 0 X
433cab2bb3Spatrick       if (rem)
443cab2bb3Spatrick         *rem = n.s.low % d.s.low;
453cab2bb3Spatrick       return n.s.low / d.s.low;
463cab2bb3Spatrick     }
473cab2bb3Spatrick     // 0 X
483cab2bb3Spatrick     // ---
493cab2bb3Spatrick     // K X
503cab2bb3Spatrick     if (rem)
513cab2bb3Spatrick       *rem = n.s.low;
523cab2bb3Spatrick     return 0;
533cab2bb3Spatrick   }
543cab2bb3Spatrick   // n.s.high != 0
553cab2bb3Spatrick   if (d.s.low == 0) {
563cab2bb3Spatrick     if (d.s.high == 0) {
573cab2bb3Spatrick       // K X
583cab2bb3Spatrick       // ---
593cab2bb3Spatrick       // 0 0
603cab2bb3Spatrick       if (rem)
613cab2bb3Spatrick         *rem = n.s.high % d.s.low;
623cab2bb3Spatrick       return n.s.high / d.s.low;
633cab2bb3Spatrick     }
643cab2bb3Spatrick     // d.s.high != 0
653cab2bb3Spatrick     if (n.s.low == 0) {
663cab2bb3Spatrick       // K 0
673cab2bb3Spatrick       // ---
683cab2bb3Spatrick       // K 0
693cab2bb3Spatrick       if (rem) {
703cab2bb3Spatrick         r.s.high = n.s.high % d.s.high;
713cab2bb3Spatrick         r.s.low = 0;
723cab2bb3Spatrick         *rem = r.all;
733cab2bb3Spatrick       }
743cab2bb3Spatrick       return n.s.high / d.s.high;
753cab2bb3Spatrick     }
763cab2bb3Spatrick     // K K
773cab2bb3Spatrick     // ---
783cab2bb3Spatrick     // K 0
793cab2bb3Spatrick     if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ {
803cab2bb3Spatrick       if (rem) {
813cab2bb3Spatrick         r.s.low = n.s.low;
823cab2bb3Spatrick         r.s.high = n.s.high & (d.s.high - 1);
833cab2bb3Spatrick         *rem = r.all;
843cab2bb3Spatrick       }
85*810390e3Srobert       return n.s.high >> ctzsi(d.s.high);
863cab2bb3Spatrick     }
873cab2bb3Spatrick     // K K
883cab2bb3Spatrick     // ---
893cab2bb3Spatrick     // K 0
901f9cb04fSpatrick     sr = clzsi(d.s.high) - clzsi(n.s.high);
913cab2bb3Spatrick     // 0 <= sr <= n_uword_bits - 2 or sr large
923cab2bb3Spatrick     if (sr > n_uword_bits - 2) {
933cab2bb3Spatrick       if (rem)
943cab2bb3Spatrick         *rem = n.all;
953cab2bb3Spatrick       return 0;
963cab2bb3Spatrick     }
973cab2bb3Spatrick     ++sr;
983cab2bb3Spatrick     // 1 <= sr <= n_uword_bits - 1
993cab2bb3Spatrick     // q.all = n.all << (n_udword_bits - sr);
1003cab2bb3Spatrick     q.s.low = 0;
1013cab2bb3Spatrick     q.s.high = n.s.low << (n_uword_bits - sr);
1023cab2bb3Spatrick     // r.all = n.all >> sr;
1033cab2bb3Spatrick     r.s.high = n.s.high >> sr;
1043cab2bb3Spatrick     r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
1053cab2bb3Spatrick   } else /* d.s.low != 0 */ {
1063cab2bb3Spatrick     if (d.s.high == 0) {
1073cab2bb3Spatrick       // K X
1083cab2bb3Spatrick       // ---
1093cab2bb3Spatrick       // 0 K
1103cab2bb3Spatrick       if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ {
1113cab2bb3Spatrick         if (rem)
1123cab2bb3Spatrick           *rem = n.s.low & (d.s.low - 1);
1133cab2bb3Spatrick         if (d.s.low == 1)
1143cab2bb3Spatrick           return n.all;
115*810390e3Srobert         sr = ctzsi(d.s.low);
1163cab2bb3Spatrick         q.s.high = n.s.high >> sr;
1173cab2bb3Spatrick         q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
1183cab2bb3Spatrick         return q.all;
1193cab2bb3Spatrick       }
1203cab2bb3Spatrick       // K X
1213cab2bb3Spatrick       // ---
1223cab2bb3Spatrick       // 0 K
1231f9cb04fSpatrick       sr = 1 + n_uword_bits + clzsi(d.s.low) - clzsi(n.s.high);
1243cab2bb3Spatrick       // 2 <= sr <= n_udword_bits - 1
1253cab2bb3Spatrick       // q.all = n.all << (n_udword_bits - sr);
1263cab2bb3Spatrick       // r.all = n.all >> sr;
1273cab2bb3Spatrick       if (sr == n_uword_bits) {
1283cab2bb3Spatrick         q.s.low = 0;
1293cab2bb3Spatrick         q.s.high = n.s.low;
1303cab2bb3Spatrick         r.s.high = 0;
1313cab2bb3Spatrick         r.s.low = n.s.high;
1323cab2bb3Spatrick       } else if (sr < n_uword_bits) /* 2 <= sr <= n_uword_bits - 1 */ {
1333cab2bb3Spatrick         q.s.low = 0;
1343cab2bb3Spatrick         q.s.high = n.s.low << (n_uword_bits - sr);
1353cab2bb3Spatrick         r.s.high = n.s.high >> sr;
1363cab2bb3Spatrick         r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
1373cab2bb3Spatrick       } else /* n_uword_bits + 1 <= sr <= n_udword_bits - 1 */ {
1383cab2bb3Spatrick         q.s.low = n.s.low << (n_udword_bits - sr);
1393cab2bb3Spatrick         q.s.high = (n.s.high << (n_udword_bits - sr)) |
1403cab2bb3Spatrick                    (n.s.low >> (sr - n_uword_bits));
1413cab2bb3Spatrick         r.s.high = 0;
1423cab2bb3Spatrick         r.s.low = n.s.high >> (sr - n_uword_bits);
1433cab2bb3Spatrick       }
1443cab2bb3Spatrick     } else {
1453cab2bb3Spatrick       // K X
1463cab2bb3Spatrick       // ---
1473cab2bb3Spatrick       // K K
1481f9cb04fSpatrick       sr = clzsi(d.s.high) - clzsi(n.s.high);
1493cab2bb3Spatrick       // 0 <= sr <= n_uword_bits - 1 or sr large
1503cab2bb3Spatrick       if (sr > n_uword_bits - 1) {
1513cab2bb3Spatrick         if (rem)
1523cab2bb3Spatrick           *rem = n.all;
1533cab2bb3Spatrick         return 0;
1543cab2bb3Spatrick       }
1553cab2bb3Spatrick       ++sr;
1563cab2bb3Spatrick       // 1 <= sr <= n_uword_bits
1573cab2bb3Spatrick       // q.all = n.all << (n_udword_bits - sr);
1583cab2bb3Spatrick       q.s.low = 0;
1593cab2bb3Spatrick       if (sr == n_uword_bits) {
1603cab2bb3Spatrick         q.s.high = n.s.low;
1613cab2bb3Spatrick         r.s.high = 0;
1623cab2bb3Spatrick         r.s.low = n.s.high;
1633cab2bb3Spatrick       } else {
1643cab2bb3Spatrick         q.s.high = n.s.low << (n_uword_bits - sr);
1653cab2bb3Spatrick         r.s.high = n.s.high >> sr;
1663cab2bb3Spatrick         r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
1673cab2bb3Spatrick       }
1683cab2bb3Spatrick     }
1693cab2bb3Spatrick   }
1703cab2bb3Spatrick   // Not a special case
1713cab2bb3Spatrick   // q and r are initialized with:
1723cab2bb3Spatrick   // q.all = n.all << (n_udword_bits - sr);
1733cab2bb3Spatrick   // r.all = n.all >> sr;
1743cab2bb3Spatrick   // 1 <= sr <= n_udword_bits - 1
1753cab2bb3Spatrick   su_int carry = 0;
1763cab2bb3Spatrick   for (; sr > 0; --sr) {
1773cab2bb3Spatrick     // r:q = ((r:q)  << 1) | carry
1783cab2bb3Spatrick     r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1));
1793cab2bb3Spatrick     r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1));
1803cab2bb3Spatrick     q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1));
1813cab2bb3Spatrick     q.s.low = (q.s.low << 1) | carry;
1823cab2bb3Spatrick     // carry = 0;
1833cab2bb3Spatrick     // if (r.all >= d.all)
1843cab2bb3Spatrick     // {
1853cab2bb3Spatrick     //      r.all -= d.all;
1863cab2bb3Spatrick     //      carry = 1;
1873cab2bb3Spatrick     // }
1883cab2bb3Spatrick     const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1);
1893cab2bb3Spatrick     carry = s & 1;
1903cab2bb3Spatrick     r.all -= d.all & s;
1913cab2bb3Spatrick   }
1923cab2bb3Spatrick   q.all = (q.all << 1) | carry;
1933cab2bb3Spatrick   if (rem)
1943cab2bb3Spatrick     *rem = r.all;
1953cab2bb3Spatrick   return q.all;
1963cab2bb3Spatrick }
1973cab2bb3Spatrick 
1983cab2bb3Spatrick #if defined(_MSC_VER) && !defined(__clang__)
1993cab2bb3Spatrick #pragma warning(pop)
2003cab2bb3Spatrick #endif
201