diff --git a/SingleSource/UnitTests/CMakeLists.txt b/SingleSource/UnitTests/CMakeLists.txt --- a/SingleSource/UnitTests/CMakeLists.txt +++ b/SingleSource/UnitTests/CMakeLists.txt @@ -1,6 +1,7 @@ include(CheckCCompilerFlag) add_subdirectory(C++11) +add_subdirectory(Float) add_subdirectory(SignlessTypes) add_subdirectory(Threads) add_subdirectory(Vector) diff --git a/SingleSource/UnitTests/Float/CMakeLists.txt b/SingleSource/UnitTests/Float/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/CMakeLists.txt @@ -0,0 +1 @@ +llvm_singlesource() diff --git a/SingleSource/UnitTests/Float/Makefile b/SingleSource/UnitTests/Float/Makefile new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/Makefile @@ -0,0 +1,7 @@ +# SingleSource/UnitTests/Float/Makefile + +DIRS = +LEVEL = ../../.. +include $(LEVEL)/SingleSource/Makefile.singlesrc + + diff --git a/SingleSource/UnitTests/Float/check-helper.h b/SingleSource/UnitTests/Float/check-helper.h new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/check-helper.h @@ -0,0 +1,60 @@ +//===--- check-helper.h - Helper stuff for tests ------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This header file contains helper macros for making tests for floating point +// operations. +// +//===----------------------------------------------------------------------===// +#ifndef _CHECK_HELPER_H_ +#define _CHECK_HELPER_H_ + +#define DimOf(x) (sizeof(x) / sizeof(x[0])) + +// Checks if condition 'cond' is true for the 'value'. +// +// Requires the following macros to be defined: +// +// VAL_FORMAT - printf format specifier without %, like "d" or "llx", which +// should be used to print 'value'. +// +#define CHECK_VALUE(cond, value) \ + do { \ + if (!cond) { \ + printf("Check '%s' in file '%s' at line %d " \ + "failed for the value '%" VAL_FORMAT "'\n", \ + #cond, __FILE__, __LINE__, value); \ + exit(-1); \ + } \ + } while(0) + +// Checks if floating point 'value' is equal to the value 'expected' which is an +// integer that represents bits of floating point number. +// +// Requires the following macros to be defined: +// +// INT_FORMAT - printf format specifier without %, like "d" or "llx", +// which should be used to print 'expected'. +// FLOAT_FORMAT - printf format specifier without % to print 'value'. +// INT_TYPE - type of 'expected'. +// FLOAT_TYPE - type of 'value'. +// +#define CHECK_EQ(value, expected) \ + do { \ + union { \ + INT_TYPE i; \ + FLOAT_TYPE f; \ + } u; \ + u.i = value; \ + if (u.f != expected) { \ + printf("Check in file '%s' at line %d failed: " \ + "'%" INT_FORMAT "' != '%" FLOAT_FORMAT "'\n", \ + __FILE__, __LINE__, value, expected); \ + exit(-1); \ + } \ + } while(0) +#endif diff --git a/SingleSource/UnitTests/Float/classify-f32.h b/SingleSource/UnitTests/Float/classify-f32.h new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/classify-f32.h @@ -0,0 +1,184 @@ +//===--- classify-f32.h - Tests for 'float' classification --------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains tests of classification functions for 'float' type. +// +//===----------------------------------------------------------------------===// +#ifndef _CLASSIFY_F32_H_ +#define _CLASSIFY_F32_H_ + +#include "check-helper.h" +#include "fformat.h" +#include +#include +#include +#include + + +#define INT_FORMAT PRIx32 +#define FLOAT_FORMAT "g" +#define VAL_FORMAT INT_FORMAT +#define INT_TYPE uint32_t +#define FLOAT_TYPE float + +uint32_t FloatNaNValues[] = { + F32_MAKE(0, F32_EXP_MASK, F32_PAYLOAD_MASK), + F32_MAKE(1, F32_EXP_MASK, F32_PAYLOAD_MASK), + F32_MAKE(0, F32_EXP_MASK, F32_QNAN_BIT | F32_PAYLOAD_MASK), + F32_MAKE(1, F32_EXP_MASK, F32_QNAN_BIT | F32_PAYLOAD_MASK), + + F32_MAKE(0, F32_EXP_MASK, F32_QNAN_BIT), + F32_MAKE(1, F32_EXP_MASK, F32_QNAN_BIT), + + F32_MAKE(0, F32_EXP_MASK, F32_QNAN_BIT | 0x00200000U), + F32_MAKE(1, F32_EXP_MASK, F32_QNAN_BIT | 0x00100000U), + F32_MAKE(0, F32_EXP_MASK, 0x00200000U), + F32_MAKE(1, F32_EXP_MASK, 0x00100000U), + + F32_MAKE(0, F32_EXP_MASK, F32_QNAN_BIT | 0x00000001U), + F32_MAKE(1, F32_EXP_MASK, F32_QNAN_BIT | 0x00000002U), + F32_MAKE(0, F32_EXP_MASK, 0x00000001U), + F32_MAKE(1, F32_EXP_MASK, 0x00000002U) +}; + +uint32_t FloatInfValues[] = { + F32_MAKE(0, F32_EXP_MASK, 0), // +Inf + F32_MAKE(1, F32_EXP_MASK, 0) // -Inf +}; + +uint32_t FloatZeroValues[] = { + F32_MAKE(0, 0, 0), // +0.0 + F32_MAKE(1, 0, 0) // -0.0 +}; + +uint32_t FloatDenormValues[] = { + F32_MAKE(0, 0, 1), // smallest positive denornal + F32_MAKE(1, 0, 1), // smallest negative denornal + F32_MAKE(0, 0, F32_MANTISSA_MASK), // largest positive denormal + F32_MAKE(1, 0, F32_MANTISSA_MASK) // largest negative denormal +}; + +uint32_t FloatNormalValues[] = { + F32_NORMAL(0, F32_EXP_MIN, 0), // smallest positive normal + F32_NORMAL(1, F32_EXP_MIN, 0), // smallest negative normal + F32_NORMAL(0, F32_EXP_MAX, F32_MANTISSA_MASK), // largest positive normal + F32_NORMAL(1, F32_EXP_MAX, F32_MANTISSA_MASK), // largest negative normal + + F32_NORMAL(0, 0, 0), // +1 + F32_NORMAL(0, -1, F32_MANTISSA_MASK), // largest number less than 1 + F32_NORMAL(0, 0, 1), // smallest number larger than 1 + F32_NORMAL(0, 0, F32_MANTISSA(1, 0, 0)), // +1.5 + F32_NORMAL(0, 0, F32_MANTISSA(0, 1, 0)), // +1.25 + F32_NORMAL(0, 0, F32_MANTISSA(0, 0, 1)), // +1.125 + F32_NORMAL(0, -1, 0), // +0.5 + F32_NORMAL(0, -2, 0), // +0.25 + F32_NORMAL(0, -3, 0), // +0.125 + + F32_NORMAL(1, 0, 0), // -1 + F32_NORMAL(1, -1, F32_MANTISSA_MASK), + F32_NORMAL(1, 0, 1), + F32_NORMAL(1, 0, F32_MANTISSA(1, 0, 0)), // -1.5 + F32_NORMAL(1, 0, F32_MANTISSA(0, 1, 0)), // -1.25 + F32_NORMAL(1, 0, F32_MANTISSA(0, 0, 1)), // -1.125 + F32_NORMAL(1, -1, 0), // -0.5 + F32_NORMAL(1, -2, 0), // -0.25 + F32_NORMAL(1, -3, 0), // -0.125 + + F32_NORMAL(0, 1, 0), // 2 + F32_NORMAL(0, 1, F32_MANTISSA(1, 0, 0)), // 3 + F32_NORMAL(1, 1, 0), // -2 + F32_NORMAL(1, 1, F32_MANTISSA(1, 0, 0)) // -3 +}; + +int test_float() { + CHECK_EQ(F32_NORMAL(0, 0, 0), 1.0F); + CHECK_EQ(F32_NORMAL(0, 0, F32_MANTISSA(1, 0, 0)), 1.5F); + CHECK_EQ(F32_NORMAL(0, 0, F32_MANTISSA(0, 1, 0)), 1.25F); + CHECK_EQ(F32_NORMAL(0, 0, F32_MANTISSA(0, 0, 1)), 1.125); + CHECK_EQ(F32_NORMAL(0, -1, 0), 0.5F); + CHECK_EQ(F32_NORMAL(0, -2, 0), 0.25); + CHECK_EQ(F32_NORMAL(0, -3, 0), 0.125); + CHECK_EQ(F32_NORMAL(0, 1, 0), 2.0F); + CHECK_EQ(F32_NORMAL(0, 1, F32_MANTISSA(1, 0, 0)), 3.0F); + + CHECK_EQ(F32_NORMAL(1, 0, 0), -1.0F); + CHECK_EQ(F32_NORMAL(1, 0, F32_MANTISSA(1, 0, 0)), -1.5F); + CHECK_EQ(F32_NORMAL(1, 0, F32_MANTISSA(0, 1, 0)), -1.25F); + CHECK_EQ(F32_NORMAL(1, 0, F32_MANTISSA(0, 0, 1)), -1.125); + CHECK_EQ(F32_NORMAL(1, -1, 0), -0.5F); + CHECK_EQ(F32_NORMAL(1, -2, 0), -0.25); + CHECK_EQ(F32_NORMAL(1, -3, 0), -0.125); + CHECK_EQ(F32_NORMAL(1, 1, 0), -2.0F); + CHECK_EQ(F32_NORMAL(1, 1, F32_MANTISSA(1, 0, 0)), -3.0F); + + CHECK_EQ(F32_NORMAL(0, F32_EXP_MIN, 0), 1.1754943508e-38F); + CHECK_EQ(F32_NORMAL(1, F32_EXP_MIN, 0), -1.1754943508e-38F); + CHECK_EQ(F32_NORMAL(0, F32_EXP_MAX, F32_MANTISSA_MASK), 3.4028234664e38F); + CHECK_EQ(F32_NORMAL(1, F32_EXP_MAX, F32_MANTISSA_MASK), -3.4028234664e38F); + + for (unsigned i = 0; i < DimOf(FloatNaNValues); i++) { + uint32_t *IPtr = FloatNaNValues + i; + uint32_t IX = *IPtr; + float X = *(float *)IPtr; + CHECK_VALUE(__builtin_isnan(X), IX); + CHECK_VALUE(!__builtin_isinf(X), IX); + CHECK_VALUE(!__builtin_isfinite(X), IX); + CHECK_VALUE(!__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, IX); + } + for (unsigned i = 0; i < DimOf(FloatInfValues); i++) { + uint32_t *IPtr = FloatInfValues + i; + uint32_t IX = *IPtr; + float X = *(float *)IPtr; + CHECK_VALUE(!__builtin_isnan(X), IX); + CHECK_VALUE(__builtin_isinf(X), IX); + CHECK_VALUE(!__builtin_isfinite(X), IX); + CHECK_VALUE(!__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 1, IX); + } + for (unsigned i = 0; i < DimOf(FloatZeroValues); i++) { + uint32_t *IPtr = FloatZeroValues + i; + uint32_t IX = *IPtr; + float X = *(float *)IPtr; + CHECK_VALUE(!__builtin_isnan(X), IX); + CHECK_VALUE(!__builtin_isinf(X), IX); + CHECK_VALUE(__builtin_isfinite(X), IX); + CHECK_VALUE(!__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 4, IX); + } + for (unsigned i = 0; i < DimOf(FloatDenormValues); i++) { + uint32_t *IPtr = FloatDenormValues + i; + uint32_t IX = *IPtr; + float X = *(float *)IPtr; + CHECK_VALUE(!__builtin_isnan(X), IX); + CHECK_VALUE(!__builtin_isinf(X), IX); + CHECK_VALUE(__builtin_isfinite(X), IX); + CHECK_VALUE(!__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 3, IX); + } + for (unsigned i = 0; i < DimOf(FloatNormalValues); i++) { + uint32_t *IPtr = FloatNormalValues + i; + uint32_t IX = *IPtr; + float X = *(float *)IPtr; + CHECK_VALUE(!__builtin_isnan(X), IX); + CHECK_VALUE(!__builtin_isinf(X), IX); + CHECK_VALUE(__builtin_isfinite(X), IX); + CHECK_VALUE(__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 2, IX); + } + + return 0; +} + +#undef INT_FORMAT +#undef FLOAT_FORMAT +#undef VAL_FORMAT +#undef INT_TYPE +#undef FLOAT_TYPE + +#endif diff --git a/SingleSource/UnitTests/Float/classify-f64.h b/SingleSource/UnitTests/Float/classify-f64.h new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/classify-f64.h @@ -0,0 +1,184 @@ +//===--- classify-f64.h - Tests for 'double' classification -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains tests of classification functions for 'double' type. +// +//===----------------------------------------------------------------------===// +#ifndef _CLASSIFY_F64_H_ +#define _CLASSIFY_F64_H_ + +#include "check-helper.h" +#include "fformat.h" +#include +#include +#include +#include + + +#define INT_FORMAT PRIx64 +#define FLOAT_FORMAT "g" +#define VAL_FORMAT INT_FORMAT +#define INT_TYPE uint64_t +#define FLOAT_TYPE double + +uint64_t DoubleNaNValues[] = { + F64_MAKE(0, F64_EXP_MASK, F64_PAYLOAD_MASK), + F64_MAKE(1, F64_EXP_MASK, F64_PAYLOAD_MASK), + F64_MAKE(0, F64_EXP_MASK, F64_QNAN_BIT | F64_PAYLOAD_MASK), + F64_MAKE(1, F64_EXP_MASK, F64_QNAN_BIT | F64_PAYLOAD_MASK), + + F64_MAKE(0, F64_EXP_MASK, F64_QNAN_BIT), + F64_MAKE(1, F64_EXP_MASK, F64_QNAN_BIT), + + F64_MAKE(0, F64_EXP_MASK, F64_QNAN_BIT | 0x0004000000000000ULL), + F64_MAKE(1, F64_EXP_MASK, F64_QNAN_BIT | 0x0002000000000000ULL), + F64_MAKE(0, F64_EXP_MASK, 0x0004000000000000ULL), + F64_MAKE(1, F64_EXP_MASK, 0x0002000000000000ULL), + + F64_MAKE(0, F64_EXP_MASK, F64_QNAN_BIT | 0x0002000000000000ULL), + F64_MAKE(1, F64_EXP_MASK, F64_QNAN_BIT | 0x0004000000000000ULL), + F64_MAKE(0, F64_EXP_MASK, 0x0000000000000001ULL), + F64_MAKE(1, F64_EXP_MASK, 0x0000000000000002ULL) +}; + +uint64_t DoubleInfValues[] = { + F64_MAKE(0, F64_EXP_MASK, 0), // +Inf + F64_MAKE(1, F64_EXP_MASK, 0) // -Inf +}; + +uint64_t DoubleZeroValues[] = { + F64_MAKE(0, 0, 0), // +0.0 + F64_MAKE(1, 0, 0) // -0.0 +}; + +uint64_t DoubleDenormValues[] = { + F64_MAKE(0, 0, 1), // smallest positive denornal + F64_MAKE(1, 0, 1), // smallest negative denornal + F64_MAKE(0, 0, F64_MANTISSA_MASK), // largest positive denormal + F64_MAKE(1, 0, F64_MANTISSA_MASK) // largest negative denormal +}; + +uint64_t DoubleNormalValues[] = { + F64_NORMAL(0, F64_EXP_MIN, 0), // smallest positive normal + F64_NORMAL(1, F64_EXP_MIN, 0), // smallest negative normal + F64_NORMAL(0, F64_EXP_MAX, F64_MANTISSA_MASK), // largest positive normal + F64_NORMAL(1, F64_EXP_MAX, F64_MANTISSA_MASK), // largest negative normal + + F64_NORMAL(0, 0, 0), // +1 + F64_NORMAL(0, -1, F64_MANTISSA_MASK), // largest number less than 1 + F64_NORMAL(0, 0, 1), // smallest number larger than 1 + F64_NORMAL(0, 0, F64_MANTISSA(1, 0, 0)), // +1.5 + F64_NORMAL(0, 0, F64_MANTISSA(0, 1, 0)), // +1.25 + F64_NORMAL(0, 0, F64_MANTISSA(0, 0, 1)), // +1.125 + F64_NORMAL(0, -1, 0), // +0.5 + F64_NORMAL(0, -2, 0), // +0.25 + F64_NORMAL(0, -3, 0), // +0.125 + + F64_NORMAL(1, 0, 0), // -1 + F64_NORMAL(1, -1, F64_MANTISSA_MASK), + F64_NORMAL(1, 0, 1), + F64_NORMAL(1, 0, F64_MANTISSA(1, 0, 0)), // -1.5 + F64_NORMAL(1, 0, F64_MANTISSA(0, 1, 0)), // -1.25 + F64_NORMAL(1, 0, F64_MANTISSA(0, 0, 1)), // -1.125 + F64_NORMAL(1, -1, 0), // -0.5 + F64_NORMAL(1, -2, 0), // -0.25 + F64_NORMAL(1, -3, 0), // -0.125 + + F64_NORMAL(0, 1, 0), // 2 + F64_NORMAL(0, 1, F64_MANTISSA(1, 0, 0)), // 3 + F64_NORMAL(1, 1, 0), // -2 + F64_NORMAL(1, 1, F64_MANTISSA(1, 0, 0)) // -3 +}; + +int test_double() { + CHECK_EQ(F64_NORMAL(0, 0, 0), 1.0); + CHECK_EQ(F64_NORMAL(0, 0, F64_MANTISSA(1, 0, 0)), 1.5); + CHECK_EQ(F64_NORMAL(0, 0, F64_MANTISSA(0, 1, 0)), 1.25); + CHECK_EQ(F64_NORMAL(0, 0, F64_MANTISSA(0, 0, 1)), 1.125); + CHECK_EQ(F64_NORMAL(0, -1, 0), 0.5); + CHECK_EQ(F64_NORMAL(0, -2, 0), 0.25); + CHECK_EQ(F64_NORMAL(0, -3, 0), 0.125); + CHECK_EQ(F64_NORMAL(0, 1, 0), 2.0); + CHECK_EQ(F64_NORMAL(0, 1, F64_MANTISSA(1, 0, 0)), 3.0); + + CHECK_EQ(F64_NORMAL(1, 0, 0), -1.0); + CHECK_EQ(F64_NORMAL(1, 0, F64_MANTISSA(1, 0, 0)), -1.5); + CHECK_EQ(F64_NORMAL(1, 0, F64_MANTISSA(0, 1, 0)), -1.25); + CHECK_EQ(F64_NORMAL(1, 0, F64_MANTISSA(0, 0, 1)), -1.125); + CHECK_EQ(F64_NORMAL(1, -1, 0), -0.5); + CHECK_EQ(F64_NORMAL(1, -2, 0), -0.25); + CHECK_EQ(F64_NORMAL(1, -3, 0), -0.125); + CHECK_EQ(F64_NORMAL(1, 1, 0), -2.0); + CHECK_EQ(F64_NORMAL(1, 1, F64_MANTISSA(1, 0, 0)), -3.0); + + CHECK_EQ(F64_NORMAL(0, F64_EXP_MIN, 0), 2.2250738585072014e-308); + CHECK_EQ(F64_NORMAL(1, F64_EXP_MIN, 0), -2.2250738585072014e-308); + CHECK_EQ(F64_NORMAL(0, F64_EXP_MAX, F64_MANTISSA_MASK), 1.7976931348623157e+308); + CHECK_EQ(F64_NORMAL(1, F64_EXP_MAX, F64_MANTISSA_MASK), -1.7976931348623157e+308); + + for (unsigned i = 0; i < DimOf(DoubleNaNValues); i++) { + uint64_t *IPtr = DoubleNaNValues + i; + uint64_t IX = *IPtr; + double X = *(double *)IPtr; + CHECK_VALUE(__builtin_isnan(X), IX); + CHECK_VALUE(!__builtin_isinf(X), IX); + CHECK_VALUE(!__builtin_isfinite(X), IX); + CHECK_VALUE(!__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, IX); + } + for (unsigned i = 0; i < DimOf(DoubleInfValues); i++) { + uint64_t *IPtr = DoubleInfValues + i; + uint64_t IX = *IPtr; + double X = *(double *)IPtr; + CHECK_VALUE(!__builtin_isnan(X), IX); + CHECK_VALUE(__builtin_isinf(X), IX); + CHECK_VALUE(!__builtin_isfinite(X), IX); + CHECK_VALUE(!__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 1, IX); + } + for (unsigned i = 0; i < DimOf(DoubleZeroValues); i++) { + uint64_t *IPtr = DoubleZeroValues + i; + uint64_t IX = *IPtr; + double X = *(double *)IPtr; + CHECK_VALUE(!__builtin_isnan(X), IX); + CHECK_VALUE(!__builtin_isinf(X), IX); + CHECK_VALUE(__builtin_isfinite(X), IX); + CHECK_VALUE(!__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 4, IX); + } + for (unsigned i = 0; i < DimOf(DoubleDenormValues); i++) { + uint64_t *IPtr = DoubleDenormValues + i; + uint64_t IX = *IPtr; + double X = *(double *)IPtr; + CHECK_VALUE(!__builtin_isnan(X), IX); + CHECK_VALUE(!__builtin_isinf(X), IX); + CHECK_VALUE(__builtin_isfinite(X), IX); + CHECK_VALUE(!__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 3, IX); + } + for (unsigned i = 0; i < DimOf(DoubleNormalValues); i++) { + uint64_t *IPtr = DoubleNormalValues + i; + uint64_t IX = *IPtr; + double X = *(double *)IPtr; + CHECK_VALUE(!__builtin_isnan(X), IX); + CHECK_VALUE(!__builtin_isinf(X), IX); + CHECK_VALUE(__builtin_isfinite(X), IX); + CHECK_VALUE(__builtin_isnormal(X), IX); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 2, IX); + } + + return 0; +} + +#undef INT_FORMAT +#undef FLOAT_FORMAT +#undef VAL_FORMAT +#undef INT_TYPE +#undef FLOAT_TYPE + +#endif diff --git a/SingleSource/UnitTests/Float/classify-ldouble.h b/SingleSource/UnitTests/Float/classify-ldouble.h new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/classify-ldouble.h @@ -0,0 +1,121 @@ +//===--- classify-ldouble.h - Tests for 'long double' -------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains tests of classification functions for 'long double' type. +// +//===----------------------------------------------------------------------===// +#ifndef _CLASSIFY_LDOUBLE_H_ +#define _CLASSIFY_LDOUBLE_H_ + +#include "check-helper.h" +#include +#include +#include +#include +#include + + +// The type long double does not have definite representation, it may be mapped +// to various float types. So instead of preparing bit patterns, rely on builtin +// functions and macro definitions provided by the compiler. + +long double LongDoubleNaNValues[8]; +#ifdef __LDBL_HAS_INFINITY__ +long double LongDoubleInfValues[2]; +#endif +long double LongDoubleZeroValues[] = { 0.0L, -0.0L}; +#ifdef __LDBL_HAS_DENORM__ +long double LongDoubleDenormValues[2]; +#endif +long double LongDoubleNormalValues[6]; + +#define FLOAT_FORMAT "Lg" +#define VAL_FORMAT FLOAT_FORMAT +#define FLOAT_TYPE long double + +void prepare_ldouble_tables() { + LongDoubleNaNValues[0] = __builtin_nanl(""); + LongDoubleNaNValues[1] = -__builtin_nanl(""); + LongDoubleNaNValues[2] = __builtin_nanl("0x01"); + LongDoubleNaNValues[3] = -__builtin_nanl("0x01"); + LongDoubleNaNValues[4] = __builtin_nansl(""); + LongDoubleNaNValues[5] = -__builtin_nansl(""); + LongDoubleNaNValues[6] = __builtin_nansl("0x01"); + LongDoubleNaNValues[7] = -__builtin_nansl("0x01"); + +#ifdef __LDBL_HAS_INFINITY__ + LongDoubleInfValues[0] = __builtin_infl(); + LongDoubleInfValues[1] = -__builtin_infl(); +#endif +#ifdef __LDBL_HAS_DENORM__ + LongDoubleDenormValues[0] = __LDBL_DENORM_MIN__; + LongDoubleDenormValues[1] = -__LDBL_DENORM_MIN__; +#endif + + LongDoubleNormalValues[0] = 1.0L; + LongDoubleNormalValues[1] = -1.0L; + LongDoubleNormalValues[2] = __LDBL_MAX__; + LongDoubleNormalValues[3] = -__LDBL_MAX__; + LongDoubleNormalValues[4] = __LDBL_MIN__; + LongDoubleNormalValues[5] = -__LDBL_MIN__; +} + +int test_ldouble() { + for (unsigned i = 0; i < DimOf(LongDoubleNaNValues); i++) { + long double X = LongDoubleNaNValues[i]; + CHECK_VALUE(__builtin_isnan(X), X); + CHECK_VALUE(!__builtin_isinf(X), X); + CHECK_VALUE(!__builtin_isfinite(X), X); + CHECK_VALUE(!__builtin_isnormal(X), X); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, X); + } +#ifdef __LDBL_HAS_INFINITY__ + for (unsigned i = 0; i < DimOf(LongDoubleInfValues); i++) { + long double X = LongDoubleInfValues[i]; + CHECK_VALUE(!__builtin_isnan(X), X); + CHECK_VALUE(__builtin_isinf(X), X); + CHECK_VALUE(!__builtin_isfinite(X), X); + CHECK_VALUE(!__builtin_isnormal(X), X); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 1, X); + } +#endif + for (unsigned i = 0; i < DimOf(LongDoubleZeroValues); i++) { + long double X = LongDoubleZeroValues[i]; + CHECK_VALUE(!__builtin_isnan(X), X); + CHECK_VALUE(!__builtin_isinf(X), X); + CHECK_VALUE(__builtin_isfinite(X), X); + CHECK_VALUE(!__builtin_isnormal(X), X); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 4, X); + } +#ifdef __LDBL_HAS_DENORM__ + for (unsigned i = 0; i < DimOf(LongDoubleDenormValues); i++) { + long double X = LongDoubleDenormValues[i]; + CHECK_VALUE(!__builtin_isnan(X), X); + CHECK_VALUE(!__builtin_isinf(X), X); + CHECK_VALUE(__builtin_isfinite(X), X); + CHECK_VALUE(!__builtin_isnormal(X), X); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 3, X); + } +#endif + for (unsigned i = 0; i < DimOf(LongDoubleNormalValues); i++) { + long double X = LongDoubleNormalValues[i]; + CHECK_VALUE(!__builtin_isnan(X), X); + CHECK_VALUE(!__builtin_isinf(X), X); + CHECK_VALUE(__builtin_isfinite(X), X); + CHECK_VALUE(__builtin_isnormal(X), X); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 2, X); + } + + return 0; +} + +#undef FLOAT_FORMAT +#undef VAL_FORMAT +#undef FLOAT_TYPE + +#endif diff --git a/SingleSource/UnitTests/Float/classify.c b/SingleSource/UnitTests/Float/classify.c new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/classify.c @@ -0,0 +1,26 @@ +//===--- classify.cpp - Tess for FP classification intrinsics ---*- 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 +// +//===----------------------------------------------------------------------===// +// +// This is a general test for floating point classification intrinsic. +// +//===----------------------------------------------------------------------===// + +#include "classify-f32.h" +#include "classify-f64.h" +#include "classify-ldouble.h" + + +int main() +{ + test_float(); + test_double(); + prepare_ldouble_tables(); + test_ldouble(); + return 0; +} + diff --git a/SingleSource/UnitTests/Float/classify.reference_output b/SingleSource/UnitTests/Float/classify.reference_output new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/classify.reference_output @@ -0,0 +1 @@ +exit 0 diff --git a/SingleSource/UnitTests/Float/fformat.h b/SingleSource/UnitTests/Float/fformat.h new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/fformat.h @@ -0,0 +1,65 @@ +//===--- fformat.h - Descriptions of floating point formats -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This header file contains some macro definitions useful for working with bit +// accurate floating point representations. +// +//===----------------------------------------------------------------------===// +#ifndef _FFORMAT_H_ +#define _FFORMAT_H_ + +#define F32_SIGN_BIT 0x80000000U +#define F32_EXP_MASK 0x7F800000U +#define F32_MANTISSA_MASK 0x007FFFFFU +#define F32_MANTISSA_MSB 0x00400000U +#define F32_QNAN_BIT F32_MANTISSA_MSB +#define F32_PAYLOAD_MASK (F32_MANTISSA_MASK & ~F32_QNAN_BIT) +#define F32_SIGN_SHIFT 31 +#define F32_EXP_SHIFT 23 +#define F32_EXP_SIZE (F32_SIGN_SHIFT - F32_EXP_SHIFT) +#define F32_MANTISSA_SIZE F32_EXP_SHIFT +#define F32_EXP_BIAS 127 +#define F32_EXP_MIN (-126) +#define F32_EXP_MAX 127 +#define F32_EXP(e) (((e) + F32_EXP_BIAS) << F32_EXP_SHIFT) +#define F32_MANTISSA(b1, b2, b3) \ + (((b1) ? F32_MANTISSA_MSB : 0) | \ + ((b2) ? (F32_MANTISSA_MSB >> 1) : 0) | \ + ((b3) ? (F32_MANTISSA_MSB >> 2) : 0)) +#define F32_MAKE(s, e, m) \ + (((s) ? F32_SIGN_BIT : 0) | \ + ((e) & F32_EXP_MASK) | \ + ((m) & F32_MANTISSA_MASK)) +#define F32_NORMAL(s, e, m) F32_MAKE((s), F32_EXP(e), (m)) + + +#define F64_SIGN_BIT 0x8000000000000000ULL +#define F64_EXP_MASK 0x7FF0000000000000ULL +#define F64_MANTISSA_MASK 0x000FFFFFFFFFFFFFULL +#define F64_MANTISSA_MSB 0x0008000000000000ULL +#define F64_QNAN_BIT F64_MANTISSA_MSB +#define F64_PAYLOAD_MASK (F64_MANTISSA_MASK & ~F64_QNAN_BIT) +#define F64_SIGN_SHIFT 63 +#define F64_EXP_SHIFT 52 +#define F64_EXP_SIZE (F64_SIGN_SHIFT - F64_EXP_SHIFT) +#define F64_MANTISSA_SIZE F64_EXP_SHIFT +#define F64_EXP_BIAS 1023 +#define F64_EXP_MIN (-1022) +#define F64_EXP_MAX 1023 +#define F64_EXP(e) (((uint64_t)(e) + F64_EXP_BIAS) << F64_EXP_SHIFT) +#define F64_MANTISSA(b1, b2, b3) \ + (((b1) ? F64_MANTISSA_MSB : 0) | \ + ((b2) ? (F64_MANTISSA_MSB >> 1) : 0) | \ + ((b3) ? (F64_MANTISSA_MSB >> 2) : 0)) +#define F64_MAKE(s, e, m) \ + (((s) ? F64_SIGN_BIT : 0) | \ + ((e) & F64_EXP_MASK) | \ + ((m) & F64_MANTISSA_MASK)) +#define F64_NORMAL(s, e, m) F64_MAKE((s), F64_EXP(e), (m)) + +#endif