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