diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index c8595b97b337d..42d197f2b08d0 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -296,6 +296,7 @@ endif () # long double is not 80 bits on Android or MSVC. set(x86_80_BIT_SOURCES divxc3.c + extendhfxf2.c extendxftf2.c fixxfdi.c fixxfti.c diff --git a/compiler-rt/lib/builtins/extendhfxf2.c b/compiler-rt/lib/builtins/extendhfxf2.c new file mode 100644 index 0000000000000..a2cd106e1c1b3 --- /dev/null +++ b/compiler-rt/lib/builtins/extendhfxf2.c @@ -0,0 +1,16 @@ +//===-- lib/extendhfxf2.c - half -> long double conversion --------*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "int_lib.h" +#define SRC_HALF +#define DST_DOUBLE +#include "fp_extend_impl.inc" + +// Long double are expected to be as precise as double. +COMPILER_RT_ABI xf_float __extendhfxf2(src_t a) { + return (xf_float)__extendXfYf2__(a); +} diff --git a/compiler-rt/test/builtins/Unit/extendhfxf2_test.c b/compiler-rt/test/builtins/Unit/extendhfxf2_test.c new file mode 100644 index 0000000000000..80e6f78cdd9c4 --- /dev/null +++ b/compiler-rt/test/builtins/Unit/extendhfxf2_test.c @@ -0,0 +1,73 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_extendhfxf2 + +#include +#include // for isnan, isinf +#include + +#include "int_lib.h" + +#if HAS_80_BIT_LONG_DOUBLE && defined(COMPILER_RT_HAS_FLOAT16) + +long double __extendhfxf2(_Float16 f); + +int test_extendhfxf2(_Float16 a, long double expected) { + long double x = __extendhfxf2(a); + __uint16_t *b = (void *)&a; + int ret = !((isnan(x) && isnan(expected)) || x == expected); + if (ret) { + printf("error in test__extendhfxf2(%#.4x) = %.20Lf, " + "expected %.20Lf\n", + *b, x, expected); + } + return ret; +} + +char assumption_1[sizeof(_Float16) * CHAR_BIT == 16] = {0}; + +int main() { + // Small positive value + if (test_extendhfxf2(0.09997558593750000000f, 0.09997558593750000000L)) + return 1; + + // Small negative value + if (test_extendhfxf2(-0.09997558593750000000f, -0.09997558593750000000L)) + return 1; + + // Zero + if (test_extendhfxf2(0.0f, 0.0L)) + return 1; + + // Smallest positive non-zero value + if (test_extendhfxf2(0x1p-16f, 0x1p-16L)) + return 1; + + // Smallest negative non-zero value + if (test_extendhfxf2(-0x1p-16f, -0x1p-16L)) + return 1; + + // Positive infinity + if (test_extendhfxf2(__builtin_huge_valf16(), __builtin_huge_valf64x())) + return 1; + + // Negative infinity + if (test_extendhfxf2(-__builtin_huge_valf16(), + (long double)-__builtin_huge_valf64x())) + return 1; + + // NaN + if (test_extendhfxf2(__builtin_nanf16(""), + (long double)__builtin_nanf64x(""))) + return 1; + + return 0; +} + +#else + +int main() { + printf("skipped\n"); + return 0; +} + +#endif