| Index: skia/corecg/Sk64.cpp
|
| ===================================================================
|
| --- skia/corecg/Sk64.cpp (revision 16859)
|
| +++ skia/corecg/Sk64.cpp (working copy)
|
| @@ -1,575 +0,0 @@
|
| -/* libs/corecg/Sk64.cpp
|
| -**
|
| -** Copyright 2006, The Android Open Source Project
|
| -**
|
| -** Licensed under the Apache License, Version 2.0 (the "License");
|
| -** you may not use this file except in compliance with the License.
|
| -** You may obtain a copy of the License at
|
| -**
|
| -** http://www.apache.org/licenses/LICENSE-2.0
|
| -**
|
| -** Unless required by applicable law or agreed to in writing, software
|
| -** distributed under the License is distributed on an "AS IS" BASIS,
|
| -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -** See the License for the specific language governing permissions and
|
| -** limitations under the License.
|
| -*/
|
| -
|
| -#include "Sk64.h"
|
| -
|
| -#define shift_left(hi, lo) \
|
| - hi = (hi << 1) | (lo >> 31); \
|
| - lo <<= 1
|
| -
|
| -#define shift_left_bits(hi, lo, bits) \
|
| - SkASSERT((unsigned)(bits) < 31); \
|
| - hi = (hi << (bits)) | (lo >> (32 - (bits))); \
|
| - lo <<= (bits)
|
| -
|
| -//////////////////////////////////////////////////////////////////////
|
| -
|
| -int Sk64::getClzAbs() const
|
| -{
|
| - int32_t hi = fHi;
|
| - uint32_t lo = fLo;
|
| -
|
| - // get abs
|
| - if (hi < 0)
|
| - {
|
| - hi = -hi - Sk32ToBool(lo);
|
| - lo = 0 - lo;
|
| - }
|
| - return hi ? SkCLZ(hi) : SkCLZ(lo) + 32;
|
| -}
|
| -
|
| -void Sk64::shiftLeft(unsigned bits)
|
| -{
|
| - SkASSERT(bits <= 63);
|
| - if (bits == 0)
|
| - return;
|
| -
|
| - if (bits >= 32)
|
| - {
|
| - fHi = fLo << (bits - 32);
|
| - fLo = 0;
|
| - }
|
| - else
|
| - {
|
| - fHi = (fHi << bits) | (fLo >> (32 - bits));
|
| - fLo <<= bits;
|
| - }
|
| -}
|
| -
|
| -int32_t Sk64::getShiftRight(unsigned bits) const
|
| -{
|
| - SkASSERT(bits <= 63);
|
| -
|
| - if (bits == 0)
|
| - return fLo;
|
| -
|
| - if (bits >= 32)
|
| - return fHi >> (bits - 32);
|
| - else
|
| - {
|
| -#ifdef SK_DEBUG
|
| - int32_t tmp = fHi >> bits;
|
| - SkASSERT(tmp == 0 || tmp == -1);
|
| -#endif
|
| - return (fHi << (32 - bits)) | (fLo >> bits);
|
| - }
|
| -}
|
| -
|
| -void Sk64::shiftRight(unsigned bits)
|
| -{
|
| - SkASSERT(bits <= 63);
|
| - if (bits == 0)
|
| - return;
|
| -
|
| - if (bits >= 32)
|
| - {
|
| - fLo = fHi >> (bits - 32);
|
| - fHi >>= 31;
|
| - }
|
| - else
|
| - {
|
| - fLo = (fHi << (32 - bits)) | (fLo >> bits);
|
| - fHi >>= bits;
|
| - }
|
| -}
|
| -
|
| -void Sk64::roundRight(unsigned bits)
|
| -{
|
| - SkASSERT(bits <= 63);
|
| - if (bits)
|
| - {
|
| - Sk64 one;
|
| - one.set(1);
|
| - one.shiftLeft(bits - 1);
|
| - this->add(one);
|
| - this->shiftRight(bits);
|
| - }
|
| -}
|
| -
|
| -int Sk64::shiftToMake32() const
|
| -{
|
| - int32_t hi = fHi;
|
| - uint32_t lo = fLo;
|
| -
|
| - if (hi < 0) // make it positive
|
| - {
|
| - hi = -hi - Sk32ToBool(lo);
|
| - lo = 0 - lo;
|
| - }
|
| -
|
| - if (hi == 0)
|
| - return lo >> 31;
|
| - else
|
| - return 33 - SkCLZ(hi);
|
| -}
|
| -
|
| -void Sk64::negate()
|
| -{
|
| - fHi = -fHi - Sk32ToBool(fLo);
|
| - fLo = 0 - fLo;
|
| -}
|
| -
|
| -void Sk64::abs()
|
| -{
|
| - if (fHi < 0)
|
| - {
|
| - fHi = -fHi - Sk32ToBool(fLo);
|
| - fLo = 0 - fLo;
|
| - }
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////
|
| -
|
| -static inline int32_t round_right_16(int32_t hi, uint32_t lo)
|
| -{
|
| - uint32_t sum = lo + (1 << 15);
|
| - hi += (sum < lo);
|
| - return (hi << 16) | (sum >> 16);
|
| -}
|
| -
|
| -SkBool Sk64::isFixed() const
|
| -{
|
| - Sk64 tmp = *this;
|
| - tmp.roundRight(16);
|
| - return tmp.is32();
|
| -}
|
| -
|
| -SkFract Sk64::getFract() const
|
| -{
|
| - Sk64 tmp = *this;
|
| - tmp.roundRight(30);
|
| - return tmp.get32();
|
| -}
|
| -
|
| -void Sk64::sub(const Sk64& a)
|
| -{
|
| - fHi = fHi - a.fHi - (fLo < a.fLo);
|
| - fLo = fLo - a.fLo;
|
| -}
|
| -
|
| -void Sk64::rsub(const Sk64& a)
|
| -{
|
| - fHi = a.fHi - fHi - (a.fLo < fLo);
|
| - fLo = a.fLo - fLo;
|
| -}
|
| -
|
| -void Sk64::setMul(int32_t a, int32_t b)
|
| -{
|
| - int sa = a >> 31;
|
| - int sb = b >> 31;
|
| - // now make them positive
|
| - a = (a ^ sa) - sa;
|
| - b = (b ^ sb) - sb;
|
| -
|
| - uint32_t ah = a >> 16;
|
| - uint32_t al = a & 0xFFFF;
|
| - uint32_t bh = b >> 16;
|
| - uint32_t bl = b & 0xFFFF;
|
| -
|
| - uint32_t A = ah * bh;
|
| - uint32_t B = ah * bl + al * bh;
|
| - uint32_t C = al * bl;
|
| -
|
| - /* [ A ]
|
| - [ B ]
|
| - [ C ]
|
| - */
|
| - fLo = C + (B << 16);
|
| - fHi = A + (B >>16) + (fLo < C);
|
| -
|
| - if (sa != sb)
|
| - this->negate();
|
| -}
|
| -
|
| -void Sk64::div(int32_t denom, DivOptions option)
|
| -{
|
| - SkASSERT(denom);
|
| -
|
| - int32_t hi = fHi;
|
| - uint32_t lo = fLo;
|
| - int sign = denom ^ hi;
|
| -
|
| - denom = SkAbs32(denom);
|
| - if (hi < 0)
|
| - {
|
| - hi = -hi - Sk32ToBool(lo);
|
| - lo = 0 - lo;
|
| - }
|
| -
|
| - if (option == kRound_DivOption) // add denom/2
|
| - {
|
| - uint32_t newLo = lo + (denom >> 1);
|
| - hi += (newLo < lo);
|
| - lo = newLo;
|
| - }
|
| -
|
| - if (hi == 0) // fast-case
|
| - {
|
| - if (lo < (uint32_t)denom)
|
| - this->set(0, 0);
|
| - else
|
| - {
|
| - this->set(0, lo / denom);
|
| - if (sign < 0)
|
| - this->negate();
|
| - }
|
| - return;
|
| - }
|
| -
|
| - int bits;
|
| -
|
| - {
|
| - int dbits = SkCLZ(denom);
|
| - int nbits = SkCLZ(hi);
|
| -
|
| - bits = 32 + dbits - nbits;
|
| - SkASSERT(bits <= 63);
|
| - if (bits <= 0)
|
| - {
|
| - this->set(0, 0);
|
| - return;
|
| - }
|
| - denom <<= (dbits - 1);
|
| - shift_left_bits(hi, lo, nbits - 1);
|
| - }
|
| -
|
| - int32_t rhi = 0;
|
| - uint32_t rlo = 0;
|
| -
|
| - do {
|
| - shift_left(rhi, rlo);
|
| -#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
|
| - if ((uint32_t)denom <= (uint32_t)hi)
|
| - {
|
| - hi -= denom;
|
| - rlo |= 1;
|
| - }
|
| -#else
|
| - int32_t diff = (denom - hi - 1) >> 31;
|
| - hi -= denom & diff;
|
| - rlo -= diff;
|
| -#endif
|
| - shift_left(hi, lo);
|
| - } while (--bits >= 0);
|
| - SkASSERT(rhi >= 0);
|
| -
|
| - fHi = rhi;
|
| - fLo = rlo;
|
| - if (sign < 0)
|
| - this->negate();
|
| -}
|
| -
|
| -#define shift_left_2(a, b, c) \
|
| - a = (a << 2) | (b >> 30); \
|
| - b = (b << 2) | (c >> 30); \
|
| - c <<= 2
|
| -
|
| -int32_t Sk64::getSqrt() const
|
| -{
|
| - SkASSERT(!this->isNeg());
|
| -
|
| - uint32_t hi = fHi;
|
| - uint32_t lo = fLo;
|
| - uint32_t sqr = 0;
|
| - uint32_t root = 0;
|
| - int count = 31;
|
| -
|
| - do {
|
| - root <<= 1;
|
| - shift_left_2(sqr, hi, lo);
|
| -
|
| - uint32_t testDiv = (root << 1) + 1;
|
| - if (sqr >= testDiv)
|
| - {
|
| - sqr -= testDiv;
|
| - root++;
|
| - }
|
| - } while (--count >= 0);
|
| - SkASSERT((int32_t)root >= 0);
|
| -
|
| - return root;
|
| -}
|
| -
|
| -#ifdef SkLONGLONG
|
| - SkLONGLONG Sk64::getLongLong() const
|
| - {
|
| - SkLONGLONG value = fHi;
|
| - value <<= 32;
|
| - return value | fLo;
|
| - }
|
| -#endif
|
| -
|
| -SkFixed Sk64::getFixedDiv(const Sk64& denom) const
|
| -{
|
| - Sk64 N = *this;
|
| - Sk64 D = denom;
|
| - int32_t sign = SkExtractSign(N.fHi ^ D.fHi);
|
| - SkFixed result;
|
| -
|
| - N.abs();
|
| - D.abs();
|
| -
|
| - // need to knock D down to just 31 bits
|
| - // either by rounding it to the right, or shifting N to the left
|
| - // then we can just call 64/32 div
|
| -
|
| - int nclz = N.fHi ? SkCLZ(N.fHi) : 32;
|
| - int dclz = D.fHi ? SkCLZ(D.fHi) : (33 - (D.fLo >> 31));
|
| -
|
| - int shiftN = nclz - 1;
|
| - SkASSERT(shiftN >= 0);
|
| - int shiftD = 33 - dclz;
|
| - SkASSERT(shiftD >= 0);
|
| -
|
| - if (shiftD + shiftN < 16)
|
| - shiftD = 16 - shiftN;
|
| - else
|
| - shiftN = 16 - shiftD;
|
| -
|
| - D.roundRight(shiftD);
|
| - if (D.isZero())
|
| - result = SK_MaxS32;
|
| - else
|
| - {
|
| - if (shiftN >= 0)
|
| - N.shiftLeft(shiftN);
|
| - else
|
| - N.roundRight(-shiftN);
|
| - N.div(D.get32(), Sk64::kTrunc_DivOption);
|
| - if (N.is32())
|
| - result = N.get32();
|
| - else
|
| - result = SK_MaxS32;
|
| - }
|
| - return SkApplySign(result, sign);
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////
|
| -
|
| -#ifdef SK_DEBUG
|
| -
|
| -#include "SkRandom.h"
|
| -#include <math.h>
|
| -
|
| -#ifdef SK_SUPPORT_UNITTEST
|
| -struct BoolTable {
|
| - int8_t zero, pos, neg, toBool, sign;
|
| -};
|
| -
|
| -static void bool_table_test(const Sk64& a, const BoolTable& table)
|
| -{
|
| - SkASSERT(a.isZero() != a.nonZero());
|
| -
|
| - SkASSERT(!a.isZero() == !table.zero);
|
| - SkASSERT(!a.isPos() == !table.pos);
|
| - SkASSERT(!a.isNeg() == !table.neg);
|
| - SkASSERT(a.sign() == table.sign);
|
| -}
|
| -
|
| -#ifdef SkLONGLONG
|
| - static SkLONGLONG asLL(const Sk64& a)
|
| - {
|
| - return ((SkLONGLONG)a.fHi << 32) | a.fLo;
|
| - }
|
| -#endif
|
| -#endif
|
| -
|
| -void Sk64::UnitTest()
|
| -{
|
| -#ifdef SK_SUPPORT_UNITTEST
|
| - enum BoolTests {
|
| - kZero_BoolTest,
|
| - kPos_BoolTest,
|
| - kNeg_BoolTest
|
| - };
|
| - static const BoolTable gBoolTable[] = {
|
| - { 1, 0, 0, 0, 0 },
|
| - { 0, 1, 0, 1, 1 },
|
| - { 0, 0, 1, 1, -1 }
|
| - };
|
| -
|
| - Sk64 a, b, c;
|
| -
|
| - a.fHi = a.fLo = 0;
|
| - b.set(0);
|
| - c.setZero();
|
| - SkASSERT(a == b);
|
| - SkASSERT(a == c);
|
| - bool_table_test(a, gBoolTable[kZero_BoolTest]);
|
| -
|
| - a.fHi = 0; a.fLo = 5;
|
| - b.set(5);
|
| - SkASSERT(a == b);
|
| - SkASSERT(a.is32() && a.get32() == 5 && !a.is64());
|
| - bool_table_test(a, gBoolTable[kPos_BoolTest]);
|
| -
|
| - a.fHi = -1; a.fLo = (uint32_t)-5;
|
| - b.set(-5);
|
| - SkASSERT(a == b);
|
| - SkASSERT(a.is32() && a.get32() == -5 && !a.is64());
|
| - bool_table_test(a, gBoolTable[kNeg_BoolTest]);
|
| -
|
| - a.setZero();
|
| - b.set(6);
|
| - c.set(-6);
|
| - SkASSERT(a != b && b != c && a != c);
|
| - SkASSERT(!(a == b) && !(a == b) && !(a == b));
|
| - SkASSERT(a < b && b > a && a <= b && b >= a);
|
| - SkASSERT(c < a && a > c && c <= a && a >= c);
|
| - SkASSERT(c < b && b > c && c <= b && b >= c);
|
| -
|
| - // Now test add/sub
|
| -
|
| - SkRandom rand;
|
| - int i;
|
| -
|
| - for (i = 0; i < 1000; i++)
|
| - {
|
| - int aa = rand.nextS() >> 1;
|
| - int bb = rand.nextS() >> 1;
|
| - a.set(aa);
|
| - b.set(bb);
|
| - SkASSERT(a.get32() == aa && b.get32() == bb);
|
| - c = a; c.add(bb);
|
| - SkASSERT(c.get32() == aa + bb);
|
| - c = a; c.add(-bb);
|
| - SkASSERT(c.get32() == aa - bb);
|
| - c = a; c.add(b);
|
| - SkASSERT(c.get32() == aa + bb);
|
| - c = a; c.sub(b);
|
| - SkASSERT(c.get32() == aa - bb);
|
| - }
|
| -
|
| -#ifdef SkLONGLONG
|
| - for (i = 0; i < 1000; i++)
|
| - {
|
| - rand.next64(&a); //a.fHi >>= 1; // avoid overflow
|
| - rand.next64(&b); //b.fHi >>= 1; // avoid overflow
|
| -
|
| - if (!(i & 3)) // want to explicitly test these cases
|
| - {
|
| - a.fLo = 0;
|
| - b.fLo = 0;
|
| - }
|
| - else if (!(i & 7)) // want to explicitly test these cases
|
| - {
|
| - a.fHi = 0;
|
| - b.fHi = 0;
|
| - }
|
| -
|
| - SkLONGLONG aa = asLL(a);
|
| - SkLONGLONG bb = asLL(b);
|
| -
|
| - SkASSERT((a < b) == (aa < bb));
|
| - SkASSERT((a <= b) == (aa <= bb));
|
| - SkASSERT((a > b) == (aa > bb));
|
| - SkASSERT((a >= b) == (aa >= bb));
|
| - SkASSERT((a == b) == (aa == bb));
|
| - SkASSERT((a != b) == (aa != bb));
|
| -
|
| - c = a; c.add(b);
|
| - SkASSERT(asLL(c) == aa + bb);
|
| - c = a; c.sub(b);
|
| - SkASSERT(asLL(c) == aa - bb);
|
| - c = a; c.rsub(b);
|
| - SkASSERT(asLL(c) == bb - aa);
|
| - c = a; c.negate();
|
| - SkASSERT(asLL(c) == -aa);
|
| -
|
| - int bits = rand.nextU() & 63;
|
| - c = a; c.shiftLeft(bits);
|
| - SkASSERT(asLL(c) == (aa << bits));
|
| - c = a; c.shiftRight(bits);
|
| - SkASSERT(asLL(c) == (aa >> bits));
|
| - c = a; c.roundRight(bits);
|
| -
|
| - SkLONGLONG tmp;
|
| -
|
| - tmp = aa;
|
| - if (bits > 0)
|
| - tmp += (SkLONGLONG)1 << (bits - 1);
|
| - SkASSERT(asLL(c) == (tmp >> bits));
|
| -
|
| - c.setMul(a.fHi, b.fHi);
|
| - tmp = (SkLONGLONG)a.fHi * b.fHi;
|
| - SkASSERT(asLL(c) == tmp);
|
| - }
|
| -
|
| -
|
| - for (i = 0; i < 100000; i++)
|
| - {
|
| - Sk64 wide;
|
| - int32_t denom = rand.nextS();
|
| -
|
| - while (denom == 0)
|
| - denom = rand.nextS();
|
| - wide.setMul(rand.nextS(), rand.nextS());
|
| - SkLONGLONG check = wide.getLongLong();
|
| -
|
| - wide.div(denom, Sk64::kTrunc_DivOption);
|
| - check /= denom;
|
| - SkLONGLONG w = wide.getLongLong();
|
| -
|
| - SkASSERT(check == w);
|
| -
|
| -#ifdef SK_CAN_USE_FLOATx
|
| - wide.setMul(rand.nextS(), rand.nextS());
|
| - wide.abs();
|
| - denom = wide.getSqrt();
|
| - int32_t ck = (int32_t)sqrt((double)wide.getLongLong());
|
| - int diff = denom - ck;
|
| - SkASSERT(SkAbs32(diff) <= 1);
|
| -
|
| - wide.setMul(rand.nextS(), rand.nextS());
|
| - Sk64 dwide;
|
| - dwide.setMul(rand.nextS(), rand.nextS());
|
| - SkFixed fixdiv = wide.getFixedDiv(dwide);
|
| - double dnumer = (double)wide.getLongLong();
|
| - double ddenom = (double)dwide.getLongLong();
|
| - double ddiv = dnumer / ddenom;
|
| - SkFixed dfixdiv;
|
| - if (ddiv >= (double)SK_MaxS32 / (double)SK_Fixed1)
|
| - dfixdiv = SK_MaxS32;
|
| - else if (ddiv <= -(double)SK_MaxS32 / (double)SK_Fixed1)
|
| - dfixdiv = SK_MinS32;
|
| - else
|
| - dfixdiv = SkFloatToFixed(dnumer / ddenom);
|
| - diff = fixdiv - dfixdiv;
|
| -
|
| - if (SkAbs32(diff) > 1) {
|
| - SkDebugf(" %d === numer %g denom %g div %g xdiv %x fxdiv %x\n",
|
| - i, dnumer, ddenom, ddiv, dfixdiv, fixdiv);
|
| - }
|
| -// SkASSERT(SkAbs32(diff) <= 1);
|
| -#endif
|
| - }
|
| -#endif
|
| -#endif
|
| -}
|
| -
|
| -#endif
|
| -
|
|
|