xref: /openbmc/qemu/util/host-utils.c (revision 62c9947f)
1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini  * Utility compute operations used by translated code.
3baacf047SPaolo Bonzini  *
4baacf047SPaolo Bonzini  * Copyright (c) 2003 Fabrice Bellard
5baacf047SPaolo Bonzini  * Copyright (c) 2007 Aurelien Jarno
6baacf047SPaolo Bonzini  *
7baacf047SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
8baacf047SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
9baacf047SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
10baacf047SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11baacf047SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
12baacf047SPaolo Bonzini  * furnished to do so, subject to the following conditions:
13baacf047SPaolo Bonzini  *
14baacf047SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
15baacf047SPaolo Bonzini  * all copies or substantial portions of the Software.
16baacf047SPaolo Bonzini  *
17baacf047SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18baacf047SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19baacf047SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20baacf047SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21baacf047SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22baacf047SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23baacf047SPaolo Bonzini  * THE SOFTWARE.
24baacf047SPaolo Bonzini  */
25baacf047SPaolo Bonzini 
26aafd7584SPeter Maydell #include "qemu/osdep.h"
27baacf047SPaolo Bonzini #include "qemu/host-utils.h"
28baacf047SPaolo Bonzini 
296758c192SJose Ricardo Ziviani #ifndef CONFIG_INT128
30baacf047SPaolo Bonzini /* Long integer helpers */
mul64(uint64_t * plow,uint64_t * phigh,uint64_t a,uint64_t b)31ff7a1eb0SRichard Henderson static inline void mul64(uint64_t *plow, uint64_t *phigh,
32ff7a1eb0SRichard Henderson                          uint64_t a, uint64_t b)
33baacf047SPaolo Bonzini {
34ff7a1eb0SRichard Henderson     typedef union {
35ff7a1eb0SRichard Henderson         uint64_t ll;
36ff7a1eb0SRichard Henderson         struct {
37e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
38ff7a1eb0SRichard Henderson             uint32_t high, low;
39ff7a1eb0SRichard Henderson #else
40ff7a1eb0SRichard Henderson             uint32_t low, high;
41ff7a1eb0SRichard Henderson #endif
42ff7a1eb0SRichard Henderson         } l;
43ff7a1eb0SRichard Henderson     } LL;
44ff7a1eb0SRichard Henderson     LL rl, rm, rn, rh, a0, b0;
45ff7a1eb0SRichard Henderson     uint64_t c;
46baacf047SPaolo Bonzini 
47ff7a1eb0SRichard Henderson     a0.ll = a;
48ff7a1eb0SRichard Henderson     b0.ll = b;
49baacf047SPaolo Bonzini 
50ff7a1eb0SRichard Henderson     rl.ll = (uint64_t)a0.l.low * b0.l.low;
51ff7a1eb0SRichard Henderson     rm.ll = (uint64_t)a0.l.low * b0.l.high;
52ff7a1eb0SRichard Henderson     rn.ll = (uint64_t)a0.l.high * b0.l.low;
53ff7a1eb0SRichard Henderson     rh.ll = (uint64_t)a0.l.high * b0.l.high;
54baacf047SPaolo Bonzini 
55ff7a1eb0SRichard Henderson     c = (uint64_t)rl.l.high + rm.l.low + rn.l.low;
56ff7a1eb0SRichard Henderson     rl.l.high = c;
57ff7a1eb0SRichard Henderson     c >>= 32;
58ff7a1eb0SRichard Henderson     c = c + rm.l.high + rn.l.high + rh.l.low;
59ff7a1eb0SRichard Henderson     rh.l.low = c;
60ff7a1eb0SRichard Henderson     rh.l.high += (uint32_t)(c >> 32);
61baacf047SPaolo Bonzini 
62ff7a1eb0SRichard Henderson     *plow = rl.ll;
63ff7a1eb0SRichard Henderson     *phigh = rh.ll;
64baacf047SPaolo Bonzini }
65baacf047SPaolo Bonzini 
66baacf047SPaolo Bonzini /* Unsigned 64x64 -> 128 multiplication */
mulu64(uint64_t * plow,uint64_t * phigh,uint64_t a,uint64_t b)67baacf047SPaolo Bonzini void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
68baacf047SPaolo Bonzini {
69baacf047SPaolo Bonzini     mul64(plow, phigh, a, b);
70baacf047SPaolo Bonzini }
71baacf047SPaolo Bonzini 
72baacf047SPaolo Bonzini /* Signed 64x64 -> 128 multiplication */
muls64(uint64_t * plow,uint64_t * phigh,int64_t a,int64_t b)73baacf047SPaolo Bonzini void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
74baacf047SPaolo Bonzini {
75ff7a1eb0SRichard Henderson     uint64_t rh;
76baacf047SPaolo Bonzini 
77ff7a1eb0SRichard Henderson     mul64(plow, &rh, a, b);
78ff7a1eb0SRichard Henderson 
79ff7a1eb0SRichard Henderson     /* Adjust for signs.  */
80ff7a1eb0SRichard Henderson     if (b < 0) {
81ff7a1eb0SRichard Henderson         rh -= a;
82baacf047SPaolo Bonzini     }
83ff7a1eb0SRichard Henderson     if (a < 0) {
84ff7a1eb0SRichard Henderson         rh -= b;
85ff7a1eb0SRichard Henderson     }
86ff7a1eb0SRichard Henderson     *phigh = rh;
87baacf047SPaolo Bonzini }
8898d1eb27STom Musta 
899276a31cSLuis Pires /*
9040f3e79aSLuis Pires  * Unsigned 128-by-64 division.
9140f3e79aSLuis Pires  * Returns the remainder.
9240f3e79aSLuis Pires  * Returns quotient via plow and phigh.
9340f3e79aSLuis Pires  * Also returns the remainder via the function return value.
949276a31cSLuis Pires  */
divu128(uint64_t * plow,uint64_t * phigh,uint64_t divisor)9540f3e79aSLuis Pires uint64_t divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor)
9698d1eb27STom Musta {
9798d1eb27STom Musta     uint64_t dhi = *phigh;
9898d1eb27STom Musta     uint64_t dlo = *plow;
9940f3e79aSLuis Pires     uint64_t rem, dhighest;
10040f3e79aSLuis Pires     int sh;
10198d1eb27STom Musta 
1029276a31cSLuis Pires     if (divisor == 0 || dhi == 0) {
10398d1eb27STom Musta         *plow  = dlo / divisor;
10440f3e79aSLuis Pires         *phigh = 0;
10540f3e79aSLuis Pires         return dlo % divisor;
10698d1eb27STom Musta     } else {
10740f3e79aSLuis Pires         sh = clz64(divisor);
10898d1eb27STom Musta 
10940f3e79aSLuis Pires         if (dhi < divisor) {
11040f3e79aSLuis Pires             if (sh != 0) {
11140f3e79aSLuis Pires                 /* normalize the divisor, shifting the dividend accordingly */
11240f3e79aSLuis Pires                 divisor <<= sh;
11340f3e79aSLuis Pires                 dhi = (dhi << sh) | (dlo >> (64 - sh));
11440f3e79aSLuis Pires                 dlo <<= sh;
11540f3e79aSLuis Pires             }
11640f3e79aSLuis Pires 
11740f3e79aSLuis Pires             *phigh = 0;
11840f3e79aSLuis Pires             *plow = udiv_qrnnd(&rem, dhi, dlo, divisor);
11940f3e79aSLuis Pires         } else {
12040f3e79aSLuis Pires             if (sh != 0) {
12140f3e79aSLuis Pires                 /* normalize the divisor, shifting the dividend accordingly */
12240f3e79aSLuis Pires                 divisor <<= sh;
12340f3e79aSLuis Pires                 dhighest = dhi >> (64 - sh);
12440f3e79aSLuis Pires                 dhi = (dhi << sh) | (dlo >> (64 - sh));
12540f3e79aSLuis Pires                 dlo <<= sh;
12640f3e79aSLuis Pires 
12740f3e79aSLuis Pires                 *phigh = udiv_qrnnd(&dhi, dhighest, dhi, divisor);
12840f3e79aSLuis Pires             } else {
12940f3e79aSLuis Pires                 /**
13040f3e79aSLuis Pires                  * dhi >= divisor
13140f3e79aSLuis Pires                  * Since the MSB of divisor is set (sh == 0),
13240f3e79aSLuis Pires                  * (dhi - divisor) < divisor
13340f3e79aSLuis Pires                  *
13440f3e79aSLuis Pires                  * Thus, the high part of the quotient is 1, and we can
13540f3e79aSLuis Pires                  * calculate the low part with a single call to udiv_qrnnd
13640f3e79aSLuis Pires                  * after subtracting divisor from dhi
13740f3e79aSLuis Pires                  */
13898d1eb27STom Musta                 dhi -= divisor;
13940f3e79aSLuis Pires                 *phigh = 1;
14098d1eb27STom Musta             }
14198d1eb27STom Musta 
14240f3e79aSLuis Pires             *plow = udiv_qrnnd(&rem, dhi, dlo, divisor);
14340f3e79aSLuis Pires         }
14440f3e79aSLuis Pires 
14540f3e79aSLuis Pires         /*
14640f3e79aSLuis Pires          * since the dividend/divisor might have been normalized,
14740f3e79aSLuis Pires          * the remainder might also have to be shifted back
14840f3e79aSLuis Pires          */
14940f3e79aSLuis Pires         return rem >> sh;
15098d1eb27STom Musta     }
15198d1eb27STom Musta }
152e44259b6STom Musta 
1539276a31cSLuis Pires /*
15440f3e79aSLuis Pires  * Signed 128-by-64 division.
15540f3e79aSLuis Pires  * Returns quotient via plow and phigh.
15640f3e79aSLuis Pires  * Also returns the remainder via the function return value.
1579276a31cSLuis Pires  */
divs128(uint64_t * plow,int64_t * phigh,int64_t divisor)15840f3e79aSLuis Pires int64_t divs128(uint64_t *plow, int64_t *phigh, int64_t divisor)
159e44259b6STom Musta {
16040f3e79aSLuis Pires     bool neg_quotient = false, neg_remainder = false;
16140f3e79aSLuis Pires     uint64_t unsig_hi = *phigh, unsig_lo = *plow;
16240f3e79aSLuis Pires     uint64_t rem;
163e44259b6STom Musta 
16440f3e79aSLuis Pires     if (*phigh < 0) {
16540f3e79aSLuis Pires         neg_quotient = !neg_quotient;
16640f3e79aSLuis Pires         neg_remainder = !neg_remainder;
16740f3e79aSLuis Pires 
16840f3e79aSLuis Pires         if (unsig_lo == 0) {
16940f3e79aSLuis Pires             unsig_hi = -unsig_hi;
170e44259b6STom Musta         } else {
17140f3e79aSLuis Pires             unsig_hi = ~unsig_hi;
17240f3e79aSLuis Pires             unsig_lo = -unsig_lo;
173e44259b6STom Musta         }
174e44259b6STom Musta     }
175e44259b6STom Musta 
17640f3e79aSLuis Pires     if (divisor < 0) {
17740f3e79aSLuis Pires         neg_quotient = !neg_quotient;
17840f3e79aSLuis Pires 
17940f3e79aSLuis Pires         divisor = -divisor;
180e44259b6STom Musta     }
181e44259b6STom Musta 
18240f3e79aSLuis Pires     rem = divu128(&unsig_lo, &unsig_hi, (uint64_t)divisor);
183e44259b6STom Musta 
18440f3e79aSLuis Pires     if (neg_quotient) {
18540f3e79aSLuis Pires         if (unsig_lo == 0) {
18640f3e79aSLuis Pires             *phigh = -unsig_hi;
18740f3e79aSLuis Pires             *plow = 0;
18840f3e79aSLuis Pires         } else {
18940f3e79aSLuis Pires             *phigh = ~unsig_hi;
19040f3e79aSLuis Pires             *plow = -unsig_lo;
19140f3e79aSLuis Pires         }
19240f3e79aSLuis Pires     } else {
19340f3e79aSLuis Pires         *phigh = unsig_hi;
19440f3e79aSLuis Pires         *plow = unsig_lo;
19540f3e79aSLuis Pires     }
19640f3e79aSLuis Pires 
19740f3e79aSLuis Pires     if (neg_remainder) {
19840f3e79aSLuis Pires         return -rem;
19940f3e79aSLuis Pires     } else {
20040f3e79aSLuis Pires         return rem;
201e44259b6STom Musta     }
202e44259b6STom Musta }
2036758c192SJose Ricardo Ziviani #endif
204e44259b6STom Musta 
205f539fbe3SJose Ricardo Ziviani /**
206f539fbe3SJose Ricardo Ziviani  * urshift - 128-bit Unsigned Right Shift.
207f539fbe3SJose Ricardo Ziviani  * @plow: in/out - lower 64-bit integer.
208f539fbe3SJose Ricardo Ziviani  * @phigh: in/out - higher 64-bit integer.
209f539fbe3SJose Ricardo Ziviani  * @shift: in - bytes to shift, between 0 and 127.
210f539fbe3SJose Ricardo Ziviani  *
211f539fbe3SJose Ricardo Ziviani  * Result is zero-extended and stored in plow/phigh, which are
212f539fbe3SJose Ricardo Ziviani  * input/output variables. Shift values outside the range will
213f539fbe3SJose Ricardo Ziviani  * be mod to 128. In other words, the caller is responsible to
214f539fbe3SJose Ricardo Ziviani  * verify/assert both the shift range and plow/phigh pointers.
215f539fbe3SJose Ricardo Ziviani  */
urshift(uint64_t * plow,uint64_t * phigh,int32_t shift)216f539fbe3SJose Ricardo Ziviani void urshift(uint64_t *plow, uint64_t *phigh, int32_t shift)
217f539fbe3SJose Ricardo Ziviani {
218f539fbe3SJose Ricardo Ziviani     shift &= 127;
219f539fbe3SJose Ricardo Ziviani     if (shift == 0) {
220f539fbe3SJose Ricardo Ziviani         return;
221f539fbe3SJose Ricardo Ziviani     }
222f539fbe3SJose Ricardo Ziviani 
223f539fbe3SJose Ricardo Ziviani     uint64_t h = *phigh >> (shift & 63);
224f539fbe3SJose Ricardo Ziviani     if (shift >= 64) {
225f539fbe3SJose Ricardo Ziviani         *plow = h;
226f539fbe3SJose Ricardo Ziviani         *phigh = 0;
227f539fbe3SJose Ricardo Ziviani     } else {
228f539fbe3SJose Ricardo Ziviani         *plow = (*plow >> (shift & 63)) | (*phigh << (64 - (shift & 63)));
229f539fbe3SJose Ricardo Ziviani         *phigh = h;
230f539fbe3SJose Ricardo Ziviani     }
231f539fbe3SJose Ricardo Ziviani }
232f539fbe3SJose Ricardo Ziviani 
233f539fbe3SJose Ricardo Ziviani /**
234f539fbe3SJose Ricardo Ziviani  * ulshift - 128-bit Unsigned Left Shift.
235f539fbe3SJose Ricardo Ziviani  * @plow: in/out - lower 64-bit integer.
236f539fbe3SJose Ricardo Ziviani  * @phigh: in/out - higher 64-bit integer.
237f539fbe3SJose Ricardo Ziviani  * @shift: in - bytes to shift, between 0 and 127.
238f539fbe3SJose Ricardo Ziviani  * @overflow: out - true if any 1-bit is shifted out.
239f539fbe3SJose Ricardo Ziviani  *
240f539fbe3SJose Ricardo Ziviani  * Result is zero-extended and stored in plow/phigh, which are
241f539fbe3SJose Ricardo Ziviani  * input/output variables. Shift values outside the range will
242f539fbe3SJose Ricardo Ziviani  * be mod to 128. In other words, the caller is responsible to
243f539fbe3SJose Ricardo Ziviani  * verify/assert both the shift range and plow/phigh pointers.
244f539fbe3SJose Ricardo Ziviani  */
ulshift(uint64_t * plow,uint64_t * phigh,int32_t shift,bool * overflow)245f539fbe3SJose Ricardo Ziviani void ulshift(uint64_t *plow, uint64_t *phigh, int32_t shift, bool *overflow)
246f539fbe3SJose Ricardo Ziviani {
247f539fbe3SJose Ricardo Ziviani     uint64_t low = *plow;
248f539fbe3SJose Ricardo Ziviani     uint64_t high = *phigh;
249f539fbe3SJose Ricardo Ziviani 
250f539fbe3SJose Ricardo Ziviani     shift &= 127;
251f539fbe3SJose Ricardo Ziviani     if (shift == 0) {
252f539fbe3SJose Ricardo Ziviani         return;
253f539fbe3SJose Ricardo Ziviani     }
254f539fbe3SJose Ricardo Ziviani 
255f539fbe3SJose Ricardo Ziviani     /* check if any bit will be shifted out */
256f539fbe3SJose Ricardo Ziviani     urshift(&low, &high, 128 - shift);
257f539fbe3SJose Ricardo Ziviani     if (low | high) {
258f539fbe3SJose Ricardo Ziviani         *overflow = true;
259f539fbe3SJose Ricardo Ziviani     }
260f539fbe3SJose Ricardo Ziviani 
261f539fbe3SJose Ricardo Ziviani     if (shift >= 64) {
262f539fbe3SJose Ricardo Ziviani         *phigh = *plow << (shift & 63);
263f539fbe3SJose Ricardo Ziviani         *plow = 0;
264f539fbe3SJose Ricardo Ziviani     } else {
265f539fbe3SJose Ricardo Ziviani         *phigh = (*plow >> (64 - (shift & 63))) | (*phigh << (shift & 63));
266f539fbe3SJose Ricardo Ziviani         *plow = *plow << shift;
267f539fbe3SJose Ricardo Ziviani     }
268f539fbe3SJose Ricardo Ziviani }
2694724bbd2SLucas Mateus Castro (alqotel) 
2704724bbd2SLucas Mateus Castro (alqotel) /*
2714724bbd2SLucas Mateus Castro (alqotel)  * Unsigned 256-by-128 division.
2724724bbd2SLucas Mateus Castro (alqotel)  * Returns the remainder via r.
2734724bbd2SLucas Mateus Castro (alqotel)  * Returns lower 128 bit of quotient.
2744724bbd2SLucas Mateus Castro (alqotel)  * Needs a normalized divisor (most significant bit set to 1).
2754724bbd2SLucas Mateus Castro (alqotel)  *
2764724bbd2SLucas Mateus Castro (alqotel)  * Adapted from include/qemu/host-utils.h udiv_qrnnd,
2774724bbd2SLucas Mateus Castro (alqotel)  * from the GNU Multi Precision Library - longlong.h __udiv_qrnnd
2784724bbd2SLucas Mateus Castro (alqotel)  * (https://gmplib.org/repo/gmp/file/tip/longlong.h)
2794724bbd2SLucas Mateus Castro (alqotel)  *
2804724bbd2SLucas Mateus Castro (alqotel)  * Licensed under the GPLv2/LGPLv3
2814724bbd2SLucas Mateus Castro (alqotel)  */
udiv256_qrnnd(Int128 * r,Int128 n1,Int128 n0,Int128 d)2824724bbd2SLucas Mateus Castro (alqotel) static Int128 udiv256_qrnnd(Int128 *r, Int128 n1, Int128 n0, Int128 d)
2834724bbd2SLucas Mateus Castro (alqotel) {
2844724bbd2SLucas Mateus Castro (alqotel)     Int128 d0, d1, q0, q1, r1, r0, m;
2854724bbd2SLucas Mateus Castro (alqotel)     uint64_t mp0, mp1;
2864724bbd2SLucas Mateus Castro (alqotel) 
2874724bbd2SLucas Mateus Castro (alqotel)     d0 = int128_make64(int128_getlo(d));
2884724bbd2SLucas Mateus Castro (alqotel)     d1 = int128_make64(int128_gethi(d));
2894724bbd2SLucas Mateus Castro (alqotel) 
2904724bbd2SLucas Mateus Castro (alqotel)     r1 = int128_remu(n1, d1);
2914724bbd2SLucas Mateus Castro (alqotel)     q1 = int128_divu(n1, d1);
2924724bbd2SLucas Mateus Castro (alqotel)     mp0 = int128_getlo(q1);
2934724bbd2SLucas Mateus Castro (alqotel)     mp1 = int128_gethi(q1);
2944724bbd2SLucas Mateus Castro (alqotel)     mulu128(&mp0, &mp1, int128_getlo(d0));
2954724bbd2SLucas Mateus Castro (alqotel)     m = int128_make128(mp0, mp1);
2964724bbd2SLucas Mateus Castro (alqotel)     r1 = int128_make128(int128_gethi(n0), int128_getlo(r1));
2974724bbd2SLucas Mateus Castro (alqotel)     if (int128_ult(r1, m)) {
2984724bbd2SLucas Mateus Castro (alqotel)         q1 = int128_sub(q1, int128_one());
2994724bbd2SLucas Mateus Castro (alqotel)         r1 = int128_add(r1, d);
3004724bbd2SLucas Mateus Castro (alqotel)         if (int128_uge(r1, d)) {
3014724bbd2SLucas Mateus Castro (alqotel)             if (int128_ult(r1, m)) {
3024724bbd2SLucas Mateus Castro (alqotel)                 q1 = int128_sub(q1, int128_one());
3034724bbd2SLucas Mateus Castro (alqotel)                 r1 = int128_add(r1, d);
3044724bbd2SLucas Mateus Castro (alqotel)             }
3054724bbd2SLucas Mateus Castro (alqotel)         }
3064724bbd2SLucas Mateus Castro (alqotel)     }
3074724bbd2SLucas Mateus Castro (alqotel)     r1 = int128_sub(r1, m);
3084724bbd2SLucas Mateus Castro (alqotel) 
3094724bbd2SLucas Mateus Castro (alqotel)     r0 = int128_remu(r1, d1);
3104724bbd2SLucas Mateus Castro (alqotel)     q0 = int128_divu(r1, d1);
3114724bbd2SLucas Mateus Castro (alqotel)     mp0 = int128_getlo(q0);
3124724bbd2SLucas Mateus Castro (alqotel)     mp1 = int128_gethi(q0);
3134724bbd2SLucas Mateus Castro (alqotel)     mulu128(&mp0, &mp1, int128_getlo(d0));
3144724bbd2SLucas Mateus Castro (alqotel)     m = int128_make128(mp0, mp1);
3154724bbd2SLucas Mateus Castro (alqotel)     r0 = int128_make128(int128_getlo(n0), int128_getlo(r0));
3164724bbd2SLucas Mateus Castro (alqotel)     if (int128_ult(r0, m)) {
3174724bbd2SLucas Mateus Castro (alqotel)         q0 = int128_sub(q0, int128_one());
3184724bbd2SLucas Mateus Castro (alqotel)         r0 = int128_add(r0, d);
3194724bbd2SLucas Mateus Castro (alqotel)         if (int128_uge(r0, d)) {
3204724bbd2SLucas Mateus Castro (alqotel)             if (int128_ult(r0, m)) {
3214724bbd2SLucas Mateus Castro (alqotel)                 q0 = int128_sub(q0, int128_one());
3224724bbd2SLucas Mateus Castro (alqotel)                 r0 = int128_add(r0, d);
3234724bbd2SLucas Mateus Castro (alqotel)             }
3244724bbd2SLucas Mateus Castro (alqotel)         }
3254724bbd2SLucas Mateus Castro (alqotel)     }
3264724bbd2SLucas Mateus Castro (alqotel)     r0 = int128_sub(r0, m);
3274724bbd2SLucas Mateus Castro (alqotel) 
3284724bbd2SLucas Mateus Castro (alqotel)     *r = r0;
3294724bbd2SLucas Mateus Castro (alqotel)     return int128_or(int128_lshift(q1, 64), q0);
3304724bbd2SLucas Mateus Castro (alqotel) }
3314724bbd2SLucas Mateus Castro (alqotel) 
3324724bbd2SLucas Mateus Castro (alqotel) /*
3334724bbd2SLucas Mateus Castro (alqotel)  * Unsigned 256-by-128 division.
3344724bbd2SLucas Mateus Castro (alqotel)  * Returns the remainder.
3354724bbd2SLucas Mateus Castro (alqotel)  * Returns quotient via plow and phigh.
3364724bbd2SLucas Mateus Castro (alqotel)  * Also returns the remainder via the function return value.
3374724bbd2SLucas Mateus Castro (alqotel)  */
divu256(Int128 * plow,Int128 * phigh,Int128 divisor)3384724bbd2SLucas Mateus Castro (alqotel) Int128 divu256(Int128 *plow, Int128 *phigh, Int128 divisor)
3394724bbd2SLucas Mateus Castro (alqotel) {
3404724bbd2SLucas Mateus Castro (alqotel)     Int128 dhi = *phigh;
3414724bbd2SLucas Mateus Castro (alqotel)     Int128 dlo = *plow;
3424724bbd2SLucas Mateus Castro (alqotel)     Int128 rem, dhighest;
3434724bbd2SLucas Mateus Castro (alqotel)     int sh;
3444724bbd2SLucas Mateus Castro (alqotel) 
3454724bbd2SLucas Mateus Castro (alqotel)     if (!int128_nz(divisor) || !int128_nz(dhi)) {
3464724bbd2SLucas Mateus Castro (alqotel)         *plow  = int128_divu(dlo, divisor);
3474724bbd2SLucas Mateus Castro (alqotel)         *phigh = int128_zero();
3484724bbd2SLucas Mateus Castro (alqotel)         return int128_remu(dlo, divisor);
3494724bbd2SLucas Mateus Castro (alqotel)     } else {
3504724bbd2SLucas Mateus Castro (alqotel)         sh = clz128(divisor);
3514724bbd2SLucas Mateus Castro (alqotel) 
3524724bbd2SLucas Mateus Castro (alqotel)         if (int128_ult(dhi, divisor)) {
3534724bbd2SLucas Mateus Castro (alqotel)             if (sh != 0) {
3544724bbd2SLucas Mateus Castro (alqotel)                 /* normalize the divisor, shifting the dividend accordingly */
3554724bbd2SLucas Mateus Castro (alqotel)                 divisor = int128_lshift(divisor, sh);
3564724bbd2SLucas Mateus Castro (alqotel)                 dhi = int128_or(int128_lshift(dhi, sh),
3574724bbd2SLucas Mateus Castro (alqotel)                                 int128_urshift(dlo, (128 - sh)));
3584724bbd2SLucas Mateus Castro (alqotel)                 dlo = int128_lshift(dlo, sh);
3594724bbd2SLucas Mateus Castro (alqotel)             }
3604724bbd2SLucas Mateus Castro (alqotel) 
3614724bbd2SLucas Mateus Castro (alqotel)             *phigh = int128_zero();
3624724bbd2SLucas Mateus Castro (alqotel)             *plow = udiv256_qrnnd(&rem, dhi, dlo, divisor);
3634724bbd2SLucas Mateus Castro (alqotel)         } else {
3644724bbd2SLucas Mateus Castro (alqotel)             if (sh != 0) {
3654724bbd2SLucas Mateus Castro (alqotel)                 /* normalize the divisor, shifting the dividend accordingly */
3664724bbd2SLucas Mateus Castro (alqotel)                 divisor = int128_lshift(divisor, sh);
3674724bbd2SLucas Mateus Castro (alqotel)                 dhighest = int128_rshift(dhi, (128 - sh));
3684724bbd2SLucas Mateus Castro (alqotel)                 dhi = int128_or(int128_lshift(dhi, sh),
3694724bbd2SLucas Mateus Castro (alqotel)                                 int128_urshift(dlo, (128 - sh)));
3704724bbd2SLucas Mateus Castro (alqotel)                 dlo = int128_lshift(dlo, sh);
3714724bbd2SLucas Mateus Castro (alqotel) 
3724724bbd2SLucas Mateus Castro (alqotel)                 *phigh = udiv256_qrnnd(&dhi, dhighest, dhi, divisor);
3734724bbd2SLucas Mateus Castro (alqotel)             } else {
3744724bbd2SLucas Mateus Castro (alqotel)                 /*
3754724bbd2SLucas Mateus Castro (alqotel)                  * dhi >= divisor
3764724bbd2SLucas Mateus Castro (alqotel)                  * Since the MSB of divisor is set (sh == 0),
3774724bbd2SLucas Mateus Castro (alqotel)                  * (dhi - divisor) < divisor
3784724bbd2SLucas Mateus Castro (alqotel)                  *
3794724bbd2SLucas Mateus Castro (alqotel)                  * Thus, the high part of the quotient is 1, and we can
3804724bbd2SLucas Mateus Castro (alqotel)                  * calculate the low part with a single call to udiv_qrnnd
3814724bbd2SLucas Mateus Castro (alqotel)                  * after subtracting divisor from dhi
3824724bbd2SLucas Mateus Castro (alqotel)                  */
3834724bbd2SLucas Mateus Castro (alqotel)                 dhi = int128_sub(dhi, divisor);
3844724bbd2SLucas Mateus Castro (alqotel)                 *phigh = int128_one();
3854724bbd2SLucas Mateus Castro (alqotel)             }
3864724bbd2SLucas Mateus Castro (alqotel) 
3874724bbd2SLucas Mateus Castro (alqotel)             *plow = udiv256_qrnnd(&rem, dhi, dlo, divisor);
3884724bbd2SLucas Mateus Castro (alqotel)         }
3894724bbd2SLucas Mateus Castro (alqotel) 
3904724bbd2SLucas Mateus Castro (alqotel)         /*
3914724bbd2SLucas Mateus Castro (alqotel)          * since the dividend/divisor might have been normalized,
3924724bbd2SLucas Mateus Castro (alqotel)          * the remainder might also have to be shifted back
3934724bbd2SLucas Mateus Castro (alqotel)          */
3944724bbd2SLucas Mateus Castro (alqotel)         rem = int128_urshift(rem, sh);
3954724bbd2SLucas Mateus Castro (alqotel)         return rem;
3964724bbd2SLucas Mateus Castro (alqotel)     }
3974724bbd2SLucas Mateus Castro (alqotel) }
398*62c9947fSLucas Mateus Castro (alqotel) 
399*62c9947fSLucas Mateus Castro (alqotel) /*
400*62c9947fSLucas Mateus Castro (alqotel)  * Signed 256-by-128 division.
401*62c9947fSLucas Mateus Castro (alqotel)  * Returns quotient via plow and phigh.
402*62c9947fSLucas Mateus Castro (alqotel)  * Also returns the remainder via the function return value.
403*62c9947fSLucas Mateus Castro (alqotel)  */
divs256(Int128 * plow,Int128 * phigh,Int128 divisor)404*62c9947fSLucas Mateus Castro (alqotel) Int128 divs256(Int128 *plow, Int128 *phigh, Int128 divisor)
405*62c9947fSLucas Mateus Castro (alqotel) {
406*62c9947fSLucas Mateus Castro (alqotel)     bool neg_quotient = false, neg_remainder = false;
407*62c9947fSLucas Mateus Castro (alqotel)     Int128 unsig_hi = *phigh, unsig_lo = *plow;
408*62c9947fSLucas Mateus Castro (alqotel)     Int128 rem;
409*62c9947fSLucas Mateus Castro (alqotel) 
410*62c9947fSLucas Mateus Castro (alqotel)     if (!int128_nonneg(*phigh)) {
411*62c9947fSLucas Mateus Castro (alqotel)         neg_quotient = !neg_quotient;
412*62c9947fSLucas Mateus Castro (alqotel)         neg_remainder = !neg_remainder;
413*62c9947fSLucas Mateus Castro (alqotel) 
414*62c9947fSLucas Mateus Castro (alqotel)         if (!int128_nz(unsig_lo)) {
415*62c9947fSLucas Mateus Castro (alqotel)             unsig_hi = int128_neg(unsig_hi);
416*62c9947fSLucas Mateus Castro (alqotel)         } else {
417*62c9947fSLucas Mateus Castro (alqotel)             unsig_hi = int128_not(unsig_hi);
418*62c9947fSLucas Mateus Castro (alqotel)             unsig_lo = int128_neg(unsig_lo);
419*62c9947fSLucas Mateus Castro (alqotel)         }
420*62c9947fSLucas Mateus Castro (alqotel)     }
421*62c9947fSLucas Mateus Castro (alqotel) 
422*62c9947fSLucas Mateus Castro (alqotel)     if (!int128_nonneg(divisor)) {
423*62c9947fSLucas Mateus Castro (alqotel)         neg_quotient = !neg_quotient;
424*62c9947fSLucas Mateus Castro (alqotel) 
425*62c9947fSLucas Mateus Castro (alqotel)         divisor = int128_neg(divisor);
426*62c9947fSLucas Mateus Castro (alqotel)     }
427*62c9947fSLucas Mateus Castro (alqotel) 
428*62c9947fSLucas Mateus Castro (alqotel)     rem = divu256(&unsig_lo, &unsig_hi, divisor);
429*62c9947fSLucas Mateus Castro (alqotel) 
430*62c9947fSLucas Mateus Castro (alqotel)     if (neg_quotient) {
431*62c9947fSLucas Mateus Castro (alqotel)         if (!int128_nz(unsig_lo)) {
432*62c9947fSLucas Mateus Castro (alqotel)             *phigh = int128_neg(unsig_hi);
433*62c9947fSLucas Mateus Castro (alqotel)             *plow = int128_zero();
434*62c9947fSLucas Mateus Castro (alqotel)         } else {
435*62c9947fSLucas Mateus Castro (alqotel)             *phigh = int128_not(unsig_hi);
436*62c9947fSLucas Mateus Castro (alqotel)             *plow = int128_neg(unsig_lo);
437*62c9947fSLucas Mateus Castro (alqotel)         }
438*62c9947fSLucas Mateus Castro (alqotel)     } else {
439*62c9947fSLucas Mateus Castro (alqotel)         *phigh = unsig_hi;
440*62c9947fSLucas Mateus Castro (alqotel)         *plow = unsig_lo;
441*62c9947fSLucas Mateus Castro (alqotel)     }
442*62c9947fSLucas Mateus Castro (alqotel) 
443*62c9947fSLucas Mateus Castro (alqotel)     if (neg_remainder) {
444*62c9947fSLucas Mateus Castro (alqotel)         return int128_neg(rem);
445*62c9947fSLucas Mateus Castro (alqotel)     } else {
446*62c9947fSLucas Mateus Castro (alqotel)         return rem;
447*62c9947fSLucas Mateus Castro (alqotel)     }
448*62c9947fSLucas Mateus Castro (alqotel) }
449