diff --git a/SingleSource/UnitTests/Float/check-helper.h b/SingleSource/UnitTests/Float/check-helper.h --- a/SingleSource/UnitTests/Float/check-helper.h +++ b/SingleSource/UnitTests/Float/check-helper.h @@ -15,46 +15,38 @@ #define DimOf(x) (sizeof(x) / sizeof(x[0])) -// Checks if condition 'cond' is true for the 'value'. +// Prints bits of a floating-point value, specified by the parameter 'value'. +// 'value' may an integer or a pointer to integer, the exact meaning is +// determined by macros VAL_FORMAT and GET_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'. +// VAL_FORMAT - printf format specifier, like "%d" or "%llx %llx", which +// should be used to print the value represented by the +// argument 'value'. +// GET_VALUE - a macro that extracts the value or values for printing +// the '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) +#define PRINT_VALUE(value) printf(VAL_FORMAT, GET_VALUE(value)); -// Checks if floating point 'value' is equal to the value 'expected' which is an -// integer that represents bits of floating point number. +// Checks if condition 'cond' is true for the 'value'. // -// Requires the following macros to be defined: +// The argument 'value' is a pointer to the bits representing the tested +// floating-point value. It does not participate in checks and is used only for +// printing the tested value in diagnostics. Actual value to print is obtained +// using macro 'GET_VALUE'. // -// 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__, (INT_TYPE)(value), (expected)); \ - exit(-1); \ - } \ - } while(0) +// Macros required to be defined are same as for PRINT_VALUE. +// +#define CHECK_VALUE(cond, value) \ + do { \ + if (!(cond)) { \ + printf("Check '%s' in file '%s' at line %d failed for the value '", \ + #cond, __FILE__, __LINE__); \ + PRINT_VALUE(value); \ + printf("'\n"); \ + exit(-1); \ + } \ + } while (0) + #endif diff --git a/SingleSource/UnitTests/Float/classify-f32.h b/SingleSource/UnitTests/Float/classify-f32.h --- a/SingleSource/UnitTests/Float/classify-f32.h +++ b/SingleSource/UnitTests/Float/classify-f32.h @@ -19,12 +19,8 @@ #include #include - -#define INT_FORMAT PRIx32 -#define FLOAT_FORMAT "g" -#define VAL_FORMAT INT_FORMAT -#define INT_TYPE uint32_t -#define FLOAT_TYPE float +#define VAL_FORMAT "%" PRIx32 +#define GET_VALUE(x) (*(uint32_t *)x) uint32_t FloatQNaNValues[] = { F32_MAKE(0, F32_EXP_MASK, F32_QNAN_BIT | F32_PAYLOAD_MASK), @@ -37,28 +33,25 @@ F32_MAKE(1, F32_EXP_MASK, F32_QNAN_BIT | 0x00100000U), F32_MAKE(0, F32_EXP_MASK, F32_QNAN_BIT | 0x00000001U), - F32_MAKE(1, F32_EXP_MASK, F32_QNAN_BIT | 0x00000002U) -}; + F32_MAKE(1, F32_EXP_MASK, F32_QNAN_BIT | 0x00000002U)}; -uint32_t FloatSNaNValues[] = { - F32_MAKE(0, F32_EXP_MASK, F32_PAYLOAD_MASK), - F32_MAKE(1, F32_EXP_MASK, F32_PAYLOAD_MASK), +uint32_t FloatSNaNValues[] = {F32_MAKE(0, F32_EXP_MASK, F32_PAYLOAD_MASK), + F32_MAKE(1, F32_EXP_MASK, F32_PAYLOAD_MASK), - F32_MAKE(0, F32_EXP_MASK, 0x00200000U), - F32_MAKE(1, F32_EXP_MASK, 0x00100000U), + F32_MAKE(0, F32_EXP_MASK, 0x00200000U), + F32_MAKE(1, F32_EXP_MASK, 0x00100000U), - F32_MAKE(0, F32_EXP_MASK, 0x00000001U), - F32_MAKE(1, F32_EXP_MASK, 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 + 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 + F32_MAKE(0, 0, 0), // +0.0 + F32_MAKE(1, 0, 0) // -0.0 }; uint32_t FloatDenormValues[] = { @@ -101,99 +94,130 @@ }; 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(FloatQNaNValues); i++) { uint32_t *IPtr = FloatQNaNValues + 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); + CHECK_VALUE(__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(!__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, IPtr); } for (unsigned i = 0; i < DimOf(FloatSNaNValues); i++) { uint32_t *IPtr = FloatSNaNValues + 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); + CHECK_VALUE(__builtin_isnan(X), IPtr); + CHECK_VALUE(__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(!__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, IPtr); } 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); + CHECK_VALUE(!__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(__builtin_isinf(X), IPtr); + CHECK_VALUE(!__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 1, IPtr); } 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); + CHECK_VALUE(!__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 4, IPtr); } 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); + CHECK_VALUE(!__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 3, IPtr); } 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); + CHECK_VALUE(!__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(__builtin_isfinite(X), IPtr); + CHECK_VALUE(__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 2, IPtr); } return 0; } -#undef INT_FORMAT -#undef FLOAT_FORMAT +#define FLOAT_TYPE float +#include "gen_isfpclass_funcs.h" + +void test_isfpclass_float() { + for (unsigned i = 0; i < DimOf(FloatZeroValues); i++) { + float X = *(float *)(FloatZeroValues + i); + if (__builtin_signbit(X) == 0) + test_fcPosZero_float(X); + else + test_fcNegZero_float(X); + } + for (unsigned i = 0; i < DimOf(FloatDenormValues); i++) { + float X = *(float *)(FloatDenormValues + i); + if (X < 0) + test_fcNegSubnormal_float(X); + else + test_fcPosSubnormal_float(X); + } + for (unsigned i = 0; i < DimOf(FloatNormalValues); i++) { + float X = *(float *)(FloatNormalValues + i); + if (X < 0) + test_fcNegNormal_float(X); + else + test_fcPosNormal_float(X); + } + for (unsigned i = 0; i < DimOf(FloatInfValues); i++) { + float X = *(float *)(FloatInfValues + i); + if (X > 0) + test_fcPosInf_float(X); + else + test_fcNegInf_float(X); + } + for (unsigned i = 0; i < DimOf(FloatQNaNValues); i++) { + float X = *(float *)(FloatQNaNValues + i); + test_fcQNan_float(X); + } + for (unsigned i = 0; i < DimOf(FloatSNaNValues); i++) { + float X = *(float *)(FloatSNaNValues + i); + test_fcSNan_float(X); + } + test_fcPosInf_float(__builtin_inff()); + test_fcNegInf_float(-__builtin_inff()); + test_fcPosZero_float(0.0F); + test_fcNegZero_float(-0.0F); +} + #undef VAL_FORMAT -#undef INT_TYPE +#undef GET_VALUE #undef FLOAT_TYPE #endif diff --git a/SingleSource/UnitTests/Float/classify-f64.h b/SingleSource/UnitTests/Float/classify-f64.h --- a/SingleSource/UnitTests/Float/classify-f64.h +++ b/SingleSource/UnitTests/Float/classify-f64.h @@ -19,12 +19,8 @@ #include #include - -#define INT_FORMAT PRIx64 -#define FLOAT_FORMAT "g" -#define VAL_FORMAT INT_FORMAT -#define INT_TYPE uint64_t -#define FLOAT_TYPE double +#define VAL_FORMAT "%" PRIx64 +#define GET_VALUE(x) (*(uint64_t *)x) uint64_t DoubleQNaNValues[] = { F64_MAKE(0, F64_EXP_MASK, F64_QNAN_BIT | F64_PAYLOAD_MASK), @@ -37,8 +33,7 @@ F64_MAKE(1, F64_EXP_MASK, F64_QNAN_BIT | 0x0002000000000000ULL), F64_MAKE(0, F64_EXP_MASK, F64_QNAN_BIT | 0x0000000000000001ULL), - F64_MAKE(1, F64_EXP_MASK, F64_QNAN_BIT | 0x0000000000000002ULL) -}; + F64_MAKE(1, F64_EXP_MASK, F64_QNAN_BIT | 0x0000000000000002ULL)}; uint64_t DoubleSNaNValues[] = { F64_MAKE(0, F64_EXP_MASK, F64_PAYLOAD_MASK), @@ -48,17 +43,16 @@ F64_MAKE(1, F64_EXP_MASK, 0x0002000000000000ULL), F64_MAKE(0, F64_EXP_MASK, 0x0000000000000001ULL), - F64_MAKE(1, F64_EXP_MASK, 0x0000000000000002ULL) -}; + 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 + 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 + F64_MAKE(0, 0, 0), // +0.0 + F64_MAKE(1, 0, 0) // -0.0 }; uint64_t DoubleDenormValues[] = { @@ -101,99 +95,130 @@ }; 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(DoubleQNaNValues); i++) { uint64_t *IPtr = DoubleQNaNValues + 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); + CHECK_VALUE(__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(!__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, IPtr); } for (unsigned i = 0; i < DimOf(DoubleSNaNValues); i++) { uint64_t *IPtr = DoubleSNaNValues + 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); + CHECK_VALUE(__builtin_isnan(X), IPtr); + CHECK_VALUE(__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(!__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, IPtr); } 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); + CHECK_VALUE(!__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(__builtin_isinf(X), IPtr); + CHECK_VALUE(!__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 1, IPtr); } 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); + CHECK_VALUE(!__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 4, IPtr); } 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); + CHECK_VALUE(!__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(__builtin_isfinite(X), IPtr); + CHECK_VALUE(!__builtin_isnormal(X), IPtr); + CHECK_VALUE(__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 3, IPtr); } 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); + CHECK_VALUE(!__builtin_isnan(X), IPtr); + CHECK_VALUE(!__builtin_issignaling(X), IPtr); + CHECK_VALUE(!__builtin_isinf(X), IPtr); + CHECK_VALUE(__builtin_isfinite(X), IPtr); + CHECK_VALUE(__builtin_isnormal(X), IPtr); + CHECK_VALUE(!__builtin_issubnormal(X), IPtr); + CHECK_VALUE(!__builtin_iszero(X), IPtr); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 2, IPtr); } return 0; } -#undef INT_FORMAT -#undef FLOAT_FORMAT +#define FLOAT_TYPE double +#include "gen_isfpclass_funcs.h" + +void test_isfpclass_double() { + for (unsigned i = 0; i < DimOf(DoubleZeroValues); i++) { + double X = *(double *)(DoubleZeroValues + i); + if (__builtin_signbit(X) == 0) + test_fcPosZero_double(X); + else + test_fcNegZero_double(X); + } + for (unsigned i = 0; i < DimOf(DoubleDenormValues); i++) { + double X = *(double *)(DoubleDenormValues + i); + if (X < 0) + test_fcNegSubnormal_double(X); + else + test_fcPosSubnormal_double(X); + } + for (unsigned i = 0; i < DimOf(DoubleNormalValues); i++) { + double X = *(double *)(DoubleNormalValues + i); + if (X < 0) + test_fcNegNormal_double(X); + else + test_fcPosNormal_double(X); + } + for (unsigned i = 0; i < DimOf(DoubleInfValues); i++) { + double X = *(double *)(DoubleInfValues + i); + if (X > 0) + test_fcPosInf_double(X); + else + test_fcNegInf_double(X); + } + for (unsigned i = 0; i < DimOf(DoubleQNaNValues); i++) { + double X = *(double *)(DoubleQNaNValues + i); + test_fcQNan_double(X); + } + for (unsigned i = 0; i < DimOf(DoubleSNaNValues); i++) { + double X = *(double *)(DoubleSNaNValues + i); + test_fcSNan_double(X); + } + test_fcPosInf_double(__builtin_inf()); + test_fcNegInf_double(-__builtin_inf()); + test_fcPosZero_double(0.0); + test_fcNegZero_double(-0.0); +} + #undef VAL_FORMAT -#undef INT_TYPE +#undef GET_VALUE #undef FLOAT_TYPE #endif diff --git a/SingleSource/UnitTests/Float/classify-f80.h b/SingleSource/UnitTests/Float/classify-f80.h new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/classify-f80.h @@ -0,0 +1,276 @@ +//===--- classify-fp80.h - Tests for x86 extended 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 x86 80-bit +// 'long double' type. +// +//===----------------------------------------------------------------------===// +#ifndef _CLASSIFY_F80_H_ +#define _CLASSIFY_F80_H_ + +#if defined(__LDBL_MANT_DIG__) && (__LDBL_MANT_DIG__ == 64) +#define USE_X86_FP80_TYPE +#endif + +#ifdef USE_X86_FP80_TYPE + +#include "check-helper.h" +#include "fformat.h" +#include +#include +#include +#include +#include + +typedef long double fp80; + +// Values in the tables for this type are actually 128-bit integers, stored as +// pairs of 64-bit values. +#define VAL_FORMAT "%08" PRIx64 " %016" PRIx64 +#define GET_VALUE(p) ((uint64_t *)(p))[1], ((uint64_t *)(p))[0] + +uint64_t ExtendedDoubleSNaNValues[] = { + F80_MAKE(0, F80_EXP_MASK, F80_INTEGER_BIT | F80_PAYLOAD_MASK), + F80_MAKE(1, F80_EXP_MASK, F80_INTEGER_BIT | F80_PAYLOAD_MASK), + F80_MAKE(0, F80_EXP_MASK, F80_INTEGER_BIT | 0x2000000000000000ULL), + F80_MAKE(1, F80_EXP_MASK, F80_INTEGER_BIT | 0x1000000000000000ULL), + F80_MAKE(1, F80_EXP_MASK, F80_INTEGER_BIT | 0x02ULL), + F80_MAKE(0, F80_EXP_MASK, F80_INTEGER_BIT | 0x01ULL)}; + +uint64_t ExtendedDoubleQNaNValues[] = { + F80_MAKE(0, F80_EXP_MASK, + F80_INTEGER_BIT | F80_QNAN_BIT | F80_PAYLOAD_MASK), + F80_MAKE(1, F80_EXP_MASK, + F80_INTEGER_BIT | F80_QNAN_BIT | F80_PAYLOAD_MASK), + F80_MAKE(0, F80_EXP_MASK, F80_INTEGER_BIT | F80_QNAN_BIT), + F80_MAKE(1, F80_EXP_MASK, F80_INTEGER_BIT | F80_QNAN_BIT), + F80_MAKE(0, F80_EXP_MASK, + F80_INTEGER_BIT | F80_QNAN_BIT | 0x2000000000000000ULL), + F80_MAKE(1, F80_EXP_MASK, + F80_INTEGER_BIT | F80_QNAN_BIT | 0x1000000000000000ULL), + F80_MAKE(1, F80_EXP_MASK, F80_INTEGER_BIT | F80_QNAN_BIT | 0x02ULL), + F80_MAKE(0, F80_EXP_MASK, F80_INTEGER_BIT | F80_QNAN_BIT | 0x01ULL)}; + +uint64_t ExtendedDoubleInfValues[] = { + F80_MAKE(0, F80_EXP_MASK, F80_INTEGER_BIT), + F80_MAKE(1, F80_EXP_MASK, F80_INTEGER_BIT)}; + +uint64_t ExtendedDoubleZeroValues[] = {F80_MAKE(0, 0, 0), F80_MAKE(1, 0, 0)}; + +uint64_t ExtendedDoubleDenormValues[] = { + F80_MAKE(0, 0, 1), // smallest positive denornal + F80_MAKE(1, 0, 1), // smallest negative denornal + F80_MAKE(0, 0, F80_FRACTIONAL_MASK), // largest positive denormal + F80_MAKE(1, 0, F80_FRACTIONAL_MASK) // largest negative denormal +}; + +uint64_t ExtendedDoubleNormValues[] = { + F80_NORMAL(0, F80_EXP_MIN, 0), // smallest positive normal + F80_NORMAL(1, F80_EXP_MIN, 0), // smallest negative normal + F80_NORMAL(0, F80_EXP_MAX, F80_FRACTIONAL_MASK), // largest positive normal + F80_NORMAL(1, F80_EXP_MAX, F80_FRACTIONAL_MASK), // largest negative normal + + F80_NORMAL(0, 0, 0), // +1 + F80_NORMAL(0, -1, F80_FRACTIONAL_MASK), // largest number less than 1 + F80_NORMAL(0, 0, 1), // smallest number larger than 1 + F80_NORMAL(0, 0, F80_MANTISSA(1, 0, 0)), // +1.5 + F80_NORMAL(0, 0, F80_MANTISSA(0, 1, 0)), // +1.25 + F80_NORMAL(0, 0, F80_MANTISSA(0, 0, 1)), // +1.125 + F80_NORMAL(0, -1, 0), // +0.5 + F80_NORMAL(0, -2, 0), // +0.25 + F80_NORMAL(0, -3, 0), // +0.125 + + F80_NORMAL(1, 0, 0), // -1 + F80_NORMAL(1, -1, F80_FRACTIONAL_MASK), + F80_NORMAL(1, 0, 1), + F80_NORMAL(1, 0, F80_MANTISSA(1, 0, 0)), // -1.5 + F80_NORMAL(1, 0, F80_MANTISSA(0, 1, 0)), // -1.25 + F80_NORMAL(1, 0, F80_MANTISSA(0, 0, 1)), // -1.125 + F80_NORMAL(1, -1, 0), // -0.5 + F80_NORMAL(1, -2, 0), // -0.25 + F80_NORMAL(1, -3, 0), // -0.125 + + F80_NORMAL(0, 1, 0), // 2 + F80_NORMAL(0, 1, F80_MANTISSA(1, 0, 0)), // 3 + F80_NORMAL(1, 1, 0), // -2 + F80_NORMAL(1, 1, F80_MANTISSA(1, 0, 0)) // -3 +}; + +uint64_t ExtendedDoubleUnsupportedValues[] = { + // Pseudo-NaNs. + F80_MAKE(0, F80_EXP_MASK, F80_PAYLOAD_MASK), + F80_MAKE(1, F80_EXP_MASK, F80_PAYLOAD_MASK), + F80_MAKE(0, F80_EXP_MASK, 0x2000000000000000ULL), + F80_MAKE(1, F80_EXP_MASK, 0x1000000000000000ULL), + F80_MAKE(1, F80_EXP_MASK, 0x02ULL), + F80_MAKE(0, F80_EXP_MASK, 0x01ULL), + F80_MAKE(0, F80_EXP_MASK, F80_QNAN_BIT | F80_PAYLOAD_MASK), + F80_MAKE(1, F80_EXP_MASK, F80_QNAN_BIT | F80_PAYLOAD_MASK), + F80_MAKE(0, F80_EXP_MASK, F80_QNAN_BIT), + F80_MAKE(1, F80_EXP_MASK, F80_QNAN_BIT), + F80_MAKE(0, F80_EXP_MASK, F80_QNAN_BIT | 0x2000000000000000ULL), + F80_MAKE(1, F80_EXP_MASK, F80_QNAN_BIT | 0x1000000000000000ULL), + F80_MAKE(1, F80_EXP_MASK, F80_QNAN_BIT | 0x02ULL), + F80_MAKE(0, F80_EXP_MASK, F80_QNAN_BIT | 0x01ULL), + // Pseudo-infinities. + F80_MAKE(0, F80_EXP_MASK, 0), + F80_MAKE(1, F80_EXP_MASK, 0), + // Unnormals. + F80_MAKE(0, 1, 0), + F80_MAKE(1, 1, 0), + F80_MAKE(0, 0x7FFE, 0), + F80_MAKE(1, 0x7FFE, 0), +}; + +uint64_t ExtendedDoublePseudoDenormalValues[] = { + // Pseudo-denormals. + F80_MAKE(0, 0, F80_INTEGER_BIT), + F80_MAKE(1, 0, F80_INTEGER_BIT), + F80_MAKE(0, 0, F80_INTEGER_BIT | 1), + F80_MAKE(1, 0, F80_INTEGER_BIT | 1), + F80_MAKE(0, 0, F80_INTEGER_BIT | F80_FRACTIONAL_MASK), + F80_MAKE(1, 0, F80_INTEGER_BIT | F80_FRACTIONAL_MASK), +}; + +int test_fp80() { + for (unsigned i = 0; i < DimOf(ExtendedDoubleQNaNValues); i += 2) { + uint64_t *P = (uint64_t *)(ExtendedDoubleQNaNValues + i); + long double X = *(long double *)P; + CHECK_VALUE(__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(!__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, P); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleSNaNValues); i += 2) { + uint64_t *P = (uint64_t *)(ExtendedDoubleSNaNValues + i); + long double X = *(long double *)P; + CHECK_VALUE(__builtin_isnan(X), P); + CHECK_VALUE(__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(!__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, P); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleInfValues); i += 2) { + uint64_t *P = (uint64_t *)(ExtendedDoubleInfValues + i); + long double X = *(long double *)P; + CHECK_VALUE(!__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(__builtin_isinf(X), P); + CHECK_VALUE(!__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 1, P); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleZeroValues); i += 2) { + uint64_t *P = (uint64_t *)(ExtendedDoubleZeroValues + i); + long double X = *(long double *)P; + CHECK_VALUE(!__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 4, P); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleDenormValues); i += 2) { + uint64_t *P = (uint64_t *)(ExtendedDoubleDenormValues + i); + long double X = *(long double *)P; + CHECK_VALUE(!__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 3, P); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleNormValues); i += 2) { + uint64_t *P = (uint64_t *)(ExtendedDoubleNormValues + i); + long double X = *(long double *)P; + CHECK_VALUE(!__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(__builtin_isfinite(X), P); + CHECK_VALUE(__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 2, P); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleUnsupportedValues); i += 2) { + uint64_t *P = (uint64_t *)(ExtendedDoubleUnsupportedValues + i); + long double X = *(long double *)P; + CHECK_VALUE(__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(!__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, P); + } + + return 0; +} + +#define FLOAT_TYPE fp80 +#include "gen_isfpclass_funcs.h" + +void test_isfpclass_fp80() { + for (unsigned i = 0; i < DimOf(ExtendedDoubleZeroValues); i += 2) { + long double X = *(long double *)(ExtendedDoubleZeroValues + i); + if (__builtin_signbit(X)) + test_fcNegZero_fp80(X); + else + test_fcPosZero_fp80(X); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleDenormValues); i += 2) { + long double X = *(long double *)(ExtendedDoubleDenormValues + i); + if (X < 0) + test_fcNegSubnormal_fp80(X); + else + test_fcPosSubnormal_fp80(X); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleNormValues); i += 2) { + long double X = *(long double *)(ExtendedDoubleNormValues + i); + if (X < 0) + test_fcNegNormal_fp80(X); + else + test_fcPosNormal_fp80(X); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleInfValues); i += 2) { + long double X = *(long double *)(ExtendedDoubleInfValues + i); + if (X > 0) + test_fcPosInf_fp80(X); + else + test_fcNegInf_fp80(X); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleQNaNValues); i += 2) { + long double X = *(long double *)(ExtendedDoubleQNaNValues + i); + test_fcQNan_fp80(X); + } + for (unsigned i = 0; i < DimOf(ExtendedDoubleSNaNValues); i += 2) { + long double X = *(long double *)(ExtendedDoubleSNaNValues + i); + test_fcSNan_fp80(X); + } +} + +#undef VAL_FORMAT +#undef GET_VALUE +#undef FLOAT_TYPE + +#endif // #ifdef USE_X86_FP80_TYPE +#endif // #ifndef _CLASSIFY_F80_H_ diff --git a/SingleSource/UnitTests/Float/classify-ldouble.h b/SingleSource/UnitTests/Float/classify-ldouble.h --- a/SingleSource/UnitTests/Float/classify-ldouble.h +++ b/SingleSource/UnitTests/Float/classify-ldouble.h @@ -13,19 +13,25 @@ #define _CLASSIFY_LDOUBLE_H_ #include "check-helper.h" +#include "fformat.h" #include #include #include #include #include +typedef long double ldouble; -// 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. +#define VAL_FORMAT "%Lg" +#define GET_VALUE(x) (*(long double *)x) +// The type long double does not have definite representation, it may be mapped +// to various floating-point types. In general case value tables are build using +// builtin functions and macro definitions provided by the compiler. +#ifdef __LDBL_HAS_QUIET_NAN__ long double LongDoubleSNaNValues[4]; long double LongDoubleQNaNValues[4]; +#endif #ifdef __LDBL_HAS_INFINITY__ long double LongDoubleInfValues[2]; #endif @@ -35,10 +41,6 @@ #endif long double LongDoubleNormalValues[6]; -#define FLOAT_FORMAT "Lg" -#define VAL_FORMAT FLOAT_FORMAT -#define FLOAT_TYPE long double - void prepare_ldouble_tables() { LongDoubleQNaNValues[0] = __builtin_nanl(""); LongDoubleQNaNValues[1] = -__builtin_nanl(""); @@ -68,64 +70,136 @@ } int test_ldouble() { - for (unsigned i = 0; i < DimOf(LongDoubleQNaNValues); i++) { - long double X = LongDoubleQNaNValues[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_QUIET_NAN__ + for (unsigned i = 0; i < DimOf(LongDoubleQNaNValues); ++i) { + uint64_t *P = (uint64_t *)(LongDoubleQNaNValues + i); + long double X = *(long double *)P; + CHECK_VALUE(__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(!__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, P); } - for (unsigned i = 0; i < DimOf(LongDoubleSNaNValues); i++) { - long double X = LongDoubleSNaNValues[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); + for (unsigned i = 0; i < DimOf(LongDoubleSNaNValues); ++i) { + uint64_t *P = (uint64_t *)(LongDoubleSNaNValues + i); + long double X = *(long double *)P; + CHECK_VALUE(__builtin_isnan(X), P); + CHECK_VALUE(__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(!__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 0, P); } +#endif #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); + for (unsigned i = 0; i < DimOf(LongDoubleInfValues); ++i) { + uint64_t *P = (uint64_t *)(LongDoubleInfValues + i); + long double X = *(long double *)P; + CHECK_VALUE(!__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(__builtin_isinf(X), P); + CHECK_VALUE(!__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 1, P); } #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); + for (unsigned i = 0; i < DimOf(LongDoubleZeroValues); ++i) { + uint64_t *P = (uint64_t *)(LongDoubleZeroValues + i); + long double X = *(long double *)P; + CHECK_VALUE(!__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 4, P); } #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); + for (unsigned i = 0; i < DimOf(LongDoubleDenormValues); ++i) { + uint64_t *P = (uint64_t *)(LongDoubleDenormValues + i); + long double X = *(long double *)P; + CHECK_VALUE(!__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(__builtin_isfinite(X), P); + CHECK_VALUE(!__builtin_isnormal(X), P); + CHECK_VALUE(__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 3, P); } #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); + for (unsigned i = 0; i < DimOf(LongDoubleNormalValues); ++i) { + uint64_t *P = (uint64_t *)(LongDoubleNormalValues + i); + long double X = *(long double *)P; + CHECK_VALUE(!__builtin_isnan(X), P); + CHECK_VALUE(!__builtin_issignaling(X), P); + CHECK_VALUE(!__builtin_isinf(X), P); + CHECK_VALUE(__builtin_isfinite(X), P); + CHECK_VALUE(__builtin_isnormal(X), P); + CHECK_VALUE(!__builtin_issubnormal(X), P); + CHECK_VALUE(!__builtin_iszero(X), P); + CHECK_VALUE(__builtin_fpclassify(0, 1, 2, 3, 4, X) == 2, P); } return 0; } -#undef FLOAT_FORMAT +#define FLOAT_TYPE ldouble +#include "gen_isfpclass_funcs.h" + +void test_isfpclass_ldouble() { + for (unsigned i = 0; i < DimOf(LongDoubleZeroValues); ++i) { + long double X = *(long double *)(LongDoubleZeroValues + i); + if (__builtin_signbit(X)) + test_fcNegZero_ldouble(X); + else + test_fcPosZero_ldouble(X); + } +#ifdef __LDBL_HAS_DENORM__ + for (unsigned i = 0; i < DimOf(LongDoubleDenormValues); ++i) { + long double X = *(long double *)(LongDoubleDenormValues + i); + if (X < 0) + test_fcNegSubnormal_ldouble(X); + else + test_fcPosSubnormal_ldouble(X); + } +#endif + for (unsigned i = 0; i < DimOf(LongDoubleNormalValues); ++i) { + long double X = *(long double *)(LongDoubleNormalValues + i); + if (X < 0) + test_fcNegNormal_ldouble(X); + else + test_fcPosNormal_ldouble(X); + } +#ifdef __LDBL_HAS_INFINITY__ + for (unsigned i = 0; i < DimOf(LongDoubleInfValues); ++i) { + long double X = *(long double *)(LongDoubleInfValues + i); + if (X > 0) + test_fcPosInf_ldouble(X); + else + test_fcNegInf_ldouble(X); + } +#endif + for (unsigned i = 0; i < DimOf(LongDoubleQNaNValues); ++i) { + long double X = *(long double *)(LongDoubleQNaNValues + i); + test_fcQNan_ldouble(X); + } + for (unsigned i = 0; i < DimOf(LongDoubleSNaNValues); ++i) { + long double X = *(long double *)(LongDoubleSNaNValues + i); + test_fcSNan_ldouble(X); + } +} + #undef VAL_FORMAT +#undef GET_VALUE #undef FLOAT_TYPE #endif diff --git a/SingleSource/UnitTests/Float/classify.c b/SingleSource/UnitTests/Float/classify.c --- a/SingleSource/UnitTests/Float/classify.c +++ b/SingleSource/UnitTests/Float/classify.c @@ -12,15 +12,20 @@ #include "classify-f32.h" #include "classify-f64.h" +#include "classify-f80.h" #include "classify-ldouble.h" - -int main() -{ +int main() { test_float(); + test_isfpclass_float(); test_double(); + test_isfpclass_double(); prepare_ldouble_tables(); test_ldouble(); + test_isfpclass_ldouble(); +#ifdef USE_X86_FP80_TYPE + test_fp80(); + test_isfpclass_fp80(); +#endif return 0; } - diff --git a/SingleSource/UnitTests/Float/fformat.h b/SingleSource/UnitTests/Float/fformat.h --- a/SingleSource/UnitTests/Float/fformat.h +++ b/SingleSource/UnitTests/Float/fformat.h @@ -62,4 +62,24 @@ ((m) & F64_MANTISSA_MASK)) #define F64_NORMAL(s, e, m) F64_MAKE((s), F64_EXP(e), (m)) + +#define F80_SIGN_BIT 0x0000000000008000ULL +#define F80_EXP_MASK 0x0000000000007FFFULL +#define F80_INTEGER_BIT 0x8000000000000000ULL +#define F80_FRACTIONAL_MASK 0x7FFFFFFFFFFFFFFFULL +#define F80_MANTISSA_MSB 0x4000000000000000ULL +#define F80_QNAN_BIT F80_MANTISSA_MSB +#define F80_PAYLOAD_MASK (F80_FRACTIONAL_MASK & ~F80_QNAN_BIT) +#define F80_SIGN_SHIFT 15 +#define F80_EXP_BIAS 16383 +#define F80_EXP_MIN (-16382) +#define F80_EXP_MAX 16383 +#define F80_EXP(e) ((uint64_t)(e) + F80_EXP_BIAS) +#define F80_MANTISSA(b1, b2, b3) \ + (((b1) ? F80_MANTISSA_MSB : 0) | \ + ((b2) ? (F80_MANTISSA_MSB >> 1) : 0) | \ + ((b3) ? (F80_MANTISSA_MSB >> 2) : 0)) +#define F80_MAKE(s, e, m) (m), (e) | ((s) ? F80_SIGN_BIT : 0) +#define F80_NORMAL(s, e, m) F80_MAKE((s), F80_EXP(e), F80_INTEGER_BIT | (m)) + #endif diff --git a/SingleSource/UnitTests/Float/gen_isfpclass_funcs.h b/SingleSource/UnitTests/Float/gen_isfpclass_funcs.h new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/gen_isfpclass_funcs.h @@ -0,0 +1,83 @@ +//===--- gen_isfpclass_funcs.h ------------------------------------*- 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 definition of functions that test a value of the +// specified floating point type for each of the floating point classes. +// +//===----------------------------------------------------------------------===// + +// Requires macros to be defined: same as used by "test_isfpclass.h". + +#ifndef _GEN_ISFPCLASS_FUNCS_H_ +#define _GEN_ISFPCLASS_FUNCS_H_ + +enum FPClassCheck { + fcBad = 0, + fcSNan = 0x0001, + fcQNan = 0x0002, + fcNegInf = 0x0004, + fcNegNormal = 0x0008, + fcNegSubnormal = 0x0010, + fcNegZero = 0x0020, + fcPosZero = 0x0040, + fcPosSubnormal = 0x0080, + fcPosNormal = 0x0100, + fcPosInf = 0x0200, + + fcNan = fcSNan | fcQNan, + fcInf = fcPosInf | fcNegInf, + fcNormal = fcPosNormal | fcNegNormal, + fcSubnormal = fcPosSubnormal | fcNegSubnormal, + fcZero = fcPosZero | fcNegZero, + fcPosFinite = fcPosNormal | fcPosSubnormal | fcPosZero, + fcNegFinite = fcNegNormal | fcNegSubnormal | fcNegZero, + fcFinite = fcPosFinite | fcNegFinite, + fcAllFlags = fcNan | fcInf | fcFinite +}; + +#endif + +#define FPCLASS fcSNan +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcQNan +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcPosInf +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcNegInf +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcPosNormal +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcNegNormal +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcPosSubnormal +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcNegSubnormal +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcPosZero +#include "test_isfpclass.h" +#undef FPCLASS + +#define FPCLASS fcNegZero +#include "test_isfpclass.h" +#undef FPCLASS diff --git a/SingleSource/UnitTests/Float/test_isfpclass.h b/SingleSource/UnitTests/Float/test_isfpclass.h new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Float/test_isfpclass.h @@ -0,0 +1,193 @@ +//===--- test_isfpclass.h -----------------------------------------*- 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 definition of a function that tests a value of +// the specified floating point class for various combinations of the check +// made by `__builtin_isfpclass`. The function has a name and arguments like: +// `test_fcSNan_float(float x)`. +// +//===----------------------------------------------------------------------===// + +// Requires the following macros to be defined: +// +// VAL_FORMAT - printf format specifier for value(s) extracted by GET_VALUE. +// GET_VALUE - a macro that extracts value(s) for printing. +// FPCLASS - FP class of the test function argument. +// FLOAT_TYPE - type of test function argument. + +#define CONCAT(fpclass, fptype) test_##fpclass##_##fptype +#define TEST_FUNC(fpclass, fptype) CONCAT(fpclass, fptype) + +#define CHECK_CLASS(cond, value) \ + do { \ + if (!(cond)) { \ + printf("Check '%s' failed for the value '" VAL_FORMAT "' " \ + ", FPCLASS=0x%x\n", \ + #cond, GET_VALUE(&value), FPCLASS); \ + exit(-1); \ + } \ + } while (0) + +#define CHECK(flags, value) \ + CHECK_CLASS(!!((flags)&FPCLASS) == !!__builtin_isfpclass((flags), (value)), \ + (value)) + +void TEST_FUNC(FPCLASS, FLOAT_TYPE)(FLOAT_TYPE x) { + CHECK(fcSNan, x); + CHECK(fcQNan, x); + CHECK(fcNan, x); + CHECK(fcPosInf, x); + CHECK(fcNegInf, x); + CHECK(fcInf, x); + CHECK(fcPosNormal, x); + CHECK(fcNegNormal, x); + CHECK(fcNormal, x); + CHECK(fcPosSubnormal, x); + CHECK(fcNegSubnormal, x); + CHECK(fcSubnormal, x); + CHECK(fcPosZero, x); + CHECK(fcNegZero, x); + CHECK(fcZero, x); + CHECK(fcPosFinite, x); + CHECK(fcNegFinite, x); + CHECK(fcFinite, x); + + CHECK(fcQNan | fcInf | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcSNan | fcInf | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcInf | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcNan | fcNegInf | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcNan | fcPosInf | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcNan | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcNan | fcInf | fcNegNormal | fcSubnormal | fcZero, x); + CHECK(fcNan | fcInf | fcPosNormal | fcSubnormal | fcZero, x); + CHECK(fcNan | fcInf | fcSubnormal | fcZero, x); + CHECK(fcNan | fcInf | fcNormal | fcNegSubnormal | fcZero, x); + CHECK(fcNan | fcInf | fcNormal | fcPosSubnormal | fcZero, x); + CHECK(fcNan | fcInf | fcNormal | fcZero, x); + CHECK(fcNan | fcInf | fcNormal | fcSubnormal | fcNegZero, x); + CHECK(fcNan | fcInf | fcNormal | fcSubnormal | fcPosZero, x); + CHECK(fcNan | fcInf | fcNormal | fcSubnormal, x); + CHECK(fcNan | fcInf | fcNegNormal | fcNegSubnormal | fcNegZero, x); + CHECK(fcNan | fcInf | fcPosNormal | fcPosSubnormal | fcPosZero, x); + CHECK(fcNan | fcInf, x); + + CHECK(fcSNan | fcPosInf, x); + CHECK(fcSNan | fcNegInf, x); + CHECK(fcSNan | fcInf, x); + CHECK(fcSNan | fcPosNormal, x); + CHECK(fcSNan | fcNegNormal, x); + CHECK(fcSNan | fcNormal, x); + CHECK(fcSNan | fcPosSubnormal, x); + CHECK(fcSNan | fcNegSubnormal, x); + CHECK(fcSNan | fcSubnormal, x); + CHECK(fcSNan | fcPosZero, x); + CHECK(fcSNan | fcNegZero, x); + CHECK(fcSNan | fcZero, x); + CHECK(fcSNan | fcPosNormal | fcPosSubnormal | fcPosZero, x); + CHECK(fcSNan | fcNegNormal | fcNegSubnormal | fcNegZero, x); + CHECK(fcSNan | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcQNan | fcPosInf, x); + CHECK(fcQNan | fcNegInf, x); + CHECK(fcQNan | fcInf, x); + CHECK(fcQNan | fcPosNormal, x); + CHECK(fcQNan | fcNegNormal, x); + CHECK(fcQNan | fcNormal, x); + CHECK(fcQNan | fcPosSubnormal, x); + CHECK(fcQNan | fcNegSubnormal, x); + CHECK(fcQNan | fcSubnormal, x); + CHECK(fcQNan | fcPosZero, x); + CHECK(fcQNan | fcNegZero, x); + CHECK(fcQNan | fcZero, x); + CHECK(fcQNan | fcPosNormal | fcPosSubnormal | fcPosZero, x); + CHECK(fcQNan | fcNegNormal | fcNegSubnormal | fcNegZero, x); + CHECK(fcQNan | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcNan | fcPosInf, x); + CHECK(fcNan | fcNegInf, x); + CHECK(fcNan | fcPosNormal, x); + CHECK(fcNan | fcNegNormal, x); + CHECK(fcNan | fcNormal, x); + CHECK(fcNan | fcPosSubnormal, x); + CHECK(fcNan | fcNegSubnormal, x); + CHECK(fcNan | fcSubnormal, x); + CHECK(fcNan | fcPosZero, x); + CHECK(fcNan | fcNegZero, x); + CHECK(fcNan | fcZero, x); + CHECK(fcNan | fcPosNormal | fcPosSubnormal | fcPosZero, x); + CHECK(fcNan | fcNegNormal | fcNegSubnormal | fcNegZero, x); + CHECK(fcPosInf | fcPosNormal, x); + CHECK(fcPosInf | fcNegNormal, x); + CHECK(fcPosInf | fcNormal, x); + CHECK(fcPosInf | fcPosSubnormal, x); + CHECK(fcPosInf | fcNegSubnormal, x); + CHECK(fcPosInf | fcSubnormal, x); + CHECK(fcPosInf | fcPosZero, x); + CHECK(fcPosInf | fcNegZero, x); + CHECK(fcPosInf | fcZero, x); + CHECK(fcPosInf | fcPosNormal | fcPosSubnormal | fcPosZero, x); + CHECK(fcPosInf | fcNegNormal | fcNegSubnormal | fcNegZero, x); + CHECK(fcPosInf | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcNegInf | fcPosNormal, x); + CHECK(fcNegInf | fcNegNormal, x); + CHECK(fcNegInf | fcNormal, x); + CHECK(fcNegInf | fcPosSubnormal, x); + CHECK(fcNegInf | fcNegSubnormal, x); + CHECK(fcNegInf | fcSubnormal, x); + CHECK(fcNegInf | fcPosZero, x); + CHECK(fcNegInf | fcNegZero, x); + CHECK(fcNegInf | fcZero, x); + CHECK(fcNegInf | fcPosNormal | fcPosSubnormal | fcPosZero, x); + CHECK(fcNegInf | fcNegNormal | fcNegSubnormal | fcNegZero, x); + CHECK(fcNegInf | fcNormal | fcSubnormal | fcZero, x); + CHECK(fcInf | fcPosNormal, x); + CHECK(fcInf | fcNegNormal, x); + CHECK(fcInf | fcNormal, x); + CHECK(fcInf | fcPosSubnormal, x); + CHECK(fcInf | fcNegSubnormal, x); + CHECK(fcInf | fcSubnormal, x); + CHECK(fcInf | fcPosZero, x); + CHECK(fcInf | fcNegZero, x); + CHECK(fcInf | fcZero, x); + CHECK(fcInf | fcPosNormal | fcPosSubnormal | fcPosZero, x); + CHECK(fcInf | fcNegNormal | fcNegSubnormal | fcNegZero, x); + CHECK(fcPosNormal | fcPosSubnormal, x); + CHECK(fcPosNormal | fcNegSubnormal, x); + CHECK(fcPosNormal | fcSubnormal, x); + CHECK(fcPosNormal | fcPosZero, x); + CHECK(fcPosNormal | fcNegZero, x); + CHECK(fcPosNormal | fcZero, x); + CHECK(fcNegNormal | fcPosSubnormal, x); + CHECK(fcNegNormal | fcNegSubnormal, x); + CHECK(fcNegNormal | fcSubnormal, x); + CHECK(fcNegNormal | fcPosZero, x); + CHECK(fcNegNormal | fcNegZero, x); + CHECK(fcNegNormal | fcZero, x); + CHECK(fcNormal | fcPosSubnormal, x); + CHECK(fcNormal | fcNegSubnormal, x); + CHECK(fcNormal | fcSubnormal, x); + CHECK(fcNormal | fcPosZero, x); + CHECK(fcNormal | fcNegZero, x); + CHECK(fcNormal | fcZero, x); + CHECK(fcPosSubnormal | fcPosZero, x); + CHECK(fcPosSubnormal | fcNegZero, x); + CHECK(fcPosSubnormal | fcZero, x); + CHECK(fcNegNormal | fcSubnormal | fcNegZero, x); + CHECK(fcNegSubnormal | fcPosZero, x); + CHECK(fcNegSubnormal | fcNegZero, x); + CHECK(fcNegSubnormal | fcZero, x); + CHECK(fcPosNormal | fcSubnormal | fcPosZero, x); + CHECK(fcSubnormal | fcPosZero, x); + CHECK(fcSubnormal | fcNegZero, x); + CHECK(fcSubnormal | fcZero, x); + CHECK(fcNegNormal | fcNegSubnormal | fcZero, x); + CHECK(fcPosNormal | fcPosSubnormal | fcZero, x); +} + +#undef CHECK +#undef CHECK_CLASS +#undef TEST_FUNC +#undef CONCAT