| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 | /* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------=== * *                    The LLVM Compiler Infrastructure * * This file is dual licensed under the MIT and the University of Illinois Open * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== * * This file implements __udivmodti4 for the compiler_rt library. * * ===----------------------------------------------------------------------=== */ #include <limits.h>typedef          long long di_int;typedef unsigned long long du_int;typedef          int si_int;typedef unsigned int su_int;typedef          int ti_int __attribute__((mode (TI)));typedef unsigned int tu_int __attribute__((mode (TI)));typedef union{    ti_int all;    struct    {        du_int low;        di_int high;    }s;} twords;typedef union{    tu_int all;    struct    {        du_int low;        du_int high;    }s;} utwords;/* Effects: if rem != 0, *rem = a % b  * Returns: a / b  *//* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */tu_int__udivmodti4(tu_int a, tu_int b, tu_int* rem){    const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;    const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;    utwords n;    n.all = a;    utwords d;    d.all = b;    utwords q;    utwords r;    unsigned sr;    /* special cases, X is unknown, K != 0 */    if (n.s.high == 0)    {        if (d.s.high == 0)        {            /* 0 X             * ---             * 0 X             */            if (rem)                *rem = n.s.low % d.s.low;            return n.s.low / d.s.low;        }        /* 0 X         * ---         * K X         */        if (rem)            *rem = n.s.low;        return 0;    }    /* n.s.high != 0 */    if (d.s.low == 0)    {        if (d.s.high == 0)        {            /* K X             * ---             * 0 0             */            if (rem)                *rem = n.s.high % d.s.low;            return n.s.high / d.s.low;        }        /* d.s.high != 0 */        if (n.s.low == 0)        {            /* K 0             * ---             * K 0             */            if (rem)            {                r.s.high = n.s.high % d.s.high;                r.s.low = 0;                *rem = r.all;            }            return n.s.high / d.s.high;        }        /* K K         * ---         * K 0         */        if ((d.s.high & (d.s.high - 1)) == 0)     /* if d is a power of 2 */        {            if (rem)            {                r.s.low = n.s.low;                r.s.high = n.s.high & (d.s.high - 1);                *rem = r.all;            }            return n.s.high >> __builtin_ctzll(d.s.high);        }        /* K K         * ---         * K 0         */        sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);        /* 0 <= sr <= n_udword_bits - 2 or sr large */        if (sr > n_udword_bits - 2)        {           if (rem)                *rem = n.all;            return 0;        }        ++sr;        /* 1 <= sr <= n_udword_bits - 1 */        /* q.all = n.all << (n_utword_bits - sr); */        q.s.low = 0;        q.s.high = n.s.low << (n_udword_bits - sr);        /* r.all = n.all >> sr; */        r.s.high = n.s.high >> sr;        r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);    }    else  /* d.s.low != 0 */    {        if (d.s.high == 0)        {            /* K X             * ---             * 0 K             */            if ((d.s.low & (d.s.low - 1)) == 0)     /* if d is a power of 2 */            {                if (rem)                    *rem = n.s.low & (d.s.low - 1);                if (d.s.low == 1)                    return n.all;                sr = __builtin_ctzll(d.s.low);                q.s.high = n.s.high >> sr;                q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);                return q.all;            }            /* K X             * ---             * 0 K             */            sr = 1 + n_udword_bits + __builtin_clzll(d.s.low)                                   - __builtin_clzll(n.s.high);            /* 2 <= sr <= n_utword_bits - 1             * q.all = n.all << (n_utword_bits - sr);             * r.all = n.all >> sr;             * if (sr == n_udword_bits)             * {             *     q.s.low = 0;             *     q.s.high = n.s.low;             *     r.s.high = 0;             *     r.s.low = n.s.high;             * }             * else if (sr < n_udword_bits)  // 2 <= sr <= n_udword_bits - 1             * {             *     q.s.low = 0;             *     q.s.high = n.s.low << (n_udword_bits - sr);             *     r.s.high = n.s.high >> sr;             *     r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);             * }             * else              // n_udword_bits + 1 <= sr <= n_utword_bits - 1             * {             *     q.s.low = n.s.low << (n_utword_bits - sr);             *     q.s.high = (n.s.high << (n_utword_bits - sr)) |             *              (n.s.low >> (sr - n_udword_bits));             *     r.s.high = 0;             *     r.s.low = n.s.high >> (sr - n_udword_bits);             * }             */            q.s.low =  (n.s.low << (n_utword_bits - sr)) &                     ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1));            q.s.high = ((n.s.low << ( n_udword_bits - sr))                        &                     ((di_int)(int)(sr - n_udword_bits - 1) >> (n_udword_bits-1))) |                     (((n.s.high << (n_utword_bits - sr))                       |                     (n.s.low >> (sr - n_udword_bits)))                         &                     ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1)));            r.s.high = (n.s.high >> sr) &                     ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1));            r.s.low =  ((n.s.high >> (sr - n_udword_bits))                        &                     ((di_int)(int)(n_udword_bits - sr - 1) >> (n_udword_bits-1))) |                     (((n.s.high << (n_udword_bits - sr))                       |                     (n.s.low >> sr))                                           &                     ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)));        }        else        {            /* K X             * ---             * K K             */            sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);            /*0 <= sr <= n_udword_bits - 1 or sr large */            if (sr > n_udword_bits - 1)            {               if (rem)                    *rem = n.all;                return 0;            }            ++sr;            /* 1 <= sr <= n_udword_bits */            /* q.all = n.all << (n_utword_bits - sr); */            q.s.low = 0;            q.s.high = n.s.low << (n_udword_bits - sr);            /* r.all = n.all >> sr;             * if (sr < n_udword_bits)             * {             *     r.s.high = n.s.high >> sr;             *     r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);             * }             * else             * {             *     r.s.high = 0;             *     r.s.low = n.s.high;             * }             */            r.s.high = (n.s.high >> sr) &                     ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1));            r.s.low = (n.s.high << (n_udword_bits - sr)) |                    ((n.s.low >> sr)                   &                    ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)));        }    }    /* Not a special case     * q and r are initialized with:     * q.all = n.all << (n_utword_bits - sr);     * r.all = n.all >> sr;     * 1 <= sr <= n_utword_bits - 1     */    su_int carry = 0;    for (; sr > 0; --sr)    {        /* r:q = ((r:q)  << 1) | carry */        r.s.high = (r.s.high << 1) | (r.s.low  >> (n_udword_bits - 1));        r.s.low  = (r.s.low  << 1) | (q.s.high >> (n_udword_bits - 1));        q.s.high = (q.s.high << 1) | (q.s.low  >> (n_udword_bits - 1));        q.s.low  = (q.s.low  << 1) | carry;        /* carry = 0;         * if (r.all >= d.all)         * {         *     r.all -= d.all;         *      carry = 1;         * }         */        const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);        carry = s & 1;        r.all -= d.all & s;    }    q.all = (q.all << 1) | carry;    if (rem)        *rem = r.all;    return q.all;}/* Returns: a / b */tu_int__udivti3(tu_int a, tu_int b){    return __udivmodti4(a, b, 0);}
 |