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