Index: compiler-rt/lib/builtins/CMakeLists.txt =================================================================== --- compiler-rt/lib/builtins/CMakeLists.txt +++ compiler-rt/lib/builtins/CMakeLists.txt @@ -67,6 +67,7 @@ divtf3.c extendsfdf2.c extendhfsf2.c + extendhftf2.c ffsdi2.c ffssi2.c ffsti2.c @@ -170,7 +171,8 @@ floatuntitf.c multc3.c trunctfdf2.c - trunctfsf2.c) + trunctfsf2.c + trunctfhf2.c) option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN "Skip the atomic builtin (these should normally be provided by a shared library)" Index: compiler-rt/lib/builtins/extendhfsf2.c =================================================================== --- compiler-rt/lib/builtins/extendhfsf2.c +++ compiler-rt/lib/builtins/extendhfsf2.c @@ -14,20 +14,20 @@ // Use a forwarding definition and noinline to implement a poor man's alias, // as there isn't a good cross-platform way of defining one. -COMPILER_RT_ABI NOINLINE float __extendhfsf2(uint16_t a) { +COMPILER_RT_ABI NOINLINE float __extendhfsf2(src_t a) { return __extendXfYf2__(a); } -COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) { +COMPILER_RT_ABI float __gnu_h2f_ieee(src_t a) { return __extendhfsf2(a); } #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) -AEABI_RTABI float __aeabi_h2f(uint16_t a) { +AEABI_RTABI float __aeabi_h2f(src_t a) { return __extendhfsf2(a); } #else -AEABI_RTABI float __aeabi_h2f(uint16_t a) COMPILER_RT_ALIAS(__extendhfsf2); +AEABI_RTABI float __aeabi_h2f(src_t a) COMPILER_RT_ALIAS(__extendhfsf2); #endif #endif Index: compiler-rt/lib/builtins/extendhftf2.c =================================================================== --- /dev/null +++ compiler-rt/lib/builtins/extendhftf2.c @@ -0,0 +1,22 @@ +//===-- lib/extendhfsf2.c - half -> 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_HALF +#define DST_QUAD +#include "fp_extend_impl.inc" + +COMPILER_RT_ABI long double __extendhftf2(src_t a) { + return __extendXfYf2__(a); +} + +#endif Index: compiler-rt/lib/builtins/fp_extend.h =================================================================== --- compiler-rt/lib/builtins/fp_extend.h +++ compiler-rt/lib/builtins/fp_extend.h @@ -40,7 +40,12 @@ } #elif defined SRC_HALF +#if defined __aarch64__ && defined __ARM_FP16_ARGS +// Use __fp16 if available. +typedef __fp16 src_t; +#else typedef uint16_t src_t; +#endif typedef uint16_t src_rep_t; #define SRC_REP_C UINT16_C static const int srcSigBits = 10; Index: compiler-rt/lib/builtins/fp_trunc.h =================================================================== --- compiler-rt/lib/builtins/fp_trunc.h +++ compiler-rt/lib/builtins/fp_trunc.h @@ -51,7 +51,12 @@ static const int dstSigBits = 23; #elif defined DST_HALF +#if defined __aarch64__ && defined __ARM_FP16_ARGS +// Use __fp16 if available. +typedef __fp16 dst_t; +#else typedef uint16_t dst_t; +#endif typedef uint16_t dst_rep_t; #define DST_REP_C UINT16_C static const int dstSigBits = 10; Index: compiler-rt/lib/builtins/truncdfhf2.c =================================================================== --- compiler-rt/lib/builtins/truncdfhf2.c +++ compiler-rt/lib/builtins/truncdfhf2.c @@ -11,16 +11,16 @@ #define DST_HALF #include "fp_trunc_impl.inc" -COMPILER_RT_ABI uint16_t __truncdfhf2(double a) { +COMPILER_RT_ABI dst_t __truncdfhf2(double a) { return __truncXfYf2__(a); } #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) -AEABI_RTABI uint16_t __aeabi_d2h(double a) { +AEABI_RTABI dst_t __aeabi_d2h(double a) { return __truncdfhf2(a); } #else -AEABI_RTABI uint16_t __aeabi_d2h(double a) COMPILER_RT_ALIAS(__truncdfhf2); +AEABI_RTABI dst_t __aeabi_d2h(double a) COMPILER_RT_ALIAS(__truncdfhf2); #endif #endif Index: compiler-rt/lib/builtins/truncsfhf2.c =================================================================== --- compiler-rt/lib/builtins/truncsfhf2.c +++ compiler-rt/lib/builtins/truncsfhf2.c @@ -13,20 +13,20 @@ // Use a forwarding definition and noinline to implement a poor man's alias, // as there isn't a good cross-platform way of defining one. -COMPILER_RT_ABI NOINLINE uint16_t __truncsfhf2(float a) { +COMPILER_RT_ABI NOINLINE dst_t __truncsfhf2(float a) { return __truncXfYf2__(a); } -COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) { +COMPILER_RT_ABI dst_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); } #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) -AEABI_RTABI uint16_t __aeabi_f2h(float a) { +AEABI_RTABI dst_t __aeabi_f2h(float a) { return __truncsfhf2(a); } #else -AEABI_RTABI uint16_t __aeabi_f2h(float a) COMPILER_RT_ALIAS(__truncsfhf2); +AEABI_RTABI dst_t __aeabi_f2h(float a) COMPILER_RT_ALIAS(__truncsfhf2); #endif #endif Index: compiler-rt/lib/builtins/trunctfhf2.c =================================================================== --- /dev/null +++ compiler-rt/lib/builtins/trunctfhf2.c @@ -0,0 +1,22 @@ +//===-- lib/trunctfhf2.c - quad -> half 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_QUAD +#define DST_HALF +#include "fp_trunc_impl.inc" + +COMPILER_RT_ABI dst_t __trunctfhf2(long double a) { + return __truncXfYf2__(a); +} + +#endif Index: compiler-rt/test/builtins/Unit/extenddftf2_test.c =================================================================== --- compiler-rt/test/builtins/Unit/extenddftf2_test.c +++ compiler-rt/test/builtins/Unit/extenddftf2_test.c @@ -55,8 +55,17 @@ UINT64_C(0x7fff000000000000), UINT64_C(0x0))) return 1; + if (test__extenddftf2(-makeInf64(), + UINT64_C(0xffff000000000000), + UINT64_C(0x0))) + return 1; // zero - if (test__extenddftf2(0.0, UINT64_C(0x0), UINT64_C(0x0))) + if (test__extenddftf2(0.0, + UINT64_C(0x0), UINT64_C(0x0))) + return 1; + if (test__extenddftf2(-0.0, + UINT64_C(0x8000000000000000), + UINT64_C(0x0))) return 1; if (test__extenddftf2(0x1.23456789abcdefp+5, Index: compiler-rt/test/builtins/Unit/extendhfsf2_test.c =================================================================== --- compiler-rt/test/builtins/Unit/extendhfsf2_test.c +++ compiler-rt/test/builtins/Unit/extendhfsf2_test.c @@ -16,12 +16,13 @@ #include "fp_test.h" -float __extendhfsf2(uint16_t a); +float __extendhfsf2(TYPE_FP16 a); int test__extendhfsf2(uint16_t a, float expected) { - float x = __extendhfsf2(a); - int ret = compareResultH(x, expected); + TYPE_FP16 a2 = fromRep16(a); + float x = __extendhfsf2(a2); + int ret = compareResultF(x, toRep32(expected)); if (ret){ printf("error in test__extendhfsf2(%#.4x) = %f, " @@ -39,8 +40,8 @@ makeQNaN32())) return 1; // NaN - if (test__extendhfsf2(UINT16_C(0x7e00), - makeNaN32(UINT32_C(0x8000)))) + if (test__extendhfsf2(UINT16_C(0x7d00), + makeQNaN32())) return 1; // inf if (test__extendhfsf2(UINT16_C(0x7c00), @@ -56,16 +57,7 @@ if (test__extendhfsf2(UINT16_C(0x8000), -0.0f)) return 1; - - if (test__extendhfsf2(UINT16_C(0x4248), - 3.1415926535f)) - return 1; - if (test__extendhfsf2(UINT16_C(0xc248), - -3.1415926535f)) - return 1; - if (test__extendhfsf2(UINT16_C(0x7c00), - 0x1.987124876876324p+100f)) - return 1; + // miscellaneous if (test__extendhfsf2(UINT16_C(0x6e62), 0x1.988p+12f)) return 1; @@ -85,30 +77,9 @@ if (test__extendhfsf2(UINT16_C(0x8001), -0x1.0p-24f)) return 1; - if (test__extendhfsf2(UINT16_C(0x0001), - 0x1.5p-25f)) - return 1; - // and back to zero - if (test__extendhfsf2(UINT16_C(0x0000), - 0x1.0p-25f)) - return 1; - if (test__extendhfsf2(UINT16_C(0x8000), - -0x1.0p-25f)) - return 1; - // max (precise) + // max if (test__extendhfsf2(UINT16_C(0x7bff), 65504.0f)) return 1; - // max (rounded) - if (test__extendhfsf2(UINT16_C(0x7bff), - 65504.0f)) - return 1; - // max (to +inf) - if (test__extendhfsf2(UINT16_C(0x7c00), - makeInf32())) - return 1; - if (test__extendhfsf2(UINT16_C(0xfc00), - -makeInf32())) - return 1; return 0; } Index: compiler-rt/test/builtins/Unit/extendhftf2_test.c =================================================================== --- /dev/null +++ compiler-rt/test/builtins/Unit/extendhftf2_test.c @@ -0,0 +1,107 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +//===--------------- extendhftf2_test.c - Test __extendhftf2 --------------===// +// +// 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 __extendhftf2 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" +#include + +#if __LDBL_MANT_DIG__ == 113 + +#include "fp_test.h" + +COMPILER_RT_ABI long double __extendhftf2(TYPE_FP16 a); + +int test__extendhftf2(TYPE_FP16 a, uint64_t expectedHi, uint64_t expectedLo) +{ + long double x = __extendhftf2(a); + int ret = compareResultLD(x, expectedHi, expectedLo); + + if (ret) + { + printf("error in test__extendhftf2(" FMTSTR_FP16 ") = %.20Lf, " + "expected %.20Lf\n", a, x, fromRep128(expectedHi, expectedLo)); + } + return ret; +} + +char assumption_1[sizeof(__fp16) * CHAR_BIT == 16] = {0}; + +#endif + +int main() +{ +#if __LDBL_MANT_DIG__ == 113 + // qNaN + if (test__extendhftf2(makeQNaN16(), + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + // NaN + if (test__extendhftf2(makeNaN16(UINT16_C(0x0100)), + UINT64_C(0x7fff400000000000), + UINT64_C(0x0))) + return 1; + // inf + if (test__extendhftf2(makeInf16(), + UINT64_C(0x7fff000000000000), + UINT64_C(0x0))) + return 1; + if (test__extendhftf2(-makeInf16(), + UINT64_C(0xffff000000000000), + UINT64_C(0x0))) + return 1; + // zero + if (test__extendhftf2(fromRep16(0x0U), + UINT64_C(0x0), UINT64_C(0x0))) + return 1; + if (test__extendhftf2(fromRep16(0x8000U), + UINT64_C(0x8000000000000000), + UINT64_C(0x0))) + return 1; + // denormal + if (test__extendhftf2(fromRep16(0x0010U), + UINT64_C(0x3feb000000000000), + UINT64_C(0x0000000000000000))) + return 1; + if (test__extendhftf2(fromRep16(0x0001U), + UINT64_C(0x3fe7000000000000), + UINT64_C(0x0000000000000000))) + return 1; + if (test__extendhftf2(fromRep16(0x8001U), + UINT64_C(0xbfe7000000000000), + UINT64_C(0x0000000000000000))) + return 1; + + // pi + if (test__extendhftf2(fromRep16(0x4248U), + UINT64_C(0x4000920000000000), + UINT64_C(0x0000000000000000))) + return 1; + if (test__extendhftf2(fromRep16(0xc248U), + UINT64_C(0xc000920000000000), + UINT64_C(0x0000000000000000))) + return 1; + + if (test__extendhftf2(fromRep16(0x508cU), + UINT64_C(0x4004230000000000), + UINT64_C(0x0))) + return 1; + if (test__extendhftf2(fromRep16(0x1bb7U), + UINT64_C(0x3ff6edc000000000), + UINT64_C(0x0))) + return 1; +#else + printf("skipped\n"); +#endif + return 0; +} Index: compiler-rt/test/builtins/Unit/fp_test.h =================================================================== --- compiler-rt/test/builtins/Unit/fp_test.h +++ compiler-rt/test/builtins/Unit/fp_test.h @@ -16,13 +16,24 @@ #include #include +// Use __fp16 if available. +#if defined __aarch64__ && defined __ARM_FP16_ARGS +#define TYPE_FP16 __fp16 +#define FMTSTR_FP16 "%f" +#else +#define TYPE_FP16 uint16_t +#define FMTSTR_FP16 "%#.4x" +#endif + enum EXPECTED_RESULT { LESS_0, LESS_EQUAL_0, EQUAL_0, GREATER_0, GREATER_EQUAL_0, NEQUAL_0 }; -static inline uint16_t fromRep16(uint16_t x) +static inline TYPE_FP16 fromRep16(uint16_t x) { - return x; + TYPE_FP16 ret; + memcpy(&ret, &x, 2); + return ret; } static inline float fromRep32(uint32_t x) @@ -49,9 +60,11 @@ } #endif -static inline uint16_t toRep16(uint16_t x) +static inline uint16_t toRep16(TYPE_FP16 x) { - return x; + uint16_t ret; + memcpy(&ret, &x, 2); + return ret; } static inline uint32_t toRep32(float x) @@ -77,7 +90,7 @@ } #endif -static inline int compareResultH(uint16_t result, +static inline int compareResultH(TYPE_FP16 result, uint16_t expected) { uint16_t rep = toRep16(result); @@ -212,7 +225,7 @@ return ""; } -static inline uint16_t makeQNaN16() +static inline TYPE_FP16 makeQNaN16() { return fromRep16(0x7e00U); } @@ -234,7 +247,7 @@ } #endif -static inline uint16_t makeNaN16(uint16_t rand) +static inline TYPE_FP16 makeNaN16(uint16_t rand) { return fromRep16(0x7c00U | (rand & 0x7fffU)); } @@ -256,7 +269,7 @@ } #endif -static inline uint16_t makeInf16() +static inline TYPE_FP16 makeInf16() { return fromRep16(0x7c00U); } Index: compiler-rt/test/builtins/Unit/truncdfhf2_test.c =================================================================== --- compiler-rt/test/builtins/Unit/truncdfhf2_test.c +++ compiler-rt/test/builtins/Unit/truncdfhf2_test.c @@ -17,16 +17,16 @@ #include "fp_test.h" -uint16_t __truncdfhf2(double a); +TYPE_FP16 __truncdfhf2(double a); int test__truncdfhf2(double a, uint16_t expected) { - uint16_t x = __truncdfhf2(a); + TYPE_FP16 x = __truncdfhf2(a); int ret = compareResultH(x, expected); if (ret){ - printf("error in test__truncdfhf2(%f) = %#.4x, " - "expected %#.4x\n", a, x, fromRep16(expected)); + printf("error in test__truncdfhf2(%f) = " FMTSTR_FP16 ", " + "expected %#.4x\n", a, x, expected); } return ret; } Index: compiler-rt/test/builtins/Unit/truncsfhf2_test.c =================================================================== --- compiler-rt/test/builtins/Unit/truncsfhf2_test.c +++ compiler-rt/test/builtins/Unit/truncsfhf2_test.c @@ -17,16 +17,16 @@ #include "fp_test.h" -uint16_t __truncsfhf2(float a); +TYPE_FP16 __truncsfhf2(float a); int test__truncsfhf2(float a, uint16_t expected) { - uint16_t x = __truncsfhf2(a); + TYPE_FP16 x = __truncsfhf2(a); int ret = compareResultH(x, expected); if (ret){ - printf("error in test__truncsfhf2(%f) = %#.4x, " - "expected %#.4x\n", a, x, fromRep16(expected)); + printf("error in test__truncsfhf2(%f) = " FMTSTR_FP16 ", " + "expected %#.4x\n", a, x, expected); } return ret; } @@ -40,8 +40,8 @@ UINT16_C(0x7e00))) return 1; // NaN - if (test__truncsfhf2(makeNaN32(UINT32_C(0x8000)), - UINT16_C(0x7e00))) + if (test__truncsfhf2(makeNaN32(UINT32_C(0x00200000)), + UINT16_C(0x7f00))) return 1; // inf if (test__truncsfhf2(makeInf32(), Index: compiler-rt/test/builtins/Unit/trunctfhf2_test.c =================================================================== --- compiler-rt/test/builtins/Unit/trunctfhf2_test.c +++ compiler-rt/test/builtins/Unit/trunctfhf2_test.c @@ -1,6 +1,5 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t - -//===--------------- truncsfhf2_test.c - Test __truncsfhf2 ----------------===// +//===--------------- trunctfhf2_test.c - Test __trunctfhf2 ----------------===// // // The LLVM Compiler Infrastructure // @@ -9,108 +8,131 @@ // //===----------------------------------------------------------------------===// // -// This file tests __truncsfhf2 for the compiler_rt library. +// This file tests __trunctfhf2 for the compiler_rt library. // //===----------------------------------------------------------------------===// +#include "int_lib.h" #include +#if __LDBL_MANT_DIG__ == 113 + #include "fp_test.h" -uint16_t __truncsfhf2(float a); +TYPE_FP16 __trunctfhf2(long double a); -int test__truncsfhf2(float a, uint16_t expected) +int test__trunctfhf2(long double a, uint16_t expected) { - uint16_t x = __truncsfhf2(a); + TYPE_FP16 x = __trunctfhf2(a); int ret = compareResultH(x, expected); - if (ret){ - printf("error in test__truncsfhf2(%f) = %#.4x, " - "expected %#.4x\n", a, x, fromRep16(expected)); + if (ret) + { + printf("error in test__trunctfhf2(%.20Lf) = " FMTSTR_FP16 ", " + "expected %#.4x\n", a, x, expected); } return ret; } char assumption_1[sizeof(__fp16) * CHAR_BIT == 16] = {0}; +#endif + int main() { +#if __LDBL_MANT_DIG__ == 113 // qNaN - if (test__truncsfhf2(makeQNaN32(), + if (test__trunctfhf2(makeQNaN128(), UINT16_C(0x7e00))) return 1; // NaN - if (test__truncsfhf2(makeNaN32(UINT32_C(0x8000)), + if (test__trunctfhf2(makeNaN128(UINT64_C(0x810000000000)), UINT16_C(0x7e00))) return 1; // inf - if (test__truncsfhf2(makeInf32(), + if (test__trunctfhf2(makeInf128(), UINT16_C(0x7c00))) return 1; - if (test__truncsfhf2(-makeInf32(), + if (test__trunctfhf2(-makeInf128(), UINT16_C(0xfc00))) return 1; // zero - if (test__truncsfhf2(0.0f, UINT16_C(0x0))) + if (test__trunctfhf2(0.0L, UINT16_C(0x0))) return 1; - if (test__truncsfhf2(-0.0f, UINT16_C(0x8000))) + if (test__trunctfhf2(-0.0L, UINT16_C(0x8000))) return 1; - if (test__truncsfhf2(3.1415926535f, + if (test__trunctfhf2(3.1415926535L, UINT16_C(0x4248))) return 1; - if (test__truncsfhf2(-3.1415926535f, + if (test__trunctfhf2(-3.1415926535L, UINT16_C(0xc248))) return 1; - if (test__truncsfhf2(0x1.987124876876324p+100f, + if (test__trunctfhf2(0x1.987124876876324p+100L, UINT16_C(0x7c00))) return 1; - if (test__truncsfhf2(0x1.987124876876324p+12f, + if (test__trunctfhf2(0x1.987124876876324p+12L, UINT16_C(0x6e62))) return 1; - if (test__truncsfhf2(0x1.0p+0f, + if (test__trunctfhf2(0x1.0p+0L, UINT16_C(0x3c00))) return 1; - if (test__truncsfhf2(0x1.0p-14f, + if (test__trunctfhf2(0x1.0p-14L, UINT16_C(0x0400))) return 1; // denormal - if (test__truncsfhf2(0x1.0p-20f, + if (test__trunctfhf2(0x1.0p-20L, UINT16_C(0x0010))) return 1; - if (test__truncsfhf2(0x1.0p-24f, + if (test__trunctfhf2(0x1.0p-24L, UINT16_C(0x0001))) return 1; - if (test__truncsfhf2(-0x1.0p-24f, + if (test__trunctfhf2(-0x1.0p-24L, UINT16_C(0x8001))) return 1; - if (test__truncsfhf2(0x1.5p-25f, + if (test__trunctfhf2(0x1.5p-25L, UINT16_C(0x0001))) return 1; // and back to zero - if (test__truncsfhf2(0x1.0p-25f, + if (test__trunctfhf2(0x1.0p-25L, UINT16_C(0x0000))) return 1; - if (test__truncsfhf2(-0x1.0p-25f, + if (test__trunctfhf2(-0x1.0p-25L, UINT16_C(0x8000))) return 1; // max (precise) - if (test__truncsfhf2(65504.0f, + if (test__trunctfhf2(65504.0L, UINT16_C(0x7bff))) return 1; // max (rounded) - if (test__truncsfhf2(65519.0f, + if (test__trunctfhf2(65519.0L, UINT16_C(0x7bff))) return 1; // max (to +inf) - if (test__truncsfhf2(65520.0f, + if (test__trunctfhf2(65520.0L, UINT16_C(0x7c00))) return 1; - if (test__truncsfhf2(65536.0f, + if (test__trunctfhf2(65536.0L, UINT16_C(0x7c00))) return 1; - if (test__truncsfhf2(-65520.0f, + if (test__trunctfhf2(-65520.0L, UINT16_C(0xfc00))) return 1; + + if (test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5L, + UINT16_C(0x508f))) + return 1; + if (test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9L, + UINT16_C(0x1b8f))) + return 1; + if (test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453L, + UINT16_C(0x7c00))) + return 1; + if (test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43L, + UINT16_C(0x0))) + return 1; +#else + printf("skipped\n"); +#endif return 0; } Index: llvm/include/llvm/IR/RuntimeLibcalls.def =================================================================== --- llvm/include/llvm/IR/RuntimeLibcalls.def +++ llvm/include/llvm/IR/RuntimeLibcalls.def @@ -254,6 +254,7 @@ HANDLE_LIBCALL(FPEXT_F80_F128, "__extendxftf2") HANDLE_LIBCALL(FPEXT_F64_F128, "__extenddftf2") HANDLE_LIBCALL(FPEXT_F32_F128, "__extendsftf2") +HANDLE_LIBCALL(FPEXT_F16_F128, "__extendhftf2") HANDLE_LIBCALL(FPEXT_F32_F64, "__extendsfdf2") HANDLE_LIBCALL(FPEXT_F16_F32, "__gnu_h2f_ieee") HANDLE_LIBCALL(FPROUND_F32_F16, "__gnu_f2h_ieee") Index: llvm/lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringBase.cpp +++ llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -180,6 +180,8 @@ if (OpVT == MVT::f16) { if (RetVT == MVT::f32) return FPEXT_F16_F32; + if (RetVT == MVT::f128) + return FPEXT_F16_F128; } else if (OpVT == MVT::f32) { if (RetVT == MVT::f64) return FPEXT_F32_F64; Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -243,6 +243,7 @@ setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom); setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom); setOperationAction(ISD::UINT_TO_FP, MVT::i128, Custom); + setOperationAction(ISD::FP_ROUND, MVT::f16, Custom); setOperationAction(ISD::FP_ROUND, MVT::f32, Custom); setOperationAction(ISD::FP_ROUND, MVT::f64, Custom); Index: llvm/test/CodeGen/AArch64/arm64-fp128.ll =================================================================== --- llvm/test/CodeGen/AArch64/arm64-fp128.ll +++ llvm/test/CodeGen/AArch64/arm64-fp128.ll @@ -219,6 +219,7 @@ ; CHECK: ret } +@varhalf = global half 0.0, align 2 @varfloat = global float 0.0, align 4 @vardouble = global double 0.0, align 8 @@ -227,6 +228,12 @@ %val = load fp128, fp128* @lhs, align 16 + %half = fptrunc fp128 %val to half + store half %half, half* @varhalf, align 2 +; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs] +; CHECK: bl __trunctfhf2 +; CHECK: str h0, [{{x[0-9]+}}, :lo12:varhalf] + %float = fptrunc fp128 %val to float store float %float, float* @varfloat, align 4 ; CHECK: bl __trunctfsf2 @@ -245,6 +252,13 @@ %val = load fp128, fp128* @lhs, align 16 + %half = load half, half* @varhalf + %fromhalf = fpext half %half to fp128 + store volatile fp128 %fromhalf, fp128* @lhs, align 16 +; CHECK: ldr h0, [{{x[0-9]+}}, :lo12:varhalf] +; CHECK: bl __extendhftf2 +; CHECK: str q0, [{{x[0-9]+}}, :lo12:lhs] + %float = load float, float* @varfloat %fromfloat = fpext float %float to fp128 store volatile fp128 %fromfloat, fp128* @lhs, align 16