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