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