1 /*
2  *  Union to access IEEE double memory representation, indexes for double
3  *  memory representation, and some macros for double manipulation.
4  *
5  *  Also used by packed duk_tval.  Use a union for bit manipulation to
6  *  minimize aliasing issues in practice.  The C99 standard does not
7  *  guarantee that this should work, but it's a very widely supported
8  *  practice for low level manipulation.
9  *
10  *  IEEE double format summary:
11  *
12  *    seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
13  *       A        B        C        D        E        F        G        H
14  *
15  *    s       sign bit
16  *    eee...  exponent field
17  *    fff...  fraction
18  *
19  *  See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
20  *
21  *  NaNs are represented as exponent 0x7ff and mantissa != 0.  The NaN is a
22  *  signaling NaN when the highest bit of the mantissa is zero, and a quiet
23  *  NaN when the highest bit is set.
24  *
25  *  At least three memory layouts are relevant here:
26  *
27  *    A B C D E F G H    Big endian (e.g. 68k)           DUK_USE_DOUBLE_BE
28  *    H G F E D C B A    Little endian (e.g. x86)        DUK_USE_DOUBLE_LE
29  *    D C B A H G F E    Mixed endian (e.g. ARM FPA)     DUK_USE_DOUBLE_ME
30  *
31  *  Legacy ARM (FPA) is a special case: ARM double values are in mixed
32  *  endian format while ARM duk_uint64_t values are in standard little endian
33  *  format (H G F E D C B A).  When a double is read as a duk_uint64_t
34  *  from memory, the register will contain the (logical) value
35  *  E F G H A B C D.  This requires some special handling below.
36  *  See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Bcfhgcgd.html.
37  *
38  *  Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
39  *  the logical (big endian) order:
40  *
41  *  byte order      duk_uint8_t    duk_uint16_t     duk_uint32_t
42  *    BE             01234567         0123               01
43  *    LE             76543210         3210               10
44  *    ME (ARM)       32107654         1032               01
45  *
46  *  Some processors may alter NaN values in a floating point load+store.
47  *  For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
48  *  quiet one.  This is catastrophic when NaN space is used in packed
49  *  duk_tval values.  See: misc/clang_aliasing.c.
50  */
51 
52 #if !defined(DUK_DBLUNION_H_INCLUDED)
53 #define DUK_DBLUNION_H_INCLUDED
54 
55 /*
56  *  Union for accessing double parts, also serves as packed duk_tval
57  */
58 
59 union duk_double_union {
60 	double d;
61 	float f[2];
62 #if defined(DUK_USE_64BIT_OPS)
63 	duk_uint64_t ull[1];
64 #endif
65 	duk_uint32_t ui[2];
66 	duk_uint16_t us[4];
67 	duk_uint8_t uc[8];
68 #if defined(DUK_USE_PACKED_TVAL)
69 	void *vp[2];  /* used by packed duk_tval, assumes sizeof(void *) == 4 */
70 #endif
71 };
72 
73 typedef union duk_double_union duk_double_union;
74 
75 /*
76  *  Indexes of various types with respect to big endian (logical) layout
77  */
78 
79 #if defined(DUK_USE_DOUBLE_LE)
80 #if defined(DUK_USE_64BIT_OPS)
81 #define DUK_DBL_IDX_ULL0   0
82 #endif
83 #define DUK_DBL_IDX_UI0    1
84 #define DUK_DBL_IDX_UI1    0
85 #define DUK_DBL_IDX_US0    3
86 #define DUK_DBL_IDX_US1    2
87 #define DUK_DBL_IDX_US2    1
88 #define DUK_DBL_IDX_US3    0
89 #define DUK_DBL_IDX_UC0    7
90 #define DUK_DBL_IDX_UC1    6
91 #define DUK_DBL_IDX_UC2    5
92 #define DUK_DBL_IDX_UC3    4
93 #define DUK_DBL_IDX_UC4    3
94 #define DUK_DBL_IDX_UC5    2
95 #define DUK_DBL_IDX_UC6    1
96 #define DUK_DBL_IDX_UC7    0
97 #define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
98 #define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
99 #elif defined(DUK_USE_DOUBLE_BE)
100 #if defined(DUK_USE_64BIT_OPS)
101 #define DUK_DBL_IDX_ULL0   0
102 #endif
103 #define DUK_DBL_IDX_UI0    0
104 #define DUK_DBL_IDX_UI1    1
105 #define DUK_DBL_IDX_US0    0
106 #define DUK_DBL_IDX_US1    1
107 #define DUK_DBL_IDX_US2    2
108 #define DUK_DBL_IDX_US3    3
109 #define DUK_DBL_IDX_UC0    0
110 #define DUK_DBL_IDX_UC1    1
111 #define DUK_DBL_IDX_UC2    2
112 #define DUK_DBL_IDX_UC3    3
113 #define DUK_DBL_IDX_UC4    4
114 #define DUK_DBL_IDX_UC5    5
115 #define DUK_DBL_IDX_UC6    6
116 #define DUK_DBL_IDX_UC7    7
117 #define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
118 #define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
119 #elif defined(DUK_USE_DOUBLE_ME)
120 #if defined(DUK_USE_64BIT_OPS)
121 #define DUK_DBL_IDX_ULL0   0  /* not directly applicable, byte order differs from a double */
122 #endif
123 #define DUK_DBL_IDX_UI0    0
124 #define DUK_DBL_IDX_UI1    1
125 #define DUK_DBL_IDX_US0    1
126 #define DUK_DBL_IDX_US1    0
127 #define DUK_DBL_IDX_US2    3
128 #define DUK_DBL_IDX_US3    2
129 #define DUK_DBL_IDX_UC0    3
130 #define DUK_DBL_IDX_UC1    2
131 #define DUK_DBL_IDX_UC2    1
132 #define DUK_DBL_IDX_UC3    0
133 #define DUK_DBL_IDX_UC4    7
134 #define DUK_DBL_IDX_UC5    6
135 #define DUK_DBL_IDX_UC6    5
136 #define DUK_DBL_IDX_UC7    4
137 #define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
138 #define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
139 #else
140 #error internal error
141 #endif
142 
143 /*
144  *  Helper macros for reading/writing memory representation parts, used
145  *  by duk_numconv.c and duk_tval.h.
146  */
147 
148 #define DUK_DBLUNION_SET_DOUBLE(u,v)  do {  \
149 		(u)->d = (v); \
150 	} while (0)
151 
152 #define DUK_DBLUNION_SET_HIGH32(u,v)  do {  \
153 		(u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
154 	} while (0)
155 
156 #if defined(DUK_USE_64BIT_OPS)
157 #if defined(DUK_USE_DOUBLE_ME)
158 #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
159 		(u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
160 	} while (0)
161 #else
162 #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
163 		(u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
164 	} while (0)
165 #endif
166 #else  /* DUK_USE_64BIT_OPS */
167 #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
168 		(u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
169 		(u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
170 	} while (0)
171 #endif  /* DUK_USE_64BIT_OPS */
172 
173 #define DUK_DBLUNION_SET_LOW32(u,v)  do {  \
174 		(u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
175 	} while (0)
176 
177 #define DUK_DBLUNION_GET_DOUBLE(u)  ((u)->d)
178 #define DUK_DBLUNION_GET_HIGH32(u)  ((u)->ui[DUK_DBL_IDX_UI0])
179 #define DUK_DBLUNION_GET_LOW32(u)   ((u)->ui[DUK_DBL_IDX_UI1])
180 
181 #if defined(DUK_USE_64BIT_OPS)
182 #if defined(DUK_USE_DOUBLE_ME)
183 #define DUK_DBLUNION_SET_UINT64(u,v)  do { \
184 		(u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \
185 		(u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
186 	} while (0)
187 #define DUK_DBLUNION_GET_UINT64(u) \
188 	((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \
189 	 ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1]))
190 #else
191 #define DUK_DBLUNION_SET_UINT64(u,v)  do { \
192 		(u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
193 	} while (0)
194 #define DUK_DBLUNION_GET_UINT64(u)  ((u)->ull[DUK_DBL_IDX_ULL0])
195 #endif
196 #define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v))
197 #define DUK_DBLUNION_GET_INT64(u)   ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u)))
198 #endif  /* DUK_USE_64BIT_OPS */
199 
200 /*
201  *  Double NaN manipulation macros related to NaN normalization needed when
202  *  using the packed duk_tval representation.  NaN normalization is necessary
203  *  to keep double values compatible with the duk_tval format.
204  *
205  *  When packed duk_tval is used, the NaN space is used to store pointers
206  *  and other tagged values in addition to NaNs.  Actual NaNs are normalized
207  *  to a specific quiet NaN.  The macros below are used by the implementation
208  *  to check and normalize NaN values when they might be created.  The macros
209  *  are essentially NOPs when the non-packed duk_tval representation is used.
210  *
211  *  A FULL check is exact and checks all bits.  A NOTFULL check is used by
212  *  the packed duk_tval and works correctly for all NaNs except those that
213  *  begin with 0x7ff0.  Since the 'normalized NaN' values used with packed
214  *  duk_tval begin with 0x7ff8, the partial check is reliable when packed
215  *  duk_tval is used.  The 0x7ff8 prefix means the normalized NaN will be a
216  *  quiet NaN regardless of its remaining lower bits.
217  *
218  *  The ME variant below is specifically for ARM byte order, which has the
219  *  feature that while doubles have a mixed byte order (32107654), unsigned
220  *  long long values has a little endian byte order (76543210).  When writing
221  *  a logical double value through a ULL pointer, the 32-bit words need to be
222  *  swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME.
223  *  This is not full ARM support but suffices for some environments.
224  */
225 
226 #if defined(DUK_USE_64BIT_OPS)
227 #if defined(DUK_USE_DOUBLE_ME)
228 /* Macros for 64-bit ops + mixed endian doubles. */
229 #define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
230 		(u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \
231 	} while (0)
232 #define DUK__DBLUNION_IS_NAN_FULL(u) \
233 	((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \
234 	 ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0))
235 #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
236 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000))
237 #define DUK__DBLUNION_IS_ANYINF(u) \
238 	(((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000))
239 #define DUK__DBLUNION_IS_POSINF(u) \
240 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000))
241 #define DUK__DBLUNION_IS_NEGINF(u) \
242 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000))
243 #define DUK__DBLUNION_IS_ANYZERO(u) \
244 	(((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
245 #define DUK__DBLUNION_IS_POSZERO(u) \
246 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
247 #define DUK__DBLUNION_IS_NEGZERO(u) \
248 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000))
249 #else
250 /* Macros for 64-bit ops + big/little endian doubles. */
251 #define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
252 		(u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \
253 	} while (0)
254 #define DUK__DBLUNION_IS_NAN_FULL(u) \
255 	((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \
256 	 ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0))
257 #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
258 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000))
259 #define DUK__DBLUNION_IS_ANYINF(u) \
260 	(((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000))
261 #define DUK__DBLUNION_IS_POSINF(u) \
262 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000))
263 #define DUK__DBLUNION_IS_NEGINF(u) \
264 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000))
265 #define DUK__DBLUNION_IS_ANYZERO(u) \
266 	(((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
267 #define DUK__DBLUNION_IS_POSZERO(u) \
268 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
269 #define DUK__DBLUNION_IS_NEGZERO(u) \
270 	((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000))
271 #endif
272 #else  /* DUK_USE_64BIT_OPS */
273 /* Macros for no 64-bit ops, any endianness. */
274 #define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
275 		(u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
276 		(u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
277 	} while (0)
278 #define DUK__DBLUNION_IS_NAN_FULL(u) \
279 	((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
280 	 (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
281           (u)->ui[DUK_DBL_IDX_UI1] != 0))
282 #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
283 	(((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
284 	 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
285 #define DUK__DBLUNION_IS_ANYINF(u) \
286 	((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \
287 	 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
288 #define DUK__DBLUNION_IS_POSINF(u) \
289 	(((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \
290 	 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
291 #define DUK__DBLUNION_IS_NEGINF(u) \
292 	(((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \
293 	 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
294 #define DUK__DBLUNION_IS_ANYZERO(u) \
295 	((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \
296 	 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
297 #define DUK__DBLUNION_IS_POSZERO(u) \
298 	(((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \
299 	 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
300 #define DUK__DBLUNION_IS_NEGZERO(u) \
301 	(((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \
302 	 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
303 #endif  /* DUK_USE_64BIT_OPS */
304 
305 #define DUK__DBLUNION_SET_NAN_NOTFULL(u)  do { \
306 		(u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
307 	} while (0)
308 
309 #define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
310 	/* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
311 	((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
312 	 (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
313 
314 #define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
315 	/* E == 0x7ff, F == 8 => normalized NaN */ \
316 	((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
317 
318 #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u)  do { \
319 		if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
320 			DUK__DBLUNION_SET_NAN_FULL((u)); \
321 		} \
322 	} while (0)
323 
324 #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u)  do { \
325 		/* Check must be full. */ \
326 		if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
327 			DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
328 		} \
329 	} while (0)
330 
331 /* Concrete macros for NaN handling used by the implementation internals.
332  * Chosen so that they match the duk_tval representation: with a packed
333  * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
334  * these are essentially NOPs.
335  */
336 
337 #if defined(DUK_USE_PACKED_TVAL)
338 #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
339 #define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_FULL((u))
340 #define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
341 #define DUK_DBLUNION_SET_NAN(d)              DUK__DBLUNION_SET_NAN_FULL((d))
342 #if 0
343 #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
344 #define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_NOTFULL((u))
345 #define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
346 #define DUK_DBLUNION_SET_NAN(d)              DUK__DBLUNION_SET_NAN_NOTFULL((d))
347 #endif
348 #define DUK_DBLUNION_IS_NORMALIZED(u) \
349 	(!DUK_DBLUNION_IS_NAN((u)) ||  /* either not a NaN */ \
350 	 DUK_DBLUNION_IS_NORMALIZED_NAN((u)))  /* or is a normalized NaN */
351 #else  /* DUK_USE_PACKED_TVAL */
352 #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  /* nop: no need to normalize */
353 #define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_FULL((u))  /* (DUK_ISNAN((u)->d)) */
354 #define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NAN_FULL((u))  /* (DUK_ISNAN((u)->d)) */
355 #define DUK_DBLUNION_IS_NORMALIZED(u)        1  /* all doubles are considered normalized */
356 #define DUK_DBLUNION_SET_NAN(u)  do { \
357 		/* in non-packed representation we don't care about which NaN is used */ \
358 		(u)->d = DUK_DOUBLE_NAN; \
359 	} while (0)
360 #endif  /* DUK_USE_PACKED_TVAL */
361 
362 #define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u))
363 #define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u))
364 #define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u))
365 
366 #define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u))
367 #define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u))
368 #define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u))
369 
370 /* XXX: native 64-bit byteswaps when available */
371 
372 /* 64-bit byteswap, same operation independent of target endianness. */
373 #define DUK_DBLUNION_BSWAP64(u) do { \
374 		duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
375 		duk__bswaptmp1 = (u)->ui[0]; \
376 		duk__bswaptmp2 = (u)->ui[1]; \
377 		duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
378 		duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
379 		(u)->ui[0] = duk__bswaptmp2; \
380 		(u)->ui[1] = duk__bswaptmp1; \
381 	} while (0)
382 
383 /* Byteswap an IEEE double in the duk_double_union from host to network
384  * order.  For a big endian target this is a no-op.
385  */
386 #if defined(DUK_USE_DOUBLE_LE)
387 #define DUK_DBLUNION_DOUBLE_HTON(u) do { \
388 		duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
389 		duk__bswaptmp1 = (u)->ui[0]; \
390 		duk__bswaptmp2 = (u)->ui[1]; \
391 		duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
392 		duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
393 		(u)->ui[0] = duk__bswaptmp2; \
394 		(u)->ui[1] = duk__bswaptmp1; \
395 	} while (0)
396 #elif defined(DUK_USE_DOUBLE_ME)
397 #define DUK_DBLUNION_DOUBLE_HTON(u) do { \
398 		duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
399 		duk__bswaptmp1 = (u)->ui[0]; \
400 		duk__bswaptmp2 = (u)->ui[1]; \
401 		duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
402 		duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
403 		(u)->ui[0] = duk__bswaptmp1; \
404 		(u)->ui[1] = duk__bswaptmp2; \
405 	} while (0)
406 #elif defined(DUK_USE_DOUBLE_BE)
407 #define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0)
408 #else
409 #error internal error, double endianness insane
410 #endif
411 
412 /* Reverse operation is the same. */
413 #define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u))
414 
415 /* Some sign bit helpers. */
416 #if defined(DUK_USE_64BIT_OPS)
417 #define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0)
418 #define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U))
419 #else
420 #define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0)
421 #define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U))
422 #endif
423 
424 #endif  /* DUK_DBLUNION_H_INCLUDED */
425