Index: lib/builtins/extenddftf2.c =================================================================== --- /dev/null +++ lib/builtins/extenddftf2.c @@ -0,0 +1,23 @@ +//===-- lib/extenddftf2.c - double -> quad conversion -------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +#define SRC_DOUBLE +#define DST_QUAD +#include "fp_extend_impl.inc" + +COMPILER_RT_ABI long double __extenddftf2(double a) { + return __extendXfYf2__(a); +} + +#endif Index: lib/builtins/extendsfdf2.c =================================================================== --- lib/builtins/extendsfdf2.c +++ lib/builtins/extendsfdf2.c @@ -7,132 +7,13 @@ // //===----------------------------------------------------------------------===// // -// This file implements a fairly generic conversion from a narrower to a wider -// IEEE-754 floating-point type. The constants and types defined following the -// includes below parameterize the conversion. -// -// This routine can be trivially adapted to support conversions from -// half-precision or to quad-precision. It does not support types that don't -// use the usual IEEE-754 interchange formats; specifically, some work would be -// needed to adapt it to (for example) the Intel 80-bit format or PowerPC -// double-double format. -// -// Note please, however, that this implementation is only intended to support -// *widening* operations; if you need to convert to a *narrower* floating-point -// type (e.g. double -> float), then this routine will not do what you want it -// to. -// -// It also requires that integer types at least as large as both formats -// are available on the target platform; this may pose a problem when trying -// to add support for quad on some 32-bit systems, for example. You also may -// run into trouble finding an appropriate CLZ function for wide source types; -// you will likely need to roll your own on some platforms. -// -// Finally, the following assumptions are made: -// -// 1. floating-point types and integer types have the same endianness on the -// target platform -// -// 2. quiet NaNs, if supported, are indicated by the leading bit of the -// significand field being set -// -//===----------------------------------------------------------------------===// - -#include "int_lib.h" -typedef float src_t; -typedef uint32_t src_rep_t; -#define SRC_REP_C UINT32_C -static const int srcSigBits = 23; -#define src_rep_t_clz __builtin_clz - -typedef double dst_t; -typedef uint64_t dst_rep_t; -#define DST_REP_C UINT64_C -static const int dstSigBits = 52; - -// End of specialization parameters. Two helper routines for conversion to and -// from the representation of floating-point data as integer values follow. - -static inline src_rep_t srcToRep(src_t x) { - const union { src_t f; src_rep_t i; } rep = {.f = x}; - return rep.i; -} - -static inline dst_t dstFromRep(dst_rep_t x) { - const union { dst_t f; dst_rep_t i; } rep = {.i = x}; - return rep.f; -} - -// End helper routines. Conversion implementation follows. +#define SRC_SINGLE +#define DST_DOUBLE +#include "fp_extend_impl.inc" ARM_EABI_FNALIAS(f2d, extendsfdf2) -COMPILER_RT_ABI dst_t -__extendsfdf2(src_t a) { - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const int srcBits = sizeof(src_t)*CHAR_BIT; - const int srcExpBits = srcBits - srcSigBits - 1; - const int srcInfExp = (1 << srcExpBits) - 1; - const int srcExpBias = srcInfExp >> 1; - - const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits; - const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits; - const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits); - const src_rep_t srcAbsMask = srcSignMask - 1; - const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1); - const src_rep_t srcNaNCode = srcQNaN - 1; - - const int dstBits = sizeof(dst_t)*CHAR_BIT; - const int dstExpBits = dstBits - dstSigBits - 1; - const int dstInfExp = (1 << dstExpBits) - 1; - const int dstExpBias = dstInfExp >> 1; - - const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits; - - // Break a into a sign and representation of the absolute value - const src_rep_t aRep = srcToRep(a); - const src_rep_t aAbs = aRep & srcAbsMask; - const src_rep_t sign = aRep & srcSignMask; - dst_rep_t absResult; - - if (aAbs - srcMinNormal < srcInfinity - srcMinNormal) { - // a is a normal number. - // Extend to the destination type by shifting the significand and - // exponent into the proper position and rebiasing the exponent. - absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits); - absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits; - } - - else if (aAbs >= srcInfinity) { - // a is NaN or infinity. - // Conjure the result by beginning with infinity, then setting the qNaN - // bit (if needed) and right-aligning the rest of the trailing NaN - // payload field. - absResult = (dst_rep_t)dstInfExp << dstSigBits; - absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits); - absResult |= aAbs & srcNaNCode; - } - - else if (aAbs) { - // a is denormal. - // renormalize the significand and clear the leading bit, then insert - // the correct adjusted exponent in the destination type. - const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal); - absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale); - absResult ^= dstMinNormal; - const int resultExponent = dstExpBias - srcExpBias - scale + 1; - absResult |= (dst_rep_t)resultExponent << dstSigBits; - } - - else { - // a is zero. - absResult = 0; - } - - // Apply the signbit to (dst_t)abs(a). - const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits); - return dstFromRep(result); +COMPILER_RT_ABI double __extendsfdf2(float a) { + return __extendXfYf2__(a); } Index: lib/builtins/extendsftf2.c =================================================================== --- /dev/null +++ lib/builtins/extendsftf2.c @@ -0,0 +1,23 @@ +//===-- lib/extendsftf2.c - single -> quad conversion -------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +#define SRC_SINGLE +#define DST_QUAD +#include "fp_extend_impl.inc" + +COMPILER_RT_ABI long double __extendsftf2(float a) { + return __extendXfYf2__(a); +} + +#endif Index: lib/builtins/fp_extend.h =================================================================== --- /dev/null +++ lib/builtins/fp_extend.h @@ -0,0 +1,76 @@ +//===-lib/fp_extend.h - low precision -> high precision conversion -*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Set source and destination setting +// +//===----------------------------------------------------------------------===// + +#ifndef FP_EXTEND_HEADER +#define FP_EXTEND_HEADER + +#include "int_lib.h" + +#if defined SRC_SINGLE +typedef float src_t; +typedef uint32_t src_rep_t; +#define SRC_REP_C UINT32_C +static const int srcSigBits = 23; +#define src_rep_t_clz __builtin_clz + +#elif defined SRC_DOUBLE +typedef double src_t; +typedef uint64_t src_rep_t; +#define SRC_REP_C UINT64_C +static const int srcSigBits = 52; +static inline int src_rep_t_clz(src_rep_t a) { +#if defined __LP64__ + return __builtin_clzl(a); +#else + if (a & REP_C(0xffffffff00000000)) + return __builtin_clz(a >> 32); + else + return 32 + __builtin_clz(a & REP_C(0xffffffff)); +#endif +} + +#else +#error Source should be single precision or double precision! +#endif //end source precision + +#if defined DST_DOUBLE +typedef double dst_t; +typedef uint64_t dst_rep_t; +#define DST_REP_C UINT64_C +static const int dstSigBits = 52; + +#elif defined DST_QUAD +typedef long double dst_t; +typedef __uint128_t dst_rep_t; +#define DST_REP_C (__uint128_t) +static const int dstSigBits = 112; + +#else +#error Destination should be double precision or quad precision! +#endif //end destination precision + +// End of specialization parameters. Two helper routines for conversion to and +// from the representation of floating-point data as integer values follow. + +static inline src_rep_t srcToRep(src_t x) { + const union { src_t f; src_rep_t i; } rep = {.f = x}; + return rep.i; +} + +static inline dst_t dstFromRep(dst_rep_t x) { + const union { dst_t f; dst_rep_t i; } rep = {.i = x}; + return rep.f; +} +// End helper routines. Conversion implementation follows. + +#endif //FP_EXTEND_HEADER Index: lib/builtins/fp_extend_impl.inc =================================================================== --- /dev/null +++ lib/builtins/fp_extend_impl.inc @@ -0,0 +1,108 @@ +//=-lib/fp_extend_impl.inc - low precision -> high precision conversion -*-- -// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a fairly generic conversion from a narrower to a wider +// IEEE-754 floating-point type. The constants and types defined following the +// includes below parameterize the conversion. +// +// This routine can be trivially adapted to support conversions from narrower +// precision or to wider precision. It does not support types that don't +// use the usual IEEE-754 interchange formats; specifically, some work would be +// needed to adapt it to (for example) the Intel 80-bit format or PowerPC +// double-double format. +// +// Note please, however, that this implementation is only intended to support +// *widening* operations; if you need to convert to a *narrower* floating-point +// type (e.g. double -> float), then this routine will not do what you want it +// to. +// +// It also requires that integer types at least as large as both formats +// are available on the target platform; this may pose a problem when trying +// to add support for quad on some 32-bit systems, for example. You also may +// run into trouble finding an appropriate CLZ function for wide source types; +// you will likely need to roll your own on some platforms. +// +// Finally, the following assumptions are made: +// +// 1. floating-point types and integer types have the same endianness on the +// target platform +// +// 2. quiet NaNs, if supported, are indicated by the leading bit of the +// significand field being set +// +//===----------------------------------------------------------------------===// + +#include "fp_extend.h" + +static inline dst_t __extendXfYf2__(src_t a) { + /* Various constants whose values follow from the type parameters.*/ + /* Any reasonable optimizer will fold and propagate all of these.*/ + const int srcBits = sizeof(src_t)*CHAR_BIT; + const int srcExpBits = srcBits - srcSigBits - 1; + const int srcInfExp = (1 << srcExpBits) - 1; + const int srcExpBias = srcInfExp >> 1; + + const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits; + const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits; + const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits); + const src_rep_t srcAbsMask = srcSignMask - 1; + const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1); + const src_rep_t srcNaNCode = srcQNaN - 1; + + const int dstBits = sizeof(dst_t)*CHAR_BIT; + const int dstExpBits = dstBits - dstSigBits - 1; + const int dstInfExp = (1 << dstExpBits) - 1; + const int dstExpBias = dstInfExp >> 1; + + const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits; + + /* Break a into a sign and representation of the absolute value*/ + const src_rep_t aRep = srcToRep(a); + const src_rep_t aAbs = aRep & srcAbsMask; + const src_rep_t sign = aRep & srcSignMask; + dst_rep_t absResult; + + if (aAbs - srcMinNormal < srcInfinity - srcMinNormal) { + /* a is a normal number. + Extend to the destination type by shifting the significand and + exponent into the proper position and rebiasing the exponent.*/ + absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits); + absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits; + } + + else if (aAbs >= srcInfinity) { + /* a is NaN or infinity. + Conjure the result by beginning with infinity, then setting the qNaN + bit (if needed) and right-aligning the rest of the trailing NaN + payload field. */ + absResult = (dst_rep_t)dstInfExp << dstSigBits; + absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits); + absResult |= (dst_rep_t)(aAbs & srcNaNCode) << (dstSigBits - srcSigBits); + } + + else if (aAbs) { + /* a is denormal. + renormalize the significand and clear the leading bit, then insert + the correct adjusted exponent in the destination type.*/ + const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal); + absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale); + absResult ^= dstMinNormal; + const int resultExponent = dstExpBias - srcExpBias - scale + 1; + absResult |= (dst_rep_t)resultExponent << dstSigBits; + } + + else { + /* a is zero.*/ + absResult = 0; + } + + /* Apply the signbit to (dst_t)abs(a).*/ + const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits); + return dstFromRep(result); +} Index: test/builtins/Unit/extenddftf2_test.c =================================================================== --- /dev/null +++ test/builtins/Unit/extenddftf2_test.c @@ -0,0 +1,75 @@ +//===--------------- extenddftf2_test.c - Test __extenddftf2 --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file tests __extenddftf2 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include + +#if __LP64__ && __LDBL_MANT_DIG__ == 113 + +#include "fp_test.h" + +long double __extenddftf2(double a); + +int test__extenddftf2(double a, uint64_t expectedHi, uint64_t expectedLo) +{ + long double x = __extenddftf2(a); + int ret = compareResultLD(x, expectedHi, expectedLo); + + if (ret){ + printf("error in test__extenddftf2(%f) = %.20Lf, " + "expected %.20Lf\n", a, x, fromRep128(expectedHi, expectedLo)); + } + return ret; +} + +char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0}; + +#endif + +int main() +{ +#if __LP64__ && __LDBL_MANT_DIG__ == 113 + // qNaN + if (test__extenddftf2(makeQNaN64(), + 0x7fff800000000000UL, 0x0UL)) + return 1; + // NaN + if (test__extenddftf2(makeNaN64(0x7100000000000UL), + 0x7fff710000000000UL, 0x0UL)) + return 1; + // inf + if (test__extenddftf2(makeInf64(), + 0x7fff000000000000UL, 0x0UL)) + return 1; + // zero + if (test__extenddftf2(0.0, 0x0UL, 0x0UL)) + return 1; + + if (test__extenddftf2(0x1.23456789abcdefp+5, + 0x400423456789abcdUL, 0xf000000000000000UL)) + return 1; + if (test__extenddftf2(0x1.edcba987654321fp-9, + 0x3ff6edcba9876543UL, 0x2000000000000000UL)) + return 1; + if (test__extenddftf2(0x1.23456789abcdefp+45, + 0x402c23456789abcdUL, 0xf000000000000000UL)) + return 1; + if (test__extenddftf2(0x1.edcba987654321fp-45, + 0x3fd2edcba9876543UL, 0x2000000000000000UL)) + return 1; + +#else + printf("skipped\n"); + +#endif + return 0; +} Index: test/builtins/Unit/extendsftf2_test.c =================================================================== --- /dev/null +++ test/builtins/Unit/extendsftf2_test.c @@ -0,0 +1,72 @@ +//===--------------- extendsftf2_test.c - Test __extendsftf2 --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file tests __extendsftf2 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include + +#if __LP64__ && __LDBL_MANT_DIG__ == 113 + +#include "fp_test.h" + +long double __extendsftf2(float a); + +int test__extendsftf2(float a, uint64_t expectedHi, uint64_t expectedLo) +{ + long double x = __extendsftf2(a); + int ret = compareResultLD(x, expectedHi, expectedLo); + + if (ret) + { + printf("error in test__extendsftf2(%f) = %.20Lf, " + "expected %.20Lf\n", a, x, fromRep128(expectedHi, expectedLo)); + } + return ret; +} + +char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0}; + +#endif + +int main() +{ +#if __LP64__ && __LDBL_MANT_DIG__ == 113 + // qNaN + if (test__extendsftf2(makeQNaN32(), + 0x7fff800000000000UL, 0x0UL)) + return 1; + // NaN + if (test__extendsftf2(makeNaN32(0x410000U), + 0x7fff820000000000UL, 0x0UL)) + return 1; + // inf + if (test__extendsftf2(makeInf32(), + 0x7fff000000000000UL, 0x0UL)) + return 1; + // zero + if (test__extendsftf2(0.0f, 0x0UL, 0x0UL)) + return 1; + + if (test__extendsftf2(0x1.23456p+5f, 0x4004234560000000UL, 0x0UL)) + return 1; + if (test__extendsftf2(0x1.edcbap-9f, 0x3ff6edcba0000000UL, 0x0UL)) + return 1; + if (test__extendsftf2(0x1.23456p+45f, 0x402c234560000000UL, 0x0UL)) + return 1; + if (test__extendsftf2(0x1.edcbap-45f, 0x3fd2edcba0000000UL, 0x0UL)) + return 1; + +#else + printf("skipped\n"); + +#endif + return 0; +}