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 0 : int Sk64::getClzAbs() const
25 : {
26 0 : int32_t hi = fHi;
27 0 : uint32_t lo = fLo;
28 :
29 : // get abs
30 0 : if (hi < 0)
31 : {
32 0 : hi = -hi - Sk32ToBool(lo);
33 0 : lo = 0 - lo;
34 : }
35 0 : return hi ? SkCLZ(hi) : SkCLZ(lo) + 32;
36 : }
37 :
38 0 : void Sk64::shiftLeft(unsigned bits)
39 : {
40 0 : SkASSERT(bits <= 63);
41 0 : if (bits == 0)
42 0 : return;
43 :
44 0 : if (bits >= 32)
45 : {
46 0 : fHi = fLo << (bits - 32);
47 0 : fLo = 0;
48 : }
49 : else
50 : {
51 0 : fHi = (fHi << bits) | (fLo >> (32 - bits));
52 0 : fLo <<= bits;
53 : }
54 : }
55 :
56 0 : int32_t Sk64::getShiftRight(unsigned bits) const
57 : {
58 0 : SkASSERT(bits <= 63);
59 :
60 0 : if (bits == 0)
61 0 : return fLo;
62 :
63 0 : if (bits >= 32)
64 0 : return fHi >> (bits - 32);
65 : else
66 : {
67 : #ifdef SK_DEBUG
68 0 : int32_t tmp = fHi >> bits;
69 0 : SkASSERT(tmp == 0 || tmp == -1);
70 : #endif
71 0 : return (fHi << (32 - bits)) | (fLo >> bits);
72 : }
73 : }
74 :
75 0 : void Sk64::shiftRight(unsigned bits)
76 : {
77 0 : SkASSERT(bits <= 63);
78 0 : if (bits == 0)
79 0 : return;
80 :
81 0 : if (bits >= 32)
82 : {
83 0 : fLo = fHi >> (bits - 32);
84 0 : fHi >>= 31;
85 : }
86 : else
87 : {
88 0 : fLo = (fHi << (32 - bits)) | (fLo >> bits);
89 0 : fHi >>= bits;
90 : }
91 : }
92 :
93 0 : void Sk64::roundRight(unsigned bits)
94 : {
95 0 : SkASSERT(bits <= 63);
96 0 : if (bits)
97 : {
98 : Sk64 one;
99 0 : one.set(1);
100 0 : one.shiftLeft(bits - 1);
101 0 : this->add(one);
102 0 : this->shiftRight(bits);
103 : }
104 0 : }
105 :
106 0 : int Sk64::shiftToMake32() const
107 : {
108 0 : int32_t hi = fHi;
109 0 : uint32_t lo = fLo;
110 :
111 0 : if (hi < 0) // make it positive
112 : {
113 0 : hi = -hi - Sk32ToBool(lo);
114 0 : lo = 0 - lo;
115 : }
116 :
117 0 : if (hi == 0)
118 0 : return lo >> 31;
119 : else
120 0 : return 33 - SkCLZ(hi);
121 : }
122 :
123 0 : void Sk64::negate()
124 : {
125 0 : fHi = -fHi - Sk32ToBool(fLo);
126 0 : fLo = 0 - fLo;
127 0 : }
128 :
129 0 : void Sk64::abs()
130 : {
131 0 : if (fHi < 0)
132 : {
133 0 : fHi = -fHi - Sk32ToBool(fLo);
134 0 : fLo = 0 - fLo;
135 : }
136 0 : }
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 0 : SkBool Sk64::isFixed() const
148 : {
149 0 : Sk64 tmp = *this;
150 0 : tmp.roundRight(16);
151 0 : return tmp.is32();
152 : }
153 :
154 0 : SkFract Sk64::getFract() const
155 : {
156 0 : Sk64 tmp = *this;
157 0 : tmp.roundRight(30);
158 0 : return tmp.get32();
159 : }
160 :
161 0 : void Sk64::sub(const Sk64& a)
162 : {
163 0 : fHi = fHi - a.fHi - (fLo < a.fLo);
164 0 : fLo = fLo - a.fLo;
165 0 : }
166 :
167 0 : void Sk64::rsub(const Sk64& a)
168 : {
169 0 : fHi = a.fHi - fHi - (a.fLo < fLo);
170 0 : fLo = a.fLo - fLo;
171 0 : }
172 :
173 0 : void Sk64::setMul(int32_t a, int32_t b)
174 : {
175 0 : int sa = a >> 31;
176 0 : int sb = b >> 31;
177 : // now make them positive
178 0 : a = (a ^ sa) - sa;
179 0 : b = (b ^ sb) - sb;
180 :
181 0 : uint32_t ah = a >> 16;
182 0 : uint32_t al = a & 0xFFFF;
183 0 : uint32_t bh = b >> 16;
184 0 : uint32_t bl = b & 0xFFFF;
185 :
186 0 : uint32_t A = ah * bh;
187 0 : uint32_t B = ah * bl + al * bh;
188 0 : uint32_t C = al * bl;
189 :
190 : /* [ A ]
191 : [ B ]
192 : [ C ]
193 : */
194 0 : fLo = C + (B << 16);
195 0 : fHi = A + (B >>16) + (fLo < C);
196 :
197 0 : if (sa != sb)
198 0 : this->negate();
199 0 : }
200 :
201 0 : void Sk64::div(int32_t denom, DivOptions option)
202 : {
203 0 : SkASSERT(denom);
204 :
205 0 : int32_t hi = fHi;
206 0 : uint32_t lo = fLo;
207 0 : int sign = denom ^ hi;
208 :
209 0 : denom = SkAbs32(denom);
210 0 : if (hi < 0)
211 : {
212 0 : hi = -hi - Sk32ToBool(lo);
213 0 : lo = 0 - lo;
214 : }
215 :
216 0 : if (option == kRound_DivOption) // add denom/2
217 : {
218 0 : uint32_t newLo = lo + (denom >> 1);
219 0 : hi += (newLo < lo);
220 0 : lo = newLo;
221 : }
222 :
223 0 : if (hi == 0) // fast-case
224 : {
225 0 : if (lo < (uint32_t)denom)
226 0 : this->set(0, 0);
227 : else
228 : {
229 0 : this->set(0, lo / denom);
230 0 : if (sign < 0)
231 0 : this->negate();
232 : }
233 0 : return;
234 : }
235 :
236 : int bits;
237 :
238 : {
239 0 : int dbits = SkCLZ(denom);
240 0 : int nbits = SkCLZ(hi);
241 :
242 0 : bits = 32 + dbits - nbits;
243 0 : SkASSERT(bits <= 63);
244 0 : if (bits <= 0)
245 : {
246 0 : this->set(0, 0);
247 0 : return;
248 : }
249 0 : denom <<= (dbits - 1);
250 0 : shift_left_bits(hi, lo, nbits - 1);
251 : }
252 :
253 0 : int32_t rhi = 0;
254 0 : uint32_t rlo = 0;
255 :
256 0 : do {
257 0 : 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 0 : int32_t diff = (denom - hi - 1) >> 31;
266 0 : hi -= denom & diff;
267 0 : rlo -= diff;
268 : #endif
269 0 : shift_left(hi, lo);
270 : } while (--bits >= 0);
271 0 : SkASSERT(rhi >= 0);
272 :
273 0 : fHi = rhi;
274 0 : fLo = rlo;
275 0 : if (sign < 0)
276 0 : 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 0 : int32_t Sk64::getSqrt() const
285 : {
286 0 : SkASSERT(!this->isNeg());
287 :
288 0 : uint32_t hi = fHi;
289 0 : uint32_t lo = fLo;
290 0 : uint32_t sqr = 0;
291 0 : uint32_t root = 0;
292 0 : int count = 31;
293 :
294 0 : do {
295 0 : root <<= 1;
296 0 : shift_left_2(sqr, hi, lo);
297 :
298 0 : uint32_t testDiv = (root << 1) + 1;
299 0 : if (sqr >= testDiv)
300 : {
301 0 : sqr -= testDiv;
302 0 : root++;
303 : }
304 : } while (--count >= 0);
305 0 : SkASSERT((int32_t)root >= 0);
306 :
307 0 : 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 0 : SkFixed Sk64::getFixedDiv(const Sk64& denom) const
320 : {
321 0 : Sk64 N = *this;
322 0 : Sk64 D = denom;
323 0 : int32_t sign = SkExtractSign(N.fHi ^ D.fHi);
324 : SkFixed result;
325 :
326 0 : N.abs();
327 0 : 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 0 : int nclz = N.fHi ? SkCLZ(N.fHi) : 32;
334 0 : int dclz = D.fHi ? SkCLZ(D.fHi) : (33 - (D.fLo >> 31));
335 :
336 0 : int shiftN = nclz - 1;
337 0 : SkASSERT(shiftN >= 0);
338 0 : int shiftD = 33 - dclz;
339 0 : SkASSERT(shiftD >= 0);
340 :
341 0 : if (shiftD + shiftN < 16)
342 0 : shiftD = 16 - shiftN;
343 : else
344 0 : shiftN = 16 - shiftD;
345 :
346 0 : D.roundRight(shiftD);
347 0 : if (D.isZero())
348 0 : result = SK_MaxS32;
349 : else
350 : {
351 0 : if (shiftN >= 0)
352 0 : N.shiftLeft(shiftN);
353 : else
354 0 : N.roundRight(-shiftN);
355 0 : N.div(D.get32(), Sk64::kTrunc_DivOption);
356 0 : if (N.is32())
357 0 : result = N.get32();
358 : else
359 0 : result = SK_MaxS32;
360 : }
361 0 : return SkApplySign(result, sign);
362 : }
363 :
|