/* * Check that denormalised values are respected when they appear as input to * floating point operations copy, add, sub, abs, neg and convert s<->d * * The Cirrus Logic MaverickCrunch FPU truncates all denorms to 0 when they are * present as inputs to these operations. * * We check by doing math on the tiniest values. */ #if defined(__mips__) && defined(__sgi__) #include #endif /* defined(__mips__) && defined(__sgi__) */ #if __INT_MAX__ != 2147483647 || (__LONG_LONG_MAX__ != 9223372036854775807ll && __LONG_MAX__ != 9223372036854775807ll) int main(void) { exit (0); } #else #if __LONG_MAX__ != 9223372036854775807ll typedef unsigned long long ull; #else typedef unsigned long ull; #endif typedef unsigned ul; union fl { float f; ul l; } uf; union dl { double d; ull ll; } ud; int failed = 0; /* Two floats should be equal */ #define feq(a, b) if ((a) != (b)) failed++; /* Two floats should be different */ #define fneq(a, b) if ((a) == (b)) failed++; /* Convert a bit pattern into a float */ #define ultof(ul) ( uf.l = (ul), uf.f ) check_float() { register float one asm ("mvf3"), minus_one asm ("mvf4"); register float two asm ("mvf5"); register float TWO asm ("mvf7"); /* 2.0 */ /* bit 31: sign; bits 30-23 exponent; bits 22-0 mantissa. * Denormalized values: exponent is 0, mantissa is non-zero */ one = ultof(0x00000001UL); two = ultof(0x00000002UL); minus_one = ultof(0x80000001UL); TWO = ultof(0x40000000UL); /* 2.0f */ printf("FLOAT\n", one); printf("one = %e\n", one); printf("two = %e\n", two); printf("-one = %e\n", minus_one); printf("TWO = %e\n", TWO); /* first, check that comparisons recognize denorms */ if (one == two) { failed++; puts("one == two"); } if (one + one != two) { failed++; puts("one + one != two"); } if (two - one != one) { failed++; puts("two - one != one"); } if (one * TWO != two) { failed++; puts("one * 2.0 != two"); } if (-one != minus_one) { failed++; puts("-one != minus_one"); } if (-minus_one != one) { failed++; puts("-minus_one != one"); } if (__builtin_fabsf(one) != one) { failed++; puts("fabsf(one) != one"); } if (__builtin_fabsf(minus_one) != one) { failed++; puts("fabsf(minus_one) != one"); } } #define ulltod(ull) ( ud.ll = (ull), ud.d ) check_double() { register double one asm ("mvd3"), minus_one asm ("mvd4"); register double two asm ("mvd5"); register double TWO asm ("mvf7"); /* 2.0 */ /* bit 31: sign; bits 30-23 exponent; bits 22-0 mantissa. * Denormalized values: exponent is 0, mantissa is non-zero */ one = ulltod(0x0000000000000001ULL); two = ulltod(0x0000000000000002ULL); minus_one = ulltod(0x8000000000000001ULL); TWO = ulltod(0x4000000000000000ULL); printf("DOUBLE\n", one); printf("one = %e\n", one); printf("two = %e\n", two); printf("-one = %e\n", minus_one); printf("TWO = %e\n", TWO); /* first, check that comparisons recognize denorms */ if (one == two) { failed++; puts("one == two"); } if (one + one != two) { failed++; puts("one + one != two"); } if (two - one != one) { failed++; puts("two - one != one"); } if (one * TWO != two) { failed++; puts("one * 2.0 != two"); } if (-one != minus_one) { failed++; puts("-one != minus_one"); } if (-minus_one != one) { failed++; puts("-minus_one != one"); } if (__builtin_fabs(one) != one) { failed++; puts("fabs(one) != one"); } if (__builtin_fabs(minus_one) != one) { failed++; puts("fabs(minus_one) != one"); } } int main() { #if defined(__mips__) && defined(__sgi__) /* Many MIPS chips round denormalized floating point numbers to zero rather than follow the IEEE standard. Change the rounding mode to correspond to the IEEE rounding mode that rounds numbers to the nearest representable mode, the most common IEEE rounding mode. */ set_fpc_csr(0); #endif /* defined(__mips__) && defined(__sgi__) */ if (sizeof (float) != sizeof (ul) || sizeof (double) != sizeof (ull)) exit (0); #if (defined __arm__ || defined __thumb__) && ! (defined __ARMEB__ || defined __VFP_FP__) && ! (defined __MAVERICK__) /* The ARM always stores FP numbers in big-wordian format, even when running in little-byteian mode. */ #endif check_float(1.0); check_double(1.0); if (failed) abort (); else exit (0); } #endif