|
| 1 | +//===-- int_div_impl.inc - Integer division ---------------------*- C++ -*-===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | +// |
| 9 | +// Helpers used by __udivsi3, __umodsi3, __udivdi3, and __umodsi3. |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +#define clz(a) (sizeof(a) == sizeof(unsigned long long) ? __builtin_clzll(a) : clzsi(a)) |
| 14 | + |
| 15 | +// Adapted from Figure 3-40 of The PowerPC Compiler Writer's Guide |
| 16 | +static __inline fixuint_t __udivXi3(fixuint_t n, fixuint_t d) { |
| 17 | + const unsigned N = sizeof(fixuint_t) * CHAR_BIT; |
| 18 | + // d == 0 cases are unspecified. |
| 19 | + unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N); |
| 20 | + // 0 <= sr <= N - 1 or sr is very large. |
| 21 | + if (sr > N - 1) // n < d |
| 22 | + return 0; |
| 23 | + if (sr == N - 1) // d == 1 |
| 24 | + return n; |
| 25 | + ++sr; |
| 26 | + // 1 <= sr <= N - 1. Shifts do not trigger UB. |
| 27 | + fixuint_t r = n >> sr; |
| 28 | + n <<= N - sr; |
| 29 | + fixuint_t carry = 0; |
| 30 | + for (; sr > 0; --sr) { |
| 31 | + r = (r << 1) | (n >> (N - 1)); |
| 32 | + n = (n << 1) | carry; |
| 33 | + // Branch-less version of: |
| 34 | + // carry = 0; |
| 35 | + // if (r >= d) r -= d, carry = 1; |
| 36 | + const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1); |
| 37 | + carry = s & 1; |
| 38 | + r -= d & s; |
| 39 | + } |
| 40 | + n = (n << 1) | carry; |
| 41 | + return n; |
| 42 | +} |
| 43 | + |
| 44 | +// Mostly identical to __udivXi3 but the return values are different. |
| 45 | +static __inline fixuint_t __umodXi3(fixuint_t n, fixuint_t d) { |
| 46 | + const unsigned N = sizeof(fixuint_t) * CHAR_BIT; |
| 47 | + // d == 0 cases are unspecified. |
| 48 | + unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N); |
| 49 | + // 0 <= sr <= N - 1 or sr is very large. |
| 50 | + if (sr > N - 1) // n < d |
| 51 | + return n; |
| 52 | + if (sr == N - 1) // d == 1 |
| 53 | + return 0; |
| 54 | + ++sr; |
| 55 | + // 1 <= sr <= N - 1. Shifts do not trigger UB. |
| 56 | + fixuint_t r = n >> sr; |
| 57 | + n <<= N - sr; |
| 58 | + fixuint_t carry = 0; |
| 59 | + for (; sr > 0; --sr) { |
| 60 | + r = (r << 1) | (n >> (N - 1)); |
| 61 | + n = (n << 1) | carry; |
| 62 | + // Branch-less version of: |
| 63 | + // carry = 0; |
| 64 | + // if (r >= d) r -= d, carry = 1; |
| 65 | + const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1); |
| 66 | + carry = s & 1; |
| 67 | + r -= d & s; |
| 68 | + } |
| 69 | + return r; |
| 70 | +} |
| 71 | + |
| 72 | +#ifdef COMPUTE_UDIV |
| 73 | +static __inline fixint_t __divXi3(fixint_t a, fixint_t b) { |
| 74 | + const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1; |
| 75 | + fixint_t s_a = a >> N; // s_a = a < 0 ? -1 : 0 |
| 76 | + fixint_t s_b = b >> N; // s_b = b < 0 ? -1 : 0 |
| 77 | + fixuint_t a_u = (fixuint_t)(a ^ s_a) + (-s_a); // negate if s_a == -1 |
| 78 | + fixuint_t b_u = (fixuint_t)(b ^ s_b) + (-s_b); // negate if s_b == -1 |
| 79 | + s_a ^= s_b; // sign of quotient |
| 80 | + return (COMPUTE_UDIV(a_u, b_u) ^ s_a) + (-s_a); // negate if s_a == -1 |
| 81 | +} |
| 82 | +#endif // COMPUTE_UDIV |
| 83 | + |
| 84 | +#ifdef ASSIGN_UMOD |
| 85 | +static __inline fixint_t __modXi3(fixint_t a, fixint_t b) { |
| 86 | + const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1; |
| 87 | + fixint_t s = b >> N; // s = b < 0 ? -1 : 0 |
| 88 | + fixuint_t b_u = (fixuint_t)(b ^ s) + (-s); // negate if s == -1 |
| 89 | + s = a >> N; // s = a < 0 ? -1 : 0 |
| 90 | + fixuint_t a_u = (fixuint_t)(a ^ s) + (-s); // negate if s == -1 |
| 91 | + fixuint_t res; |
| 92 | + ASSIGN_UMOD(res, a_u, b_u); |
| 93 | + return (res ^ s) + (-s); // negate if s == -1 |
| 94 | +} |
| 95 | +#endif // ASSIGN_UMOD |
0 commit comments