1 /*
2  * Copyright 2011 Google Inc.
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 
8 #include "SkFloatBits.h"
9 #include "SkMathPriv.h"
10 
11 /******************************************************************************
12     SkFloatBits_toInt[Floor, Round, Ceil] are identical except for what they
13     do right before they return ... >> exp;
14     Floor - adds nothing
15     Round - adds 1 << (exp - 1)
16     Ceil - adds (1 << exp) - 1
17 
18     Floor and Cast are very similar, but Cast applies its sign after all other
19     computations on value. Also, Cast does not need to check for negative zero,
20     as that value (0x80000000) "does the right thing" for Ceil. Note that it
21     doesn't for Floor/Round/Ceil, hence the explicit check.
22 ******************************************************************************/
23 
24 #define EXP_BIAS            (127+23)
25 #define MATISSA_MAGIC_BIG   (1 << 23)
26 
unpack_exp(uint32_t packed)27 static inline int unpack_exp(uint32_t packed) {
28     return (packed << 1 >> 24);
29 }
30 
31 #if 0
32 // the ARM compiler generates an extra BIC, so I use the dirty version instead
33 static inline int unpack_matissa(uint32_t packed) {
34     // we could mask with 0x7FFFFF, but that is harder for ARM to encode
35     return (packed & ~0xFF000000) | MATISSA_MAGIC_BIG;
36 }
37 #endif
38 
39 // returns the low 24-bits, so we need to OR in the magic_bit afterwards
unpack_matissa_dirty(uint32_t packed)40 static inline int unpack_matissa_dirty(uint32_t packed) {
41     return packed & ~0xFF000000;
42 }
43 
44 // same as (int)float
SkFloatBits_toIntCast(int32_t packed)45 int32_t SkFloatBits_toIntCast(int32_t packed) {
46     int exp = unpack_exp(packed) - EXP_BIAS;
47     int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
48 
49     if (exp >= 0) {
50         if (exp > 7) {    // overflow
51             value = SK_MaxS32;
52         } else {
53             value <<= exp;
54         }
55     } else {
56         exp = -exp;
57         if (exp > 25) {   // underflow
58             exp = 25;
59         }
60         value >>= exp;
61     }
62     return SkApplySign(value, SkExtractSign(packed));
63 }
64 
65 // same as (int)floor(float)
SkFloatBits_toIntFloor(int32_t packed)66 int32_t SkFloatBits_toIntFloor(int32_t packed) {
67     // curse you negative 0
68     if ((packed << 1) == 0) {
69         return 0;
70     }
71 
72     int exp = unpack_exp(packed) - EXP_BIAS;
73     int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
74 
75     if (exp >= 0) {
76         if (exp > 7) {    // overflow
77             value = SK_MaxS32;
78         } else {
79             value <<= exp;
80         }
81         // apply the sign after we check for overflow
82         return SkApplySign(value, SkExtractSign(packed));
83     } else {
84         // apply the sign before we right-shift
85         value = SkApplySign(value, SkExtractSign(packed));
86         exp = -exp;
87         if (exp > 25) {   // underflow
88 #ifdef SK_DISCARD_DENORMALIZED_FOR_SPEED
89         // The iOS ARM processor discards small denormalized numbers to go faster.
90         // The comparision below empirically causes the result to agree with the
91         // tests in MathTest test_float_floor
92             if (exp > 149) {
93                 return 0;
94             }
95 #else
96             exp = 25;
97 #endif
98         }
99         // int add = 0;
100         return value >> exp;
101     }
102 }
103 
104 // same as (int)floor(float + 0.5)
SkFloatBits_toIntRound(int32_t packed)105 int32_t SkFloatBits_toIntRound(int32_t packed) {
106     // curse you negative 0
107     if ((packed << 1) == 0) {
108         return 0;
109     }
110 
111     int exp = unpack_exp(packed) - EXP_BIAS;
112     int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
113 
114     if (exp >= 0) {
115         if (exp > 7) {    // overflow
116             value = SK_MaxS32;
117         } else {
118             value <<= exp;
119         }
120         // apply the sign after we check for overflow
121         return SkApplySign(value, SkExtractSign(packed));
122     } else {
123         // apply the sign before we right-shift
124         value = SkApplySign(value, SkExtractSign(packed));
125         exp = -exp;
126         if (exp > 25) {   // underflow
127             exp = 25;
128         }
129         int add = 1 << (exp - 1);
130         return (value + add) >> exp;
131     }
132 }
133 
134 // same as (int)ceil(float)
SkFloatBits_toIntCeil(int32_t packed)135 int32_t SkFloatBits_toIntCeil(int32_t packed) {
136     // curse you negative 0
137     if ((packed << 1) == 0) {
138         return 0;
139     }
140 
141     int exp = unpack_exp(packed) - EXP_BIAS;
142     int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
143 
144     if (exp >= 0) {
145         if (exp > 7) {    // overflow
146             value = SK_MaxS32;
147         } else {
148             value <<= exp;
149         }
150         // apply the sign after we check for overflow
151         return SkApplySign(value, SkExtractSign(packed));
152     } else {
153         // apply the sign before we right-shift
154         value = SkApplySign(value, SkExtractSign(packed));
155         exp = -exp;
156         if (exp > 25) {   // underflow
157 #ifdef SK_DISCARD_DENORMALIZED_FOR_SPEED
158         // The iOS ARM processor discards small denormalized numbers to go faster.
159         // The comparision below empirically causes the result to agree with the
160         // tests in MathTest test_float_ceil
161             if (exp > 149) {
162                 return 0;
163             }
164             return 0 < value;
165 #else
166             exp = 25;
167 #endif
168         }
169         int add = (1 << exp) - 1;
170         return (value + add) >> exp;
171     }
172 }
173 
SkIntToFloatCast(int32_t value)174 float SkIntToFloatCast(int32_t value) {
175     if (0 == value) {
176         return 0;
177     }
178 
179     int shift = EXP_BIAS;
180 
181     // record the sign and make value positive
182     int sign = SkExtractSign(value);
183     value = SkApplySign(value, sign);
184 
185     if (value >> 24) {    // value is too big (has more than 24 bits set)
186         int bias = 8 - SkCLZ(value);
187         SkDebugf("value = %d, bias = %d\n", value, bias);
188         SkASSERT(bias > 0 && bias < 8);
189         value >>= bias; // need to round?
190         shift += bias;
191     } else {
192         int zeros = SkCLZ(value << 8);
193         SkASSERT(zeros >= 0 && zeros <= 23);
194         value <<= zeros;
195         shift -= zeros;
196     }
197 
198     // now value is left-aligned to 24 bits
199     SkASSERT((value >> 23) == 1);
200     SkASSERT(shift >= 0 && shift <= 255);
201 
202     SkFloatIntUnion data;
203     data.fSignBitInt = (sign << 31) | (shift << 23) | (value & ~MATISSA_MAGIC_BIG);
204     return data.fFloat;
205 }
206