blob: 63b0f8d35bdb7dbde8a0b1a0ae48c1657c4a3fb4 [file] [log] [blame]
/* { dg-do run { target { powerpc*-*-linux* } } } */
/* { dg-require-effective-target ppc_float128_sw } */
/* { dg-require-effective-target vsx_hw } */
/* { dg-options "-mvsx -O2" } */
/*
* Test program to make sure we are getting more precision than the 53 bits we
* get with IEEE double.
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stddef.h>
#ifndef TYPE
#define TYPE __float128
#endif
#ifndef NO_INLINE
#define NO_INLINE __attribute__((__noinline__))
#endif
static TYPE power_of_two (ssize_t) NO_INLINE;
static TYPE calc1 (TYPE) NO_INLINE;
static TYPE calc2 (TYPE) NO_INLINE;
static TYPE calc3 (TYPE) NO_INLINE;
#ifndef POWER2
#define POWER2 60
#endif
/*
* Print TYPE in hex.
*/
#if defined(DEBUG) || defined(DEBUG2)
static void print_hex (const char *prefix, TYPE, const char *suffix) NO_INLINE;
#if defined (__i386__) || defined (__x86_64__) || defined (__LITTLE_ENDIAN__)
#define ENDIAN_REVERSE(N, MAX) ((MAX) - 1 - (N))
#else
#define ENDIAN_REVERSE(N, MAX) (N)
#endif
static void
print_hex (const char *prefix, TYPE value, const char *suffix)
{
union {
TYPE f128;
unsigned char uc[sizeof (TYPE)];
} u;
size_t i;
u.f128 = value;
printf ("%s0x", prefix);
for (i = 0; i < sizeof (TYPE); i++)
printf ("%.2x", u.uc[ ENDIAN_REVERSE (i, sizeof (TYPE)) ]);
printf (", %24.2Lf%s", (long double)value, suffix);
}
#endif
/*
* Return a power of two.
*/
static TYPE
power_of_two (ssize_t num)
{
TYPE ret = (TYPE) 1.0;
ssize_t i;
if (num >= 0)
{
for (i = 0; i < num; i++)
ret *= (TYPE) 2.0;
}
else
{
ssize_t num2 = -num;
for (i = 0; i < num2; i++)
ret /= (TYPE) 2.0;
}
#ifdef DEBUG
printf ("power_of_two (%2ld) = ", (long) num);
print_hex ("", ret, "\n");
#endif
return ret;
}
#ifdef ADDSUB
static TYPE add (TYPE a, TYPE b) NO_INLINE;
static TYPE sub (TYPE a, TYPE b) NO_INLINE;
static TYPE
add (TYPE a, TYPE b)
{
TYPE c;
#ifdef DEBUG
print_hex ("add, arg1 = ", a, "\n");
print_hex ("add, arg2 = ", b, "\n");
#endif
c = a + b;
#ifdef DEBUG
print_hex ("add, result = ", c, "\n");
#endif
return c;
}
static TYPE
sub (TYPE a, TYPE b)
{
TYPE c;
#ifdef DEBUG
print_hex ("sub, arg1 = ", a, "\n");
print_hex ("sub, arg2 = ", b, "\n");
#endif
c = a - b;
#ifdef DEBUG
print_hex ("sub, result = ", c, "\n");
#endif
return c;
}
#else
#define add(x, y) ((x) + (y))
#define sub(x, y) ((x) - (y))
#endif
/*
* Various calculations. Add in 2**POWER2, and subtract 2**(POWER2-1) twice, and we should
* get the original value.
*/
static TYPE
calc1 (TYPE num)
{
TYPE num2 = add (power_of_two (POWER2), num);
TYPE ret;
#ifdef DEBUG
print_hex ("calc1 (before call) = ", num2, "\n");
#endif
ret = calc2 (num2);
#ifdef DEBUG
print_hex ("calc1 (after call) = ", ret, "\n");
#endif
return ret;
}
static TYPE
calc2 (TYPE num)
{
TYPE num2 = sub (num, power_of_two (POWER2-1));
TYPE ret;
#ifdef DEBUG
print_hex ("calc2 (before call) = ", num2, "\n");
#endif
ret = calc3 (num2);
#ifdef DEBUG
print_hex ("calc2 (after call) = ", ret, "\n");
#endif
return ret;
}
static TYPE
calc3 (TYPE num)
{
TYPE ret = sub (num, (((TYPE) 2.0) * power_of_two (POWER2-2)));
#ifdef DEBUG
print_hex ("calc3 = ", ret, "\n");
#endif
return ret;
}
int
main (void)
{
TYPE input, output;
#ifdef DEBUG
printf ("Testing, %ld bytes\n", (long) sizeof (TYPE));
#endif
input = power_of_two (-1);
if ((double)input != 0.5)
{
#if defined(DEBUG) || defined(DEBUG2)
print_hex ("Input should be 0.5: ", output, "\n");
return 1;
#else
__builtin_abort ();
#endif
}
output = calc1 (input);
if ((double)output != 0.5)
{
#if defined(DEBUG) || defined(DEBUG2)
print_hex ("Output should be 0.5: ", output, "\n");
return 1;
#else
__builtin_abort ();
#endif
}
return 0;
}