floatdidf.c revision 37b97d1cf4501b94347e0b4e880f4b25825a289f
137a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan/*===-- floatdidf.c - Implement __floatdidf -------------------------------=== 237a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * 337a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * The LLVM Compiler Infrastructure 437a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * 59ad441ffec97db647fee3725b3424284fb913e14Howard Hinnant * This file is dual licensed under the MIT and the University of Illinois Open 69ad441ffec97db647fee3725b3424284fb913e14Howard Hinnant * Source Licenses. See LICENSE.TXT for details. 737a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * 837a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan *===----------------------------------------------------------------------=== 937a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * 1037a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * This file implements __floatdidf for the compiler_rt library. 1137a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * 1237a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan *===----------------------------------------------------------------------=== 1337a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan */ 14b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 15b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar#include "int_lib.h" 16b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar#include <float.h> 17b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 1837a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan/* Returns: convert a to a double, rounding toward even. */ 19b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 2037a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan/* Assumption: double is a IEEE 64 bit floating point type 2137a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * di_int is a 64 bit integral type 2237a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan */ 23b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 2437a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ 25b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 2637b97d1cf4501b94347e0b4e880f4b25825a289fAnton Korobeynikov#include "int_lib.h" 2737b97d1cf4501b94347e0b4e880f4b25825a289fAnton Korobeynikov 2837b97d1cf4501b94347e0b4e880f4b25825a289fAnton KorobeynikovARM_EABI_FNALIAS(l2d, floatdidf); 2937b97d1cf4501b94347e0b4e880f4b25825a289fAnton Korobeynikov 30b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar#ifndef __SOFT_FP__ 3137a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan/* Support for systems that have hardware floating-point; we'll set the inexact flag 3237a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * as a side-effect of this computation. 3337a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan */ 34b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar#include <stdint.h> 35b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 36b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbardouble 37b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar__floatdidf(di_int a) 38b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar{ 39b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar static const double twop52 = 0x1.0p52; 40b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar static const double twop32 = 0x1.0p32; 41b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 42b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar union { int64_t x; double d; } low = { .d = twop52 }; 43b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 44b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar const double high = (int32_t)(a >> 32) * twop32; 45b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar low.x |= a & INT64_C(0x00000000ffffffff); 46b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 47b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar const double result = (high - twop52) + low.d; 48b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar return result; 49b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar} 50b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 51b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar#else 5237a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan/* Support for systems that don't have hardware floating-point; there are no flags to 5337a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * set, and we don't want to code-gen to an unknown soft-float implementation. 5437a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan */ 55b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar 56b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbardouble 57b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar__floatdidf(di_int a) 58b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar{ 59b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar if (a == 0) 60b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar return 0.0; 61b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar const unsigned N = sizeof(di_int) * CHAR_BIT; 62b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar const di_int s = a >> (N-1); 63b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar a = (a ^ s) - s; 6437a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan int sd = N - __builtin_clzll(a); /* number of significant digits */ 6537a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan int e = sd - 1; /* exponent */ 66b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar if (sd > DBL_MANT_DIG) 67b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar { 6837a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx 6937a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR 7037a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * 12345678901234567890123456 7137a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * 1 = msb 1 bit 7237a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * P = bit DBL_MANT_DIG-1 bits to the right of 1 7337a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * Q = bit DBL_MANT_DIG bits to the right of 1 7437a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan * R = "or" of all bits to the right of Q 7537a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan */ 76b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar switch (sd) 77b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar { 78b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar case DBL_MANT_DIG + 1: 79b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar a <<= 1; 80b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar break; 81b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar case DBL_MANT_DIG + 2: 82b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar break; 83b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar default: 84b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar a = ((du_int)a >> (sd - (DBL_MANT_DIG+2))) | 85b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); 86b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar }; 8737a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan /* finish: */ 8837a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan a |= (a & 4) != 0; /* Or P into R */ 8937a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan ++a; /* round - this step may add a significant bit */ 9037a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan a >>= 2; /* dump Q and R */ 9137a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ 92b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar if (a & ((du_int)1 << DBL_MANT_DIG)) 93b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar { 94b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar a >>= 1; 95b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar ++e; 96b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar } 9737a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan /* a is now rounded to DBL_MANT_DIG bits */ 98b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar } 99b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar else 100b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar { 101b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar a <<= (DBL_MANT_DIG - sd); 10237a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan /* a is now rounded to DBL_MANT_DIG bits */ 103b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar } 104b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar double_bits fb; 10537a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan fb.u.high = ((su_int)s & 0x80000000) | /* sign */ 10637a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan ((e + 1023) << 20) | /* exponent */ 10737a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ 10837a6a455466e5b197311771a777ab241e471ed8aEdward O'Callaghan fb.u.low = (su_int)a; /* mantissa-low */ 109b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar return fb.f; 110b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar} 111b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar#endif 112