Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "Sk64.h"
     11 #include "SkMath.h"
     12 
     13 #define shift_left(hi, lo)          \
     14     hi = (hi << 1) | (lo >> 31);    \
     15     lo <<= 1
     16 
     17 #define shift_left_bits(hi, lo, bits)           \
     18     SkASSERT((unsigned)(bits) < 31);                \
     19     hi = (hi << (bits)) | (lo >> (32 - (bits)));    \
     20     lo <<= (bits)
     21 
     22 //////////////////////////////////////////////////////////////////////
     23 
     24 int Sk64::getClzAbs() const
     25 {
     26     int32_t     hi = fHi;
     27     uint32_t    lo = fLo;
     28 
     29     // get abs
     30     if (hi < 0)
     31     {
     32         hi = -hi - Sk32ToBool(lo);
     33         lo = 0 - lo;
     34     }
     35     return hi ? SkCLZ(hi) : SkCLZ(lo) + 32;
     36 }
     37 
     38 void Sk64::shiftLeft(unsigned bits)
     39 {
     40     SkASSERT(bits <= 63);
     41     if (bits == 0)
     42         return;
     43 
     44     if (bits >= 32)
     45     {
     46         fHi = fLo << (bits - 32);
     47         fLo = 0;
     48     }
     49     else
     50     {
     51         fHi = (fHi << bits) | (fLo >> (32 - bits));
     52         fLo <<= bits;
     53     }
     54 }
     55 
     56 int32_t Sk64::getShiftRight(unsigned bits) const
     57 {
     58     SkASSERT(bits <= 63);
     59 
     60     if (bits == 0)
     61         return fLo;
     62 
     63     if (bits >= 32)
     64         return fHi >> (bits - 32);
     65     else
     66     {
     67 #ifdef SK_DEBUG
     68         int32_t tmp = fHi >> bits;
     69         SkASSERT(tmp == 0 || tmp == -1);
     70 #endif
     71         return (fHi << (32 - bits)) | (fLo >> bits);
     72     }
     73 }
     74 
     75 void Sk64::shiftRight(unsigned bits)
     76 {
     77     SkASSERT(bits <= 63);
     78     if (bits == 0)
     79         return;
     80 
     81     if (bits >= 32)
     82     {
     83         fLo = fHi >> (bits - 32);
     84         fHi >>= 31;
     85     }
     86     else
     87     {
     88         fLo = (fHi << (32 - bits)) | (fLo >> bits);
     89         fHi >>= bits;
     90     }
     91 }
     92 
     93 void Sk64::roundRight(unsigned bits)
     94 {
     95     SkASSERT(bits <= 63);
     96     if (bits)
     97     {
     98         Sk64 one;
     99         one.set(1);
    100         one.shiftLeft(bits - 1);
    101         this->add(one);
    102         this->shiftRight(bits);
    103     }
    104 }
    105 
    106 int Sk64::shiftToMake32() const
    107 {
    108     int32_t     hi = fHi;
    109     uint32_t    lo = fLo;
    110 
    111     if (hi < 0) // make it positive
    112     {
    113         hi = -hi - Sk32ToBool(lo);
    114         lo = 0 - lo;
    115     }
    116 
    117     if (hi == 0)
    118         return lo >> 31;
    119     else
    120         return 33 - SkCLZ(hi);
    121 }
    122 
    123 void Sk64::negate()
    124 {
    125     fHi = -fHi - Sk32ToBool(fLo);
    126     fLo = 0 - fLo;
    127 }
    128 
    129 void Sk64::abs()
    130 {
    131     if (fHi < 0)
    132     {
    133         fHi = -fHi - Sk32ToBool(fLo);
    134         fLo = 0 - fLo;
    135     }
    136 }
    137 
    138 ////////////////////////////////////////////////////////////////
    139 
    140 static inline int32_t round_right_16(int32_t hi, uint32_t lo)
    141 {
    142     uint32_t sum = lo + (1 << 15);
    143     hi += (sum < lo);
    144     return (hi << 16) | (sum >> 16);
    145 }
    146 
    147 SkBool Sk64::isFixed() const
    148 {
    149     Sk64 tmp = *this;
    150     tmp.roundRight(16);
    151     return tmp.is32();
    152 }
    153 
    154 SkFract Sk64::getFract() const
    155 {
    156     Sk64 tmp = *this;
    157     tmp.roundRight(30);
    158     return tmp.get32();
    159 }
    160 
    161 void Sk64::sub(const Sk64& a)
    162 {
    163     fHi = fHi - a.fHi - (fLo < a.fLo);
    164     fLo = fLo - a.fLo;
    165 }
    166 
    167 void Sk64::rsub(const Sk64& a)
    168 {
    169     fHi = a.fHi - fHi - (a.fLo < fLo);
    170     fLo = a.fLo - fLo;
    171 }
    172 
    173 void Sk64::setMul(int32_t a, int32_t b)
    174 {
    175     int sa = a >> 31;
    176     int sb = b >> 31;
    177     // now make them positive
    178     a = (a ^ sa) - sa;
    179     b = (b ^ sb) - sb;
    180 
    181     uint32_t    ah = a >> 16;
    182     uint32_t    al = a & 0xFFFF;
    183     uint32_t bh = b >> 16;
    184     uint32_t bl = b & 0xFFFF;
    185 
    186     uint32_t A = ah * bh;
    187     uint32_t B = ah * bl + al * bh;
    188     uint32_t C = al * bl;
    189 
    190     /*  [  A  ]
    191            [  B  ]
    192               [  C  ]
    193     */
    194     fLo = C + (B << 16);
    195     fHi = A + (B >>16) + (fLo < C);
    196 
    197     if (sa != sb)
    198         this->negate();
    199 }
    200 
    201 void Sk64::div(int32_t denom, DivOptions option)
    202 {
    203     SkASSERT(denom);
    204 
    205     int32_t     hi = fHi;
    206     uint32_t    lo = fLo;
    207     int         sign = denom ^ hi;
    208 
    209     denom = SkAbs32(denom);
    210     if (hi < 0)
    211     {
    212         hi = -hi - Sk32ToBool(lo);
    213         lo = 0 - lo;
    214     }
    215 
    216     if (option == kRound_DivOption) // add denom/2
    217     {
    218         uint32_t newLo = lo + (denom >> 1);
    219         hi += (newLo < lo);
    220         lo = newLo;
    221     }
    222 
    223     if (hi == 0)    // fast-case
    224     {
    225         if (lo < (uint32_t)denom)
    226             this->set(0, 0);
    227         else
    228         {
    229             this->set(0, lo / denom);
    230             if (sign < 0)
    231                 this->negate();
    232         }
    233         return;
    234     }
    235 
    236     int bits;
    237 
    238     {
    239         int dbits = SkCLZ(denom);
    240         int nbits = SkCLZ(hi);
    241 
    242         bits = 32 + dbits - nbits;
    243         SkASSERT(bits <= 63);
    244         if (bits <= 0)
    245         {
    246             this->set(0, 0);
    247             return;
    248         }
    249         denom <<= (dbits - 1);
    250         shift_left_bits(hi, lo, nbits - 1);
    251     }
    252 
    253     int32_t     rhi = 0;
    254     uint32_t    rlo = 0;
    255 
    256     do {
    257         shift_left(rhi, rlo);
    258 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
    259         if ((uint32_t)denom <= (uint32_t)hi)
    260         {
    261             hi -= denom;
    262             rlo |= 1;
    263         }
    264 #else
    265         int32_t diff = (denom - hi - 1) >> 31;
    266         hi -= denom & diff;
    267         rlo -= diff;
    268 #endif
    269         shift_left(hi, lo);
    270     } while (--bits >= 0);
    271     SkASSERT(rhi >= 0);
    272 
    273     fHi = rhi;
    274     fLo = rlo;
    275     if (sign < 0)
    276         this->negate();
    277 }
    278 
    279 #define shift_left_2(a, b, c)   \
    280     a = (a << 2) | (b >> 30);   \
    281     b = (b << 2) | (c >> 30);   \
    282     c <<= 2
    283 
    284 int32_t Sk64::getSqrt() const
    285 {
    286     SkASSERT(!this->isNeg());
    287 
    288     uint32_t    hi = fHi;
    289     uint32_t lo = fLo;
    290     uint32_t    sqr = 0;
    291     uint32_t root = 0;
    292     int count = 31;
    293 
    294     do {
    295         root <<= 1;
    296         shift_left_2(sqr, hi, lo);
    297 
    298         uint32_t testDiv = (root << 1) + 1;
    299         if (sqr >= testDiv)
    300         {
    301             sqr -= testDiv;
    302             root++;
    303         }
    304     } while (--count >= 0);
    305     SkASSERT((int32_t)root >= 0);
    306 
    307     return root;
    308 }
    309 
    310 #ifdef SkLONGLONG
    311     SkLONGLONG Sk64::getLongLong() const
    312     {
    313         SkLONGLONG value = fHi;
    314         value <<= 32;
    315         return value | fLo;
    316     }
    317 #endif
    318 
    319 SkFixed Sk64::getFixedDiv(const Sk64& denom) const
    320 {
    321     Sk64    N = *this;
    322     Sk64    D = denom;
    323     int32_t sign = SkExtractSign(N.fHi ^ D.fHi);
    324     SkFixed result;
    325 
    326     N.abs();
    327     D.abs();
    328 
    329     // need to knock D down to just 31 bits
    330     // either by rounding it to the right, or shifting N to the left
    331     // then we can just call 64/32 div
    332 
    333     int nclz = N.fHi ? SkCLZ(N.fHi) : 32;
    334     int dclz = D.fHi ? SkCLZ(D.fHi) : (33 - (D.fLo >> 31));
    335 
    336     int shiftN = nclz - 1;
    337     SkASSERT(shiftN >= 0);
    338     int shiftD = 33 - dclz;
    339     SkASSERT(shiftD >= 0);
    340 
    341     if (shiftD + shiftN < 16)
    342         shiftD = 16 - shiftN;
    343     else
    344         shiftN = 16 - shiftD;
    345 
    346     D.roundRight(shiftD);
    347     if (D.isZero())
    348         result = SK_MaxS32;
    349     else
    350     {
    351         if (shiftN >= 0)
    352             N.shiftLeft(shiftN);
    353         else
    354             N.roundRight(-shiftN);
    355         N.div(D.get32(), Sk64::kTrunc_DivOption);
    356         if (N.is32())
    357             result = N.get32();
    358         else
    359             result = SK_MaxS32;
    360     }
    361     return SkApplySign(result, sign);
    362 }
    363 
    364