xref: /qemu/util/int128.c (revision b959822c)
1e9d07601SFrédéric Pétrot /*
2e9d07601SFrédéric Pétrot  * 128-bit division and remainder for compilers not supporting __int128
3e9d07601SFrédéric Pétrot  *
4e9d07601SFrédéric Pétrot  * Copyright (c) 2021 Frédéric Pétrot <frederic.petrot@univ-grenoble-alpes.fr>
5e9d07601SFrédéric Pétrot  *
6e9d07601SFrédéric Pétrot  * Permission is hereby granted, free of charge, to any person obtaining a copy
7e9d07601SFrédéric Pétrot  * of this software and associated documentation files (the "Software"), to deal
8e9d07601SFrédéric Pétrot  * in the Software without restriction, including without limitation the rights
9e9d07601SFrédéric Pétrot  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10e9d07601SFrédéric Pétrot  * copies of the Software, and to permit persons to whom the Software is
11e9d07601SFrédéric Pétrot  * furnished to do so, subject to the following conditions:
12e9d07601SFrédéric Pétrot  *
13e9d07601SFrédéric Pétrot  * The above copyright notice and this permission notice shall be included in
14e9d07601SFrédéric Pétrot  * all copies or substantial portions of the Software.
15e9d07601SFrédéric Pétrot  *
16e9d07601SFrédéric Pétrot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e9d07601SFrédéric Pétrot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e9d07601SFrédéric Pétrot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19e9d07601SFrédéric Pétrot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20e9d07601SFrédéric Pétrot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21e9d07601SFrédéric Pétrot  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22e9d07601SFrédéric Pétrot  * THE SOFTWARE.
23e9d07601SFrédéric Pétrot  */
24e9d07601SFrédéric Pétrot 
25e9d07601SFrédéric Pétrot #include "qemu/osdep.h"
26e9d07601SFrédéric Pétrot #include "qemu/host-utils.h"
27e9d07601SFrédéric Pétrot #include "qemu/int128.h"
28e9d07601SFrédéric Pétrot 
29e9d07601SFrédéric Pétrot #ifndef CONFIG_INT128
30e9d07601SFrédéric Pétrot 
31e9d07601SFrédéric Pétrot /*
32e9d07601SFrédéric Pétrot  * Division and remainder algorithms for 128-bit due to Stefan Kanthak,
33e9d07601SFrédéric Pétrot  * https://skanthak.homepage.t-online.de/integer.html#udivmodti4
34e9d07601SFrédéric Pétrot  * Preconditions:
35e9d07601SFrédéric Pétrot  *     - function should never be called with v equals to 0, it has to
36e9d07601SFrédéric Pétrot  *       be dealt with beforehand
37e9d07601SFrédéric Pétrot  *     - quotien pointer must be valid
38e9d07601SFrédéric Pétrot  */
divrem128(Int128 u,Int128 v,Int128 * q)39e9d07601SFrédéric Pétrot static Int128 divrem128(Int128 u, Int128 v, Int128 *q)
40e9d07601SFrédéric Pétrot {
41e9d07601SFrédéric Pétrot     Int128 qq;
42e9d07601SFrédéric Pétrot     uint64_t hi, lo, tmp;
43e9d07601SFrédéric Pétrot     int s = clz64(v.hi);
44e9d07601SFrédéric Pétrot 
45e9d07601SFrédéric Pétrot     if (s == 64) {
46e9d07601SFrédéric Pétrot         /* we have uu÷0v => let's use divu128 */
47e9d07601SFrédéric Pétrot         hi = u.hi;
48e9d07601SFrédéric Pétrot         lo = u.lo;
49e9d07601SFrédéric Pétrot         tmp = divu128(&lo, &hi, v.lo);
50e9d07601SFrédéric Pétrot         *q = int128_make128(lo, hi);
51e9d07601SFrédéric Pétrot         return int128_make128(tmp, 0);
52e9d07601SFrédéric Pétrot     } else {
53e9d07601SFrédéric Pétrot         hi = int128_gethi(int128_lshift(v, s));
54e9d07601SFrédéric Pétrot 
55e9d07601SFrédéric Pétrot         if (hi > u.hi) {
56e9d07601SFrédéric Pétrot             lo = u.lo;
57e9d07601SFrédéric Pétrot             tmp = u.hi;
58e9d07601SFrédéric Pétrot             divu128(&lo, &tmp, hi);
59e9d07601SFrédéric Pétrot             lo = int128_gethi(int128_lshift(int128_make128(lo, 0), s));
60e9d07601SFrédéric Pétrot         } else { /* prevent overflow */
61e9d07601SFrédéric Pétrot             lo = u.lo;
62e9d07601SFrédéric Pétrot             tmp = u.hi - hi;
63e9d07601SFrédéric Pétrot             divu128(&lo, &tmp, hi);
64e9d07601SFrédéric Pétrot             lo = int128_gethi(int128_lshift(int128_make128(lo, 1), s));
65e9d07601SFrédéric Pétrot         }
66e9d07601SFrédéric Pétrot 
67e9d07601SFrédéric Pétrot         qq = int128_make64(lo);
68e9d07601SFrédéric Pétrot 
69e9d07601SFrédéric Pétrot         tmp = lo * v.hi;
70e9d07601SFrédéric Pétrot         mulu64(&lo, &hi, lo, v.lo);
71e9d07601SFrédéric Pétrot         hi += tmp;
72e9d07601SFrédéric Pétrot 
73e9d07601SFrédéric Pétrot         if (hi < tmp     /* quotient * divisor >= 2**128 > dividend */
74e9d07601SFrédéric Pétrot             || hi > u.hi /* quotient * divisor > dividend */
75e9d07601SFrédéric Pétrot             || (hi == u.hi && lo > u.lo)) {
76e9d07601SFrédéric Pétrot             qq.lo -= 1;
77e9d07601SFrédéric Pétrot             mulu64(&lo, &hi, qq.lo, v.lo);
78e9d07601SFrédéric Pétrot             hi += qq.lo * v.hi;
79e9d07601SFrédéric Pétrot         }
80e9d07601SFrédéric Pétrot 
81e9d07601SFrédéric Pétrot         *q = qq;
82e9d07601SFrédéric Pétrot         u.hi -= hi + (u.lo < lo);
83e9d07601SFrédéric Pétrot         u.lo -= lo;
84e9d07601SFrédéric Pétrot         return u;
85e9d07601SFrédéric Pétrot     }
86e9d07601SFrédéric Pétrot }
87e9d07601SFrédéric Pétrot 
int128_divu(Int128 a,Int128 b)88e9d07601SFrédéric Pétrot Int128 int128_divu(Int128 a, Int128 b)
89e9d07601SFrédéric Pétrot {
90e9d07601SFrédéric Pétrot     Int128 q;
91e9d07601SFrédéric Pétrot     divrem128(a, b, &q);
92e9d07601SFrédéric Pétrot     return q;
93e9d07601SFrédéric Pétrot }
94e9d07601SFrédéric Pétrot 
int128_remu(Int128 a,Int128 b)95e9d07601SFrédéric Pétrot Int128 int128_remu(Int128 a, Int128 b)
96e9d07601SFrédéric Pétrot {
97e9d07601SFrédéric Pétrot     Int128 q;
98e9d07601SFrédéric Pétrot     return divrem128(a, b, &q);
99e9d07601SFrédéric Pétrot }
100e9d07601SFrédéric Pétrot 
int128_divs(Int128 a,Int128 b)101e9d07601SFrédéric Pétrot Int128 int128_divs(Int128 a, Int128 b)
102e9d07601SFrédéric Pétrot {
103e9d07601SFrédéric Pétrot     Int128 q;
104e9d07601SFrédéric Pétrot     bool sgna = !int128_nonneg(a);
105e9d07601SFrédéric Pétrot     bool sgnb = !int128_nonneg(b);
106e9d07601SFrédéric Pétrot 
107e9d07601SFrédéric Pétrot     if (sgna) {
108e9d07601SFrédéric Pétrot         a = int128_neg(a);
109e9d07601SFrédéric Pétrot     }
110e9d07601SFrédéric Pétrot 
111e9d07601SFrédéric Pétrot     if (sgnb) {
112e9d07601SFrédéric Pétrot         b = int128_neg(b);
113e9d07601SFrédéric Pétrot     }
114e9d07601SFrédéric Pétrot 
115e9d07601SFrédéric Pétrot     divrem128(a, b, &q);
116e9d07601SFrédéric Pétrot 
117e9d07601SFrédéric Pétrot     if (sgna != sgnb) {
118e9d07601SFrédéric Pétrot         q = int128_neg(q);
119e9d07601SFrédéric Pétrot     }
120e9d07601SFrédéric Pétrot 
121e9d07601SFrédéric Pétrot     return q;
122e9d07601SFrédéric Pétrot }
123e9d07601SFrédéric Pétrot 
int128_rems(Int128 a,Int128 b)124e9d07601SFrédéric Pétrot Int128 int128_rems(Int128 a, Int128 b)
125e9d07601SFrédéric Pétrot {
126e9d07601SFrédéric Pétrot     Int128 q, r;
127e9d07601SFrédéric Pétrot     bool sgna = !int128_nonneg(a);
128e9d07601SFrédéric Pétrot     bool sgnb = !int128_nonneg(b);
129e9d07601SFrédéric Pétrot 
130e9d07601SFrédéric Pétrot     if (sgna) {
131e9d07601SFrédéric Pétrot         a = int128_neg(a);
132e9d07601SFrédéric Pétrot     }
133e9d07601SFrédéric Pétrot 
134e9d07601SFrédéric Pétrot     if (sgnb) {
135e9d07601SFrédéric Pétrot         b = int128_neg(b);
136e9d07601SFrédéric Pétrot     }
137e9d07601SFrédéric Pétrot 
138e9d07601SFrédéric Pétrot     r = divrem128(a, b, &q);
139e9d07601SFrédéric Pétrot 
140e9d07601SFrédéric Pétrot     if (sgna) {
141e9d07601SFrédéric Pétrot         r = int128_neg(r);
142e9d07601SFrédéric Pétrot     }
143e9d07601SFrédéric Pétrot 
144e9d07601SFrédéric Pétrot     return r;
145e9d07601SFrédéric Pétrot }
146e9d07601SFrédéric Pétrot 
147b959822cSRichard Henderson #elif defined(CONFIG_TCG_INTERPRETER)
148b959822cSRichard Henderson 
int128_divu(Int128 a_s,Int128 b_s)149b959822cSRichard Henderson Int128 int128_divu(Int128 a_s, Int128 b_s)
150b959822cSRichard Henderson {
151b959822cSRichard Henderson     Int128Alias r, a, b;
152b959822cSRichard Henderson 
153b959822cSRichard Henderson     a.s = a_s;
154b959822cSRichard Henderson     b.s = b_s;
155b959822cSRichard Henderson     r.u = a.u / b.u;
156b959822cSRichard Henderson     return r.s;
157b959822cSRichard Henderson }
158b959822cSRichard Henderson 
int128_remu(Int128 a_s,Int128 b_s)159b959822cSRichard Henderson Int128 int128_remu(Int128 a_s, Int128 b_s)
160b959822cSRichard Henderson {
161b959822cSRichard Henderson     Int128Alias r, a, b;
162b959822cSRichard Henderson 
163b959822cSRichard Henderson     a.s = a_s;
164b959822cSRichard Henderson     b.s = b_s;
165b959822cSRichard Henderson     r.u = a.u % b.u;
166b959822cSRichard Henderson     return r.s;
167b959822cSRichard Henderson }
168b959822cSRichard Henderson 
int128_divs(Int128 a_s,Int128 b_s)169b959822cSRichard Henderson Int128 int128_divs(Int128 a_s, Int128 b_s)
170b959822cSRichard Henderson {
171b959822cSRichard Henderson     Int128Alias r, a, b;
172b959822cSRichard Henderson 
173b959822cSRichard Henderson     a.s = a_s;
174b959822cSRichard Henderson     b.s = b_s;
175b959822cSRichard Henderson     r.i = a.i / b.i;
176b959822cSRichard Henderson     return r.s;
177b959822cSRichard Henderson }
178b959822cSRichard Henderson 
int128_rems(Int128 a_s,Int128 b_s)179b959822cSRichard Henderson Int128 int128_rems(Int128 a_s, Int128 b_s)
180b959822cSRichard Henderson {
181b959822cSRichard Henderson     Int128Alias r, a, b;
182b959822cSRichard Henderson 
183b959822cSRichard Henderson     a.s = a_s;
184b959822cSRichard Henderson     b.s = b_s;
185b959822cSRichard Henderson     r.i = a.i % b.i;
186b959822cSRichard Henderson     return r.s;
187b959822cSRichard Henderson }
188b959822cSRichard Henderson 
189e9d07601SFrédéric Pétrot #endif
190