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