xref: /netbsd-src/sys/external/bsd/compiler_rt/dist/lib/builtins/udivmodti4.c (revision f7f78b3373aafafa211473d7733a8806c0e402c0)
1156cd587Sjoerg /* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===
2156cd587Sjoerg  *
3156cd587Sjoerg  *                    The LLVM Compiler Infrastructure
4156cd587Sjoerg  *
5156cd587Sjoerg  * This file is dual licensed under the MIT and the University of Illinois Open
6156cd587Sjoerg  * Source Licenses. See LICENSE.TXT for details.
7156cd587Sjoerg  *
8156cd587Sjoerg  * ===----------------------------------------------------------------------===
9156cd587Sjoerg  *
10156cd587Sjoerg  * This file implements __udivmodti4 for the compiler_rt library.
11156cd587Sjoerg  *
12156cd587Sjoerg  * ===----------------------------------------------------------------------===
13156cd587Sjoerg  */
14156cd587Sjoerg 
15156cd587Sjoerg #include "int_lib.h"
16156cd587Sjoerg 
17156cd587Sjoerg #ifdef CRT_HAS_128BIT
18156cd587Sjoerg 
19156cd587Sjoerg /* Effects: if rem != 0, *rem = a % b
20156cd587Sjoerg  * Returns: a / b
21156cd587Sjoerg  */
22156cd587Sjoerg 
23156cd587Sjoerg /* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
24156cd587Sjoerg 
25*f7f78b33Sjoerg COMPILER_RT_ABI tu_int
__udivmodti4(tu_int a,tu_int b,tu_int * rem)26156cd587Sjoerg __udivmodti4(tu_int a, tu_int b, tu_int* rem)
27156cd587Sjoerg {
28156cd587Sjoerg     const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
29156cd587Sjoerg     const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
30156cd587Sjoerg     utwords n;
31156cd587Sjoerg     n.all = a;
32156cd587Sjoerg     utwords d;
33156cd587Sjoerg     d.all = b;
34156cd587Sjoerg     utwords q;
35156cd587Sjoerg     utwords r;
36156cd587Sjoerg     unsigned sr;
37156cd587Sjoerg     /* special cases, X is unknown, K != 0 */
38156cd587Sjoerg     if (n.s.high == 0)
39156cd587Sjoerg     {
40156cd587Sjoerg         if (d.s.high == 0)
41156cd587Sjoerg         {
42156cd587Sjoerg             /* 0 X
43156cd587Sjoerg              * ---
44156cd587Sjoerg              * 0 X
45156cd587Sjoerg              */
46156cd587Sjoerg             if (rem)
47156cd587Sjoerg                 *rem = n.s.low % d.s.low;
48156cd587Sjoerg             return n.s.low / d.s.low;
49156cd587Sjoerg         }
50156cd587Sjoerg         /* 0 X
51156cd587Sjoerg          * ---
52156cd587Sjoerg          * K X
53156cd587Sjoerg          */
54156cd587Sjoerg         if (rem)
55156cd587Sjoerg             *rem = n.s.low;
56156cd587Sjoerg         return 0;
57156cd587Sjoerg     }
58156cd587Sjoerg     /* n.s.high != 0 */
59156cd587Sjoerg     if (d.s.low == 0)
60156cd587Sjoerg     {
61156cd587Sjoerg         if (d.s.high == 0)
62156cd587Sjoerg         {
63156cd587Sjoerg             /* K X
64156cd587Sjoerg              * ---
65156cd587Sjoerg              * 0 0
66156cd587Sjoerg              */
67156cd587Sjoerg             if (rem)
68156cd587Sjoerg                 *rem = n.s.high % d.s.low;
69156cd587Sjoerg             return n.s.high / d.s.low;
70156cd587Sjoerg         }
71156cd587Sjoerg         /* d.s.high != 0 */
72156cd587Sjoerg         if (n.s.low == 0)
73156cd587Sjoerg         {
74156cd587Sjoerg             /* K 0
75156cd587Sjoerg              * ---
76156cd587Sjoerg              * K 0
77156cd587Sjoerg              */
78156cd587Sjoerg             if (rem)
79156cd587Sjoerg             {
80156cd587Sjoerg                 r.s.high = n.s.high % d.s.high;
81156cd587Sjoerg                 r.s.low = 0;
82156cd587Sjoerg                 *rem = r.all;
83156cd587Sjoerg             }
84156cd587Sjoerg             return n.s.high / d.s.high;
85156cd587Sjoerg         }
86156cd587Sjoerg         /* K K
87156cd587Sjoerg          * ---
88156cd587Sjoerg          * K 0
89156cd587Sjoerg          */
90156cd587Sjoerg         if ((d.s.high & (d.s.high - 1)) == 0)     /* if d is a power of 2 */
91156cd587Sjoerg         {
92156cd587Sjoerg             if (rem)
93156cd587Sjoerg             {
94156cd587Sjoerg                 r.s.low = n.s.low;
95156cd587Sjoerg                 r.s.high = n.s.high & (d.s.high - 1);
96156cd587Sjoerg                 *rem = r.all;
97156cd587Sjoerg             }
98156cd587Sjoerg             return n.s.high >> __builtin_ctzll(d.s.high);
99156cd587Sjoerg         }
100156cd587Sjoerg         /* K K
101156cd587Sjoerg          * ---
102156cd587Sjoerg          * K 0
103156cd587Sjoerg          */
104156cd587Sjoerg         sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
105156cd587Sjoerg         /* 0 <= sr <= n_udword_bits - 2 or sr large */
106156cd587Sjoerg         if (sr > n_udword_bits - 2)
107156cd587Sjoerg         {
108156cd587Sjoerg            if (rem)
109156cd587Sjoerg                 *rem = n.all;
110156cd587Sjoerg             return 0;
111156cd587Sjoerg         }
112156cd587Sjoerg         ++sr;
113156cd587Sjoerg         /* 1 <= sr <= n_udword_bits - 1 */
114156cd587Sjoerg         /* q.all = n.all << (n_utword_bits - sr); */
115156cd587Sjoerg         q.s.low = 0;
116156cd587Sjoerg         q.s.high = n.s.low << (n_udword_bits - sr);
117156cd587Sjoerg         /* r.all = n.all >> sr; */
118156cd587Sjoerg         r.s.high = n.s.high >> sr;
119156cd587Sjoerg         r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
120156cd587Sjoerg     }
121156cd587Sjoerg     else  /* d.s.low != 0 */
122156cd587Sjoerg     {
123156cd587Sjoerg         if (d.s.high == 0)
124156cd587Sjoerg         {
125156cd587Sjoerg             /* K X
126156cd587Sjoerg              * ---
127156cd587Sjoerg              * 0 K
128156cd587Sjoerg              */
129156cd587Sjoerg             if ((d.s.low & (d.s.low - 1)) == 0)     /* if d is a power of 2 */
130156cd587Sjoerg             {
131156cd587Sjoerg                 if (rem)
132156cd587Sjoerg                     *rem = n.s.low & (d.s.low - 1);
133156cd587Sjoerg                 if (d.s.low == 1)
134156cd587Sjoerg                     return n.all;
135156cd587Sjoerg                 sr = __builtin_ctzll(d.s.low);
136156cd587Sjoerg                 q.s.high = n.s.high >> sr;
137156cd587Sjoerg                 q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
138156cd587Sjoerg                 return q.all;
139156cd587Sjoerg             }
140156cd587Sjoerg             /* K X
141156cd587Sjoerg              * ---
142156cd587Sjoerg              * 0 K
143156cd587Sjoerg              */
144156cd587Sjoerg             sr = 1 + n_udword_bits + __builtin_clzll(d.s.low)
145156cd587Sjoerg                                    - __builtin_clzll(n.s.high);
146156cd587Sjoerg             /* 2 <= sr <= n_utword_bits - 1
147156cd587Sjoerg              * q.all = n.all << (n_utword_bits - sr);
148156cd587Sjoerg              * r.all = n.all >> sr;
149156cd587Sjoerg              */
150*f7f78b33Sjoerg             if (sr == n_udword_bits)
151*f7f78b33Sjoerg             {
152*f7f78b33Sjoerg                 q.s.low = 0;
153*f7f78b33Sjoerg                 q.s.high = n.s.low;
154*f7f78b33Sjoerg                 r.s.high = 0;
155*f7f78b33Sjoerg                 r.s.low = n.s.high;
156*f7f78b33Sjoerg             }
157*f7f78b33Sjoerg             else if (sr < n_udword_bits)  // 2 <= sr <= n_udword_bits - 1
158*f7f78b33Sjoerg             {
159*f7f78b33Sjoerg                 q.s.low = 0;
160*f7f78b33Sjoerg                 q.s.high = n.s.low << (n_udword_bits - sr);
161*f7f78b33Sjoerg                 r.s.high = n.s.high >> sr;
162*f7f78b33Sjoerg                 r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
163*f7f78b33Sjoerg             }
164*f7f78b33Sjoerg             else              // n_udword_bits + 1 <= sr <= n_utword_bits - 1
165*f7f78b33Sjoerg             {
166*f7f78b33Sjoerg                 q.s.low = n.s.low << (n_utword_bits - sr);
167*f7f78b33Sjoerg                 q.s.high = (n.s.high << (n_utword_bits - sr)) |
168*f7f78b33Sjoerg                            (n.s.low >> (sr - n_udword_bits));
169*f7f78b33Sjoerg                 r.s.high = 0;
170*f7f78b33Sjoerg                 r.s.low = n.s.high >> (sr - n_udword_bits);
171*f7f78b33Sjoerg             }
172156cd587Sjoerg         }
173156cd587Sjoerg         else
174156cd587Sjoerg         {
175156cd587Sjoerg             /* K X
176156cd587Sjoerg              * ---
177156cd587Sjoerg              * K K
178156cd587Sjoerg              */
179156cd587Sjoerg             sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
180156cd587Sjoerg             /*0 <= sr <= n_udword_bits - 1 or sr large */
181156cd587Sjoerg             if (sr > n_udword_bits - 1)
182156cd587Sjoerg             {
183156cd587Sjoerg                if (rem)
184156cd587Sjoerg                     *rem = n.all;
185156cd587Sjoerg                 return 0;
186156cd587Sjoerg             }
187156cd587Sjoerg             ++sr;
188*f7f78b33Sjoerg             /* 1 <= sr <= n_udword_bits
189*f7f78b33Sjoerg              * q.all = n.all << (n_utword_bits - sr);
190*f7f78b33Sjoerg              * r.all = n.all >> sr;
191156cd587Sjoerg              */
192*f7f78b33Sjoerg             q.s.low = 0;
193*f7f78b33Sjoerg             if (sr == n_udword_bits)
194*f7f78b33Sjoerg             {
195*f7f78b33Sjoerg                 q.s.high = n.s.low;
196*f7f78b33Sjoerg                 r.s.high = 0;
197*f7f78b33Sjoerg                 r.s.low = n.s.high;
198*f7f78b33Sjoerg             }
199*f7f78b33Sjoerg             else
200*f7f78b33Sjoerg             {
201*f7f78b33Sjoerg                 r.s.high = n.s.high >> sr;
202*f7f78b33Sjoerg                 r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
203*f7f78b33Sjoerg                 q.s.high = n.s.low << (n_udword_bits - sr);
204*f7f78b33Sjoerg             }
205156cd587Sjoerg         }
206156cd587Sjoerg     }
207156cd587Sjoerg     /* Not a special case
208156cd587Sjoerg      * q and r are initialized with:
209156cd587Sjoerg      * q.all = n.all << (n_utword_bits - sr);
210156cd587Sjoerg      * r.all = n.all >> sr;
211156cd587Sjoerg      * 1 <= sr <= n_utword_bits - 1
212156cd587Sjoerg      */
213156cd587Sjoerg     su_int carry = 0;
214156cd587Sjoerg     for (; sr > 0; --sr)
215156cd587Sjoerg     {
216156cd587Sjoerg         /* r:q = ((r:q)  << 1) | carry */
217156cd587Sjoerg         r.s.high = (r.s.high << 1) | (r.s.low  >> (n_udword_bits - 1));
218156cd587Sjoerg         r.s.low  = (r.s.low  << 1) | (q.s.high >> (n_udword_bits - 1));
219156cd587Sjoerg         q.s.high = (q.s.high << 1) | (q.s.low  >> (n_udword_bits - 1));
220156cd587Sjoerg         q.s.low  = (q.s.low  << 1) | carry;
221156cd587Sjoerg         /* carry = 0;
222156cd587Sjoerg          * if (r.all >= d.all)
223156cd587Sjoerg          * {
224156cd587Sjoerg          *     r.all -= d.all;
225156cd587Sjoerg          *      carry = 1;
226156cd587Sjoerg          * }
227156cd587Sjoerg          */
228156cd587Sjoerg         const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);
229156cd587Sjoerg         carry = s & 1;
230156cd587Sjoerg         r.all -= d.all & s;
231156cd587Sjoerg     }
232156cd587Sjoerg     q.all = (q.all << 1) | carry;
233156cd587Sjoerg     if (rem)
234156cd587Sjoerg         *rem = r.all;
235156cd587Sjoerg     return q.all;
236156cd587Sjoerg }
237156cd587Sjoerg 
238156cd587Sjoerg #endif /* CRT_HAS_128BIT */
239