/** * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. * See https://llvm.org/LICENSE.txt for license information. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception **/ /*Portions of this file have been modified from the original (https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/udivmodti4.c) under the following copyright and license.*/ /** * Copyright Notice: * Copyright 2021-2022 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ typedef int si_int; typedef unsigned su_int; typedef long long di_int; typedef unsigned long long du_int; typedef int ti_int; typedef unsigned tu_int; #ifndef CHAR_BIT #define CHAR_BIT 8 #endif typedef union { tu_int all; struct { #if _YUGA_LITTLE_ENDIAN du_int low; du_int high; #else du_int high; du_int low; #endif /* _YUGA_LITTLE_ENDIAN */ }s; } utwords; static inline du_int udiv128by64to64default(du_int u1, du_int u0, du_int v, du_int *r) { const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; const du_int b = (1ULL << (n_udword_bits / 2)); /*Number base (32 bits)*/ du_int un1, un0; /*Norm. dividend LSD's*/ du_int vn1, vn0; /*Norm. divisor digits*/ du_int q1, q0; /* Quotient digits*/ du_int un64, un21, un10; /*Dividend digit pairs*/ du_int rhat; /*A remainder*/ si_int s; /*Shift amount for normalization*/ s = __builtin_clzll(v); if (s > 0) { /* Normalize the divisor.*/ v = v << s; un64 = (u1 << s) | (u0 >> (n_udword_bits - s)); un10 = u0 << s; /*Shift dividend left*/ } else { /* Avoid undefined behavior of (u0 >> 64).*/ un64 = u1; un10 = u0; } /*Break divisor up into two 32-bit digits.*/ vn1 = v >> (n_udword_bits / 2); vn0 = v & 0xFFFFFFFF; /*Break right half of dividend into two digits.*/ un1 = un10 >> (n_udword_bits / 2); un0 = un10 & 0xFFFFFFFF; /*Compute the first quotient digit, q1.*/ q1 = un64 / vn1; rhat = un64 - q1 * vn1; /*q1 has at most error 2. No more than 2 iterations.*/ while (q1 >= b || q1 * vn0 > b * rhat + un1) { q1 = q1 - 1; rhat = rhat + vn1; if (rhat >= b) { break; } } un21 = un64 * b + un1 - q1 * v; /*Compute the second quotient digit.*/ q0 = un21 / vn1; rhat = un21 - q0 * vn1; /*q0 has at most error 2. No more than 2 iterations.*/ while (q0 >= b || q0 * vn0 > b * rhat + un0) { q0 = q0 - 1; rhat = rhat + vn1; if (rhat >= b) { break; } } *r = (un21 * b + un0 - q0 * v) >> s; return q1 * b + q0; } static inline du_int udiv128by64to64(du_int u1, du_int u0, du_int v, du_int *r) { #if defined(__x86_64__) du_int result; __asm__ ("divq %[v]" : "=a" (result), "=d" (*r) : [ v ] "r" (v), "a" (u0), "d" (u1)); return result; #else return udiv128by64to64default(u1, u0, v, r); #endif } tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) { const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT; utwords dividend; dividend.all = a; utwords divisor; divisor.all = b; utwords quotient; utwords remainder; if (divisor.all > dividend.all) { if (rem) { *rem = dividend.all; } return 0; } /* When the divisor fits in 64 bits, we can use an optimized path.*/ if (divisor.s.high == 0) { remainder.s.high = 0; if (dividend.s.high < divisor.s.low) { /*The result fits in 64 bits.*/ quotient.s.low = udiv128by64to64(dividend.s.high, dividend.s.low, divisor.s.low, &remainder.s.low); quotient.s.high = 0; } else { /* First, divide with the high part to get the remainder in dividend.s.high. * After that dividend.s.high < divisor.s.low.*/ quotient.s.high = dividend.s.high / divisor.s.low; dividend.s.high = dividend.s.high % divisor.s.low; quotient.s.low = udiv128by64to64(dividend.s.high, dividend.s.low, divisor.s.low, &remainder.s.low); } if (rem) { *rem = remainder.all; } return quotient.all; } /*0 <= shift <= 63.*/ si_int shift = __builtin_clzll(divisor.s.high) - __builtin_clzll(dividend.s.high); divisor.all <<= shift; quotient.s.high = 0; quotient.s.low = 0; for (; shift >= 0; --shift) { quotient.s.low <<= 1; /* Branch free version of. * if (dividend.all >= divisor.all) * { * dividend.all -= divisor.all; * carry = 1; * } * */ const ti_int s = (ti_int)(divisor.all - dividend.all - 1) >> (n_utword_bits - 1); quotient.s.low |= s & 1; dividend.all -= divisor.all & s; divisor.all >>= 1; } if (rem) { *rem = dividend.all; } return quotient.all; } tu_int __udivti3 (tu_int a, tu_int b) { return __udivmodti4(a, b, 0); }