xref: /aosp_15_r20/external/compiler-rt/lib/builtins/udivmoddi4.c (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot /* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===
2*7c3d14c8STreehugger Robot  *
3*7c3d14c8STreehugger Robot  *                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot  *
5*7c3d14c8STreehugger Robot  * This file is dual licensed under the MIT and the University of Illinois Open
6*7c3d14c8STreehugger Robot  * Source Licenses. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot  *
8*7c3d14c8STreehugger Robot  * ===----------------------------------------------------------------------===
9*7c3d14c8STreehugger Robot  *
10*7c3d14c8STreehugger Robot  * This file implements __udivmoddi4 for the compiler_rt library.
11*7c3d14c8STreehugger Robot  *
12*7c3d14c8STreehugger Robot  * ===----------------------------------------------------------------------===
13*7c3d14c8STreehugger Robot  */
14*7c3d14c8STreehugger Robot 
15*7c3d14c8STreehugger Robot #include "int_lib.h"
16*7c3d14c8STreehugger Robot 
17*7c3d14c8STreehugger Robot /* Effects: if rem != 0, *rem = a % b
18*7c3d14c8STreehugger Robot  * Returns: a / b
19*7c3d14c8STreehugger Robot  */
20*7c3d14c8STreehugger Robot 
21*7c3d14c8STreehugger Robot /* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
22*7c3d14c8STreehugger Robot 
23*7c3d14c8STreehugger Robot COMPILER_RT_ABI du_int
__udivmoddi4(du_int a,du_int b,du_int * rem)24*7c3d14c8STreehugger Robot __udivmoddi4(du_int a, du_int b, du_int* rem)
25*7c3d14c8STreehugger Robot {
26*7c3d14c8STreehugger Robot     const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
27*7c3d14c8STreehugger Robot     const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
28*7c3d14c8STreehugger Robot     udwords n;
29*7c3d14c8STreehugger Robot     n.all = a;
30*7c3d14c8STreehugger Robot     udwords d;
31*7c3d14c8STreehugger Robot     d.all = b;
32*7c3d14c8STreehugger Robot     udwords q;
33*7c3d14c8STreehugger Robot     udwords r;
34*7c3d14c8STreehugger Robot     unsigned sr;
35*7c3d14c8STreehugger Robot     /* special cases, X is unknown, K != 0 */
36*7c3d14c8STreehugger Robot     if (n.s.high == 0)
37*7c3d14c8STreehugger Robot     {
38*7c3d14c8STreehugger Robot         if (d.s.high == 0)
39*7c3d14c8STreehugger Robot         {
40*7c3d14c8STreehugger Robot             /* 0 X
41*7c3d14c8STreehugger Robot              * ---
42*7c3d14c8STreehugger Robot              * 0 X
43*7c3d14c8STreehugger Robot              */
44*7c3d14c8STreehugger Robot             if (rem)
45*7c3d14c8STreehugger Robot                 *rem = n.s.low % d.s.low;
46*7c3d14c8STreehugger Robot             return n.s.low / d.s.low;
47*7c3d14c8STreehugger Robot         }
48*7c3d14c8STreehugger Robot         /* 0 X
49*7c3d14c8STreehugger Robot          * ---
50*7c3d14c8STreehugger Robot          * K X
51*7c3d14c8STreehugger Robot          */
52*7c3d14c8STreehugger Robot         if (rem)
53*7c3d14c8STreehugger Robot             *rem = n.s.low;
54*7c3d14c8STreehugger Robot         return 0;
55*7c3d14c8STreehugger Robot     }
56*7c3d14c8STreehugger Robot     /* n.s.high != 0 */
57*7c3d14c8STreehugger Robot     if (d.s.low == 0)
58*7c3d14c8STreehugger Robot     {
59*7c3d14c8STreehugger Robot         if (d.s.high == 0)
60*7c3d14c8STreehugger Robot         {
61*7c3d14c8STreehugger Robot             /* K X
62*7c3d14c8STreehugger Robot              * ---
63*7c3d14c8STreehugger Robot              * 0 0
64*7c3d14c8STreehugger Robot              */
65*7c3d14c8STreehugger Robot             if (rem)
66*7c3d14c8STreehugger Robot                 *rem = n.s.high % d.s.low;
67*7c3d14c8STreehugger Robot             return n.s.high / d.s.low;
68*7c3d14c8STreehugger Robot         }
69*7c3d14c8STreehugger Robot         /* d.s.high != 0 */
70*7c3d14c8STreehugger Robot         if (n.s.low == 0)
71*7c3d14c8STreehugger Robot         {
72*7c3d14c8STreehugger Robot             /* K 0
73*7c3d14c8STreehugger Robot              * ---
74*7c3d14c8STreehugger Robot              * K 0
75*7c3d14c8STreehugger Robot              */
76*7c3d14c8STreehugger Robot             if (rem)
77*7c3d14c8STreehugger Robot             {
78*7c3d14c8STreehugger Robot                 r.s.high = n.s.high % d.s.high;
79*7c3d14c8STreehugger Robot                 r.s.low = 0;
80*7c3d14c8STreehugger Robot                 *rem = r.all;
81*7c3d14c8STreehugger Robot             }
82*7c3d14c8STreehugger Robot             return n.s.high / d.s.high;
83*7c3d14c8STreehugger Robot         }
84*7c3d14c8STreehugger Robot         /* K K
85*7c3d14c8STreehugger Robot          * ---
86*7c3d14c8STreehugger Robot          * K 0
87*7c3d14c8STreehugger Robot          */
88*7c3d14c8STreehugger Robot         if ((d.s.high & (d.s.high - 1)) == 0)     /* if d is a power of 2 */
89*7c3d14c8STreehugger Robot         {
90*7c3d14c8STreehugger Robot             if (rem)
91*7c3d14c8STreehugger Robot             {
92*7c3d14c8STreehugger Robot                 r.s.low = n.s.low;
93*7c3d14c8STreehugger Robot                 r.s.high = n.s.high & (d.s.high - 1);
94*7c3d14c8STreehugger Robot                 *rem = r.all;
95*7c3d14c8STreehugger Robot             }
96*7c3d14c8STreehugger Robot             return n.s.high >> __builtin_ctz(d.s.high);
97*7c3d14c8STreehugger Robot         }
98*7c3d14c8STreehugger Robot         /* K K
99*7c3d14c8STreehugger Robot          * ---
100*7c3d14c8STreehugger Robot          * K 0
101*7c3d14c8STreehugger Robot          */
102*7c3d14c8STreehugger Robot         sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
103*7c3d14c8STreehugger Robot         /* 0 <= sr <= n_uword_bits - 2 or sr large */
104*7c3d14c8STreehugger Robot         if (sr > n_uword_bits - 2)
105*7c3d14c8STreehugger Robot         {
106*7c3d14c8STreehugger Robot            if (rem)
107*7c3d14c8STreehugger Robot                 *rem = n.all;
108*7c3d14c8STreehugger Robot             return 0;
109*7c3d14c8STreehugger Robot         }
110*7c3d14c8STreehugger Robot         ++sr;
111*7c3d14c8STreehugger Robot         /* 1 <= sr <= n_uword_bits - 1 */
112*7c3d14c8STreehugger Robot         /* q.all = n.all << (n_udword_bits - sr); */
113*7c3d14c8STreehugger Robot         q.s.low = 0;
114*7c3d14c8STreehugger Robot         q.s.high = n.s.low << (n_uword_bits - sr);
115*7c3d14c8STreehugger Robot         /* r.all = n.all >> sr; */
116*7c3d14c8STreehugger Robot         r.s.high = n.s.high >> sr;
117*7c3d14c8STreehugger Robot         r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
118*7c3d14c8STreehugger Robot     }
119*7c3d14c8STreehugger Robot     else  /* d.s.low != 0 */
120*7c3d14c8STreehugger Robot     {
121*7c3d14c8STreehugger Robot         if (d.s.high == 0)
122*7c3d14c8STreehugger Robot         {
123*7c3d14c8STreehugger Robot             /* K X
124*7c3d14c8STreehugger Robot              * ---
125*7c3d14c8STreehugger Robot              * 0 K
126*7c3d14c8STreehugger Robot              */
127*7c3d14c8STreehugger Robot             if ((d.s.low & (d.s.low - 1)) == 0)     /* if d is a power of 2 */
128*7c3d14c8STreehugger Robot             {
129*7c3d14c8STreehugger Robot                 if (rem)
130*7c3d14c8STreehugger Robot                     *rem = n.s.low & (d.s.low - 1);
131*7c3d14c8STreehugger Robot                 if (d.s.low == 1)
132*7c3d14c8STreehugger Robot                     return n.all;
133*7c3d14c8STreehugger Robot                 sr = __builtin_ctz(d.s.low);
134*7c3d14c8STreehugger Robot                 q.s.high = n.s.high >> sr;
135*7c3d14c8STreehugger Robot                 q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
136*7c3d14c8STreehugger Robot                 return q.all;
137*7c3d14c8STreehugger Robot             }
138*7c3d14c8STreehugger Robot             /* K X
139*7c3d14c8STreehugger Robot              * ---
140*7c3d14c8STreehugger Robot              * 0 K
141*7c3d14c8STreehugger Robot              */
142*7c3d14c8STreehugger Robot             sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high);
143*7c3d14c8STreehugger Robot             /* 2 <= sr <= n_udword_bits - 1
144*7c3d14c8STreehugger Robot              * q.all = n.all << (n_udword_bits - sr);
145*7c3d14c8STreehugger Robot              * r.all = n.all >> sr;
146*7c3d14c8STreehugger Robot              */
147*7c3d14c8STreehugger Robot             if (sr == n_uword_bits)
148*7c3d14c8STreehugger Robot             {
149*7c3d14c8STreehugger Robot                 q.s.low = 0;
150*7c3d14c8STreehugger Robot                 q.s.high = n.s.low;
151*7c3d14c8STreehugger Robot                 r.s.high = 0;
152*7c3d14c8STreehugger Robot                 r.s.low = n.s.high;
153*7c3d14c8STreehugger Robot             }
154*7c3d14c8STreehugger Robot             else if (sr < n_uword_bits)  // 2 <= sr <= n_uword_bits - 1
155*7c3d14c8STreehugger Robot             {
156*7c3d14c8STreehugger Robot                 q.s.low = 0;
157*7c3d14c8STreehugger Robot                 q.s.high = n.s.low << (n_uword_bits - sr);
158*7c3d14c8STreehugger Robot                 r.s.high = n.s.high >> sr;
159*7c3d14c8STreehugger Robot                 r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
160*7c3d14c8STreehugger Robot             }
161*7c3d14c8STreehugger Robot             else              // n_uword_bits + 1 <= sr <= n_udword_bits - 1
162*7c3d14c8STreehugger Robot             {
163*7c3d14c8STreehugger Robot                 q.s.low = n.s.low << (n_udword_bits - sr);
164*7c3d14c8STreehugger Robot                 q.s.high = (n.s.high << (n_udword_bits - sr)) |
165*7c3d14c8STreehugger Robot                            (n.s.low >> (sr - n_uword_bits));
166*7c3d14c8STreehugger Robot                 r.s.high = 0;
167*7c3d14c8STreehugger Robot                 r.s.low = n.s.high >> (sr - n_uword_bits);
168*7c3d14c8STreehugger Robot             }
169*7c3d14c8STreehugger Robot         }
170*7c3d14c8STreehugger Robot         else
171*7c3d14c8STreehugger Robot         {
172*7c3d14c8STreehugger Robot             /* K X
173*7c3d14c8STreehugger Robot              * ---
174*7c3d14c8STreehugger Robot              * K K
175*7c3d14c8STreehugger Robot              */
176*7c3d14c8STreehugger Robot             sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
177*7c3d14c8STreehugger Robot             /* 0 <= sr <= n_uword_bits - 1 or sr large */
178*7c3d14c8STreehugger Robot             if (sr > n_uword_bits - 1)
179*7c3d14c8STreehugger Robot             {
180*7c3d14c8STreehugger Robot                 if (rem)
181*7c3d14c8STreehugger Robot                     *rem = n.all;
182*7c3d14c8STreehugger Robot                 return 0;
183*7c3d14c8STreehugger Robot             }
184*7c3d14c8STreehugger Robot             ++sr;
185*7c3d14c8STreehugger Robot             /* 1 <= sr <= n_uword_bits */
186*7c3d14c8STreehugger Robot             /*  q.all = n.all << (n_udword_bits - sr); */
187*7c3d14c8STreehugger Robot             q.s.low = 0;
188*7c3d14c8STreehugger Robot             if (sr == n_uword_bits)
189*7c3d14c8STreehugger Robot             {
190*7c3d14c8STreehugger Robot                 q.s.high = n.s.low;
191*7c3d14c8STreehugger Robot                 r.s.high = 0;
192*7c3d14c8STreehugger Robot                 r.s.low = n.s.high;
193*7c3d14c8STreehugger Robot             }
194*7c3d14c8STreehugger Robot             else
195*7c3d14c8STreehugger Robot             {
196*7c3d14c8STreehugger Robot                 q.s.high = n.s.low << (n_uword_bits - sr);
197*7c3d14c8STreehugger Robot                 r.s.high = n.s.high >> sr;
198*7c3d14c8STreehugger Robot                 r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
199*7c3d14c8STreehugger Robot             }
200*7c3d14c8STreehugger Robot         }
201*7c3d14c8STreehugger Robot     }
202*7c3d14c8STreehugger Robot     /* Not a special case
203*7c3d14c8STreehugger Robot      * q and r are initialized with:
204*7c3d14c8STreehugger Robot      * q.all = n.all << (n_udword_bits - sr);
205*7c3d14c8STreehugger Robot      * r.all = n.all >> sr;
206*7c3d14c8STreehugger Robot      * 1 <= sr <= n_udword_bits - 1
207*7c3d14c8STreehugger Robot      */
208*7c3d14c8STreehugger Robot     su_int carry = 0;
209*7c3d14c8STreehugger Robot     for (; sr > 0; --sr)
210*7c3d14c8STreehugger Robot     {
211*7c3d14c8STreehugger Robot         /* r:q = ((r:q)  << 1) | carry */
212*7c3d14c8STreehugger Robot         r.s.high = (r.s.high << 1) | (r.s.low  >> (n_uword_bits - 1));
213*7c3d14c8STreehugger Robot         r.s.low  = (r.s.low  << 1) | (q.s.high >> (n_uword_bits - 1));
214*7c3d14c8STreehugger Robot         q.s.high = (q.s.high << 1) | (q.s.low  >> (n_uword_bits - 1));
215*7c3d14c8STreehugger Robot         q.s.low  = (q.s.low  << 1) | carry;
216*7c3d14c8STreehugger Robot         /* carry = 0;
217*7c3d14c8STreehugger Robot          * if (r.all >= d.all)
218*7c3d14c8STreehugger Robot          * {
219*7c3d14c8STreehugger Robot          *      r.all -= d.all;
220*7c3d14c8STreehugger Robot          *      carry = 1;
221*7c3d14c8STreehugger Robot          * }
222*7c3d14c8STreehugger Robot          */
223*7c3d14c8STreehugger Robot         const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1);
224*7c3d14c8STreehugger Robot         carry = s & 1;
225*7c3d14c8STreehugger Robot         r.all -= d.all & s;
226*7c3d14c8STreehugger Robot     }
227*7c3d14c8STreehugger Robot     q.all = (q.all << 1) | carry;
228*7c3d14c8STreehugger Robot     if (rem)
229*7c3d14c8STreehugger Robot         *rem = r.all;
230*7c3d14c8STreehugger Robot     return q.all;
231*7c3d14c8STreehugger Robot }
232