Index: compiler-rt/cmake/builtin-config-ix.cmake =================================================================== --- compiler-rt/cmake/builtin-config-ix.cmake +++ compiler-rt/cmake/builtin-config-ix.cmake @@ -22,6 +22,13 @@ } ") +builtin_check_c_compiler_source(COMPILER_RT_HAS_FLOAT16 +" +_Float16 foo(_Float16 x) { + return x; +} +" +) set(ARM64 aarch64) set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k) Index: compiler-rt/lib/builtins/CMakeLists.txt =================================================================== --- compiler-rt/lib/builtins/CMakeLists.txt +++ compiler-rt/lib/builtins/CMakeLists.txt @@ -169,6 +169,7 @@ divtc3.c divtf3.c extenddftf2.c + extendhftf2.c extendsftf2.c fixtfdi.c fixtfsi.c @@ -187,6 +188,7 @@ powitf2.c subtf3.c trunctfdf2.c + trunctfhf2.c trunctfsf2.c ) @@ -613,6 +615,8 @@ else () set(BUILTIN_CFLAGS "") + append_list_if(COMPILER_RT_HAS_FLOAT16 -DCOMPILER_RT_HAS_FLOAT16 BUILTIN_CFLAGS) + append_list_if(COMPILER_RT_HAS_STD_C11_FLAG -std=c11 BUILTIN_CFLAGS) # These flags would normally be added to CMAKE_C_FLAGS by the llvm Index: compiler-rt/lib/builtins/extendhfsf2.c =================================================================== --- compiler-rt/lib/builtins/extendhfsf2.c +++ compiler-rt/lib/builtins/extendhfsf2.c @@ -12,15 +12,15 @@ // 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) { return __extendhfsf2(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) { return __extendhfsf2(a); } +AEABI_RTABI float __aeabi_h2f(src_t a) { return __extendhfsf2(a); } #else COMPILER_RT_ALIAS(__extendhfsf2, __aeabi_h2f) #endif Index: compiler-rt/lib/builtins/extendhftf2.c =================================================================== --- /dev/null +++ compiler-rt/lib/builtins/extendhftf2.c @@ -0,0 +1,23 @@ +//===-- lib/extendhftf2.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) && \ + defined(COMPILER_RT_HAS_FLOAT16) +#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,11 @@ } #elif defined SRC_HALF +#ifdef COMPILER_RT_HAS_FLOAT16 +typedef _Float16 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 @@ -50,7 +50,11 @@ static const int dstSigBits = 23; #elif defined DST_HALF +#ifdef COMPILER_RT_HAS_FLOAT16 +typedef _Float16 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 @@ -10,11 +10,11 @@ #define DST_HALF #include "fp_trunc_impl.inc" -COMPILER_RT_ABI uint16_t __truncdfhf2(double a) { return __truncXfYf2__(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) { return __truncdfhf2(a); } +AEABI_RTABI dst_t __aeabi_d2h(double a) { return __truncdfhf2(a); } #else COMPILER_RT_ALIAS(__truncdfhf2, __aeabi_d2h) #endif Index: compiler-rt/lib/builtins/truncsfhf2.c =================================================================== --- compiler-rt/lib/builtins/truncsfhf2.c +++ compiler-rt/lib/builtins/truncsfhf2.c @@ -12,15 +12,15 @@ // 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) { return __truncsfhf2(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) { return __truncsfhf2(a); } +AEABI_RTABI dst_t __aeabi_f2h(float a) { return __truncsfhf2(a); } #else COMPILER_RT_ALIAS(__truncsfhf2, __aeabi_f2h) #endif Index: compiler-rt/lib/builtins/trunctfhf2.c =================================================================== --- /dev/null +++ compiler-rt/lib/builtins/trunctfhf2.c @@ -0,0 +1,21 @@ +//===-- 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) && \ + defined(COMPILER_RT_HAS_FLOAT16) +#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/CMakeLists.txt =================================================================== --- compiler-rt/test/builtins/CMakeLists.txt +++ compiler-rt/test/builtins/CMakeLists.txt @@ -44,6 +44,8 @@ string(REPLACE ";" " " BUILTINS_TEST_TARGET_CFLAGS "${BUILTINS_TEST_TARGET_CFLAGS}") endif() + append_list_if(COMPILER_RT_HAS_FLOAT16 -DCOMPILER_RT_HAS_FLOAT16 BUILTINS_TEST_TARGET_CFLAGS) + # Compute builtins available in library and add them as lit features. if(APPLE) # TODO: Support other Apple platforms. 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 @@ -5,99 +5,83 @@ #include "fp_test.h" -float __extendhfsf2(uint16_t a); +float __extendhfsf2(TYPE_FP16 a); -int test__extendhfsf2(uint16_t a, float expected) +int test__extendhfsf2(TYPE_FP16 a, uint32_t expected) { float x = __extendhfsf2(a); - int ret = compareResultH(x, expected); + int ret = compareResultF(x, expected); if (ret){ printf("error in test__extendhfsf2(%#.4x) = %f, " - "expected %f\n", a, x, expected); + "expected %f\n", toRep16(a), x, fromRep32(expected)); } return ret; } -char assumption_1[sizeof(__fp16) * CHAR_BIT == 16] = {0}; +char assumption_1[sizeof(TYPE_FP16) * CHAR_BIT == 16] = {0}; int main() { // qNaN - if (test__extendhfsf2(UINT16_C(0x7e00), - makeQNaN32())) + if (test__extendhfsf2(fromRep16(0x7e00), + UINT32_C(0x7fc00000))) return 1; // NaN - if (test__extendhfsf2(UINT16_C(0x7e00), - makeNaN32(UINT32_C(0x8000)))) + if (test__extendhfsf2(fromRep16(0x7f80), + UINT32_C(0x7ff00000))) return 1; // inf - if (test__extendhfsf2(UINT16_C(0x7c00), - makeInf32())) + if (test__extendhfsf2(fromRep16(0x7c00), + UINT32_C(0x7f800000))) return 1; - if (test__extendhfsf2(UINT16_C(0xfc00), - -makeInf32())) + // -inf + if (test__extendhfsf2(fromRep16(0xfc00), + UINT32_C(0xff800000))) return 1; // zero - if (test__extendhfsf2(UINT16_C(0x0), - 0.0f)) + if (test__extendhfsf2(fromRep16(0x0), + UINT32_C(0x00000000))) return 1; - if (test__extendhfsf2(UINT16_C(0x8000), - -0.0f)) + // -zero + if (test__extendhfsf2(fromRep16(0x8000), + UINT32_C(0x80000000))) return 1; - - if (test__extendhfsf2(UINT16_C(0x4248), - 3.1415926535f)) - return 1; - if (test__extendhfsf2(UINT16_C(0xc248), - -3.1415926535f)) + if (test__extendhfsf2(fromRep16(0x4248), + UINT32_C(0x40490000))) return 1; - if (test__extendhfsf2(UINT16_C(0x7c00), - 0x1.987124876876324p+100f)) + if (test__extendhfsf2(fromRep16(0xc248), + UINT32_C(0xc0490000))) return 1; - if (test__extendhfsf2(UINT16_C(0x6e62), - 0x1.988p+12f)) + if (test__extendhfsf2(fromRep16(0x6e62), + UINT32_C(0x45cc4000))) return 1; - if (test__extendhfsf2(UINT16_C(0x3c00), - 0x1.0p+0f)) + if (test__extendhfsf2(fromRep16(0x3c00), + UINT32_C(0x3f800000))) return 1; - if (test__extendhfsf2(UINT16_C(0x0400), - 0x1.0p-14f)) + if (test__extendhfsf2(fromRep16(0x0400), + UINT32_C(0x38800000))) return 1; // denormal - if (test__extendhfsf2(UINT16_C(0x0010), - 0x1.0p-20f)) - return 1; - if (test__extendhfsf2(UINT16_C(0x0001), - 0x1.0p-24f)) + if (test__extendhfsf2(fromRep16(0x0010), + UINT32_C(0x35800000))) return 1; - if (test__extendhfsf2(UINT16_C(0x8001), - -0x1.0p-24f)) + if (test__extendhfsf2(fromRep16(0x0001), + UINT32_C(0x33800000))) return 1; - if (test__extendhfsf2(UINT16_C(0x0001), - 0x1.5p-25f)) + if (test__extendhfsf2(fromRep16(0x8001), + UINT32_C(0xb3800000))) 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)) + if (test__extendhfsf2(fromRep16(0x0001), + UINT32_C(0x33800000))) return 1; // max (precise) - if (test__extendhfsf2(UINT16_C(0x7bff), - 65504.0f)) + if (test__extendhfsf2(fromRep16(0x7bff), + UINT32_C(0x477fe000))) 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())) + if (test__extendhfsf2(fromRep16(0x7bff), + UINT32_C(0x477fe000))) 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,95 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_extendhftf2 + +#include "int_lib.h" +#include + +#if __LDBL_MANT_DIG__ == 113 && defined(COMPILER_RT_HAS_FLOAT16) + +#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(%#.4x) = %.20Lf, " + "expected %.20Lf\n", + toRep16(a), x, + fromRep128(expectedHi, expectedLo)); + } + return ret; +} + +char assumption_1[sizeof(TYPE_FP16) * CHAR_BIT == 16] = {0}; + +#endif + +int main() { +#if __LDBL_MANT_DIG__ == 113 && defined(COMPILER_RT_HAS_FLOAT16) + // 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 @@ -3,13 +3,25 @@ #include #include +#ifdef COMPILER_RT_HAS_FLOAT16 +#define TYPE_FP16 _Float16 +#else +#define TYPE_FP16 uint16_t +#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) { +#ifdef COMPILER_RT_HAS_FLOAT16 + TYPE_FP16 ret; + memcpy(&ret, &x, sizeof(ret)); + return ret; +#else return x; +#endif } static inline float fromRep32(uint32_t x) @@ -36,9 +48,15 @@ } #endif -static inline uint16_t toRep16(uint16_t x) +static inline uint16_t toRep16(TYPE_FP16 x) { +#ifdef COMPILER_RT_HAS_FLOAT16 + uint16_t ret; + memcpy(&ret, &x, sizeof(ret)); + return ret; +#else return x; +#endif } static inline uint32_t toRep32(float x) @@ -64,7 +82,7 @@ } #endif -static inline int compareResultH(uint16_t result, +static inline int compareResultH(TYPE_FP16 result, uint16_t expected) { uint16_t rep = toRep16(result); @@ -199,7 +217,7 @@ return ""; } -static inline uint16_t makeQNaN16(void) +static inline TYPE_FP16 makeQNaN16(void) { return fromRep16(0x7e00U); } @@ -221,7 +239,7 @@ } #endif -static inline uint16_t makeNaN16(uint16_t rand) +static inline TYPE_FP16 makeNaN16(uint16_t rand) { return fromRep16(0x7c00U | (rand & 0x7fffU)); } @@ -243,7 +261,7 @@ } #endif -static inline uint16_t makeInf16(void) +static inline TYPE_FP16 makeInf16(void) { 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 @@ -5,16 +5,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(%lf) = %#.4x, " + "expected %#.4x\n", a, toRep16(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 @@ -5,16 +5,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)); + "expected %#.4x\n", a, toRep16(x), expected); } return ret; } Index: compiler-rt/test/builtins/Unit/trunctfhf2_test.c =================================================================== --- /dev/null +++ compiler-rt/test/builtins/Unit/trunctfhf2_test.c @@ -0,0 +1,125 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_trunctfhf2 + +#include "int_lib.h" +#include + +#if __LDBL_MANT_DIG__ == 113 && defined(COMPILER_RT_HAS_FLOAT16) + +#include "fp_test.h" + +TYPE_FP16 __trunctfhf2(long double a); + +int test__trunctfhf2(long double a, uint16_t expected) { + TYPE_FP16 x = __trunctfhf2(a); + int ret = compareResultH(x, expected); + + if (ret) { + printf("error in test__trunctfhf2(%.20Lf) = %#.4x, " + "expected %#.4x\n", + a, toRep16(x), expected); + } + return ret; +} + +char assumption_1[sizeof(TYPE_FP16) * CHAR_BIT == 16] = {0}; + +#endif + +int main() { +#if __LDBL_MANT_DIG__ == 113 && defined(COMPILER_RT_HAS_FLOAT16) + // qNaN + if (test__trunctfhf2(makeQNaN128(), + UINT16_C(0x7e00))) + return 1; + // NaN + if (test__trunctfhf2(makeNaN128(UINT64_C(0x810000000000)), + UINT16_C(0x7e00))) + return 1; + // inf + if (test__trunctfhf2(makeInf128(), + UINT16_C(0x7c00))) + return 1; + if (test__trunctfhf2(-makeInf128(), + UINT16_C(0xfc00))) + return 1; + // zero + if (test__trunctfhf2(0.0L, UINT16_C(0x0))) + return 1; + if (test__trunctfhf2(-0.0L, UINT16_C(0x8000))) + return 1; + + if (test__trunctfhf2(3.1415926535L, + UINT16_C(0x4248))) + return 1; + if (test__trunctfhf2(-3.1415926535L, + UINT16_C(0xc248))) + return 1; + if (test__trunctfhf2(0x1.987124876876324p+100L, + UINT16_C(0x7c00))) + return 1; + if (test__trunctfhf2(0x1.987124876876324p+12L, + UINT16_C(0x6e62))) + return 1; + if (test__trunctfhf2(0x1.0p+0L, + UINT16_C(0x3c00))) + return 1; + if (test__trunctfhf2(0x1.0p-14L, + UINT16_C(0x0400))) + return 1; + // denormal + if (test__trunctfhf2(0x1.0p-20L, + UINT16_C(0x0010))) + return 1; + if (test__trunctfhf2(0x1.0p-24L, + UINT16_C(0x0001))) + return 1; + if (test__trunctfhf2(-0x1.0p-24L, + UINT16_C(0x8001))) + return 1; + if (test__trunctfhf2(0x1.5p-25L, + UINT16_C(0x0001))) + return 1; + // and back to zero + if (test__trunctfhf2(0x1.0p-25L, + UINT16_C(0x0000))) + return 1; + if (test__trunctfhf2(-0x1.0p-25L, + UINT16_C(0x8000))) + return 1; + // max (precise) + if (test__trunctfhf2(65504.0L, + UINT16_C(0x7bff))) + return 1; + // max (rounded) + if (test__trunctfhf2(65519.0L, + UINT16_C(0x7bff))) + return 1; + // max (to +inf) + if (test__trunctfhf2(65520.0L, + UINT16_C(0x7c00))) + return 1; + if (test__trunctfhf2(65536.0L, + UINT16_C(0x7c00))) + return 1; + 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 @@ -286,6 +286,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 @@ -224,6 +224,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 @@ -364,8 +364,10 @@ setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i32, Custom); setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i64, Custom); setOperationAction(ISD::STRICT_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); + setOperationAction(ISD::STRICT_FP_ROUND, MVT::f16, Custom); setOperationAction(ISD::STRICT_FP_ROUND, MVT::f32, Custom); setOperationAction(ISD::STRICT_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