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)273cab2bb3SpatrickCOMPILER_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