Index: lib/builtins/fixunsxfti.c =================================================================== --- lib/builtins/fixunsxfti.c +++ lib/builtins/fixunsxfti.c @@ -20,30 +20,49 @@ * Negative values all become zero. */ -/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes - * tu_int is a 128 bit integral type - * value in long double is representable in tu_int or is negative +/* Assumption: + * if __LDBL_MANT_DIG__ == 64, it's Intel 80-bit FP representation: + * long double is an intel 80 bit floating point type padded with 6 bytes: + * gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + * if __LDBL_MANT_DIG__ == 113, it's IEEE754 quad-precision floating point type: + * sign: bit 127, exp: bit 126 - 112, mantissa: bit 111 - 0. + * tu_int is a 128 bit integral type + * value in long double is representable in tu_int or is negative */ -/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | - * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm - */ COMPILER_RT_ABI tu_int __fixunsxfti(long double a) { long_double_bits fb; fb.f = a; +#if __LDBL_MANT_DIG__ == 113 + // IEEE754 quad-precision floating point type. + // sign: fb.u.high.s.high[31] + // exp: fb.u.high.s.high[16:30] + // mantissa: fb.u.high.s.high[0:15] | fb.u.high.s.low | fb.u.low.all + int isNeg = (fb.u.high.s.high >> 31); + int e = (fb.u.high.s.high >> 16) - 16383; + // clear the sign and exponent fields and set implicit one. + tu_int r = (tu_int)((fb.u.high.s.high & 0xFFFF) | (1 << 16)) << 96; + r |= (tu_int)fb.u.high.s.low << 64; + r |= fb.u.low.all; +#elif __LDBL_MANT_DIG__ == 64 + int isNeg = fb.u.high.s.low & 0x00008000; int e = (fb.u.high.s.low & 0x00007FFF) - 16383; - if (e < 0 || (fb.u.high.s.low & 0x00008000)) + tu_int r = fb.u.low.all; +#else +# error("Unsupported __LDBL_MANT_DIG__:" ## __LDBL_MANT_DIG__) +#endif + if (e < 0 || isNeg) return 0; if ((unsigned)e > sizeof(tu_int) * CHAR_BIT) return ~(tu_int)0; - tu_int r = fb.u.low.all; - if (e > 63) - r <<= (e - 63); + if (e >= __LDBL_MANT_DIG__) + r <<= (e - __LDBL_MANT_DIG__ + 1); else - r >>= (63 - e); + r >>= (__LDBL_MANT_DIG__ - 1 - e); return r; } Index: test/builtins/Unit/fixunsxfti_test.c =================================================================== --- test/builtins/Unit/fixunsxfti_test.c +++ test/builtins/Unit/fixunsxfti_test.c @@ -1,5 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: aarch64 // test fails for aarch64 (see pr32260) //===-- fixunsxfti_test.c - Test __fixunsxfti -----------------------------===// @@ -23,13 +22,15 @@ // Returns: convert a to a unsigned long long, rounding toward zero. // Negative values all become zero. -// Assumption: long double is an intel 80 bit floating point type padded with 6 bytes -// tu_int is a 64 bit integral type -// value in long double is representable in tu_int or is negative -// (no range checking performed) - -// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | -// 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm +// Assumption: +// if __LDBL_MANT_DIG__ == 64, it's Intel 80-bit FP representation: +// long double is an intel 80 bit floating point type padded with 6 bytes: +// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | +// 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm +// if __LDBL_MANT_DIG__ == 113, it's IEEE754 quad-precision floating point type: +// sign: bit 127, exp: bit 126 - 112, mantissa: bit 111 - 0. +// tu_int is a 128 bit integral type +// value in long double is representable in tu_int or is negative COMPILER_RT_ABI tu_int __fixunsxfti(long double a); @@ -59,7 +60,6 @@ #ifdef CRT_HAS_128BIT if (test__fixunsxfti(0.0, 0)) return 1; - if (test__fixunsxfti(0.5, 0)) return 1; if (test__fixunsxfti(0.99, 0))