1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
/* Tests out of range handling for FSIN, FCOS, FSINCOS and FPTAN. Be
careful with the inline assembly -- this program is compiled as
both a 32-bit and 64-bit test. */
#include <stdio.h>
#include <string.h>
#include <assert.h>
typedef unsigned short int UShort;
typedef unsigned int UInt;
typedef double Double;
typedef unsigned long long int ULong;
typedef struct { Double arg; Double st0; Double st1; UShort fpusw; } Res;
#define SHIFT_C3 14
#define SHIFT_C2 10
#define SHIFT_C1 9
#define SHIFT_C0 8
#define my_offsetof(type,memb) ((int)(unsigned long int)&((type*)0)->memb)
void do_fsin ( /*OUT*/Res* r, double d )
{
assert(my_offsetof(Res,arg) == 0);
assert(my_offsetof(Res,st0) == 8);
assert(my_offsetof(Res,st1) == 16);
assert(my_offsetof(Res,fpusw) == 24);
memset(r, 0, sizeof(*r));
r->arg = d;
__asm__ __volatile__(
"finit" "\n\t"
"fldpi" "\n\t"
"fldl 0(%0)" "\n\t" // .arg
"fsin" "\n\t"
"fstsw %%ax" "\n\t"
"fstpl 8(%0)" "\n\t" // .st0
"fstpl 16(%0)" "\n\t" // .st1
"movw %%ax, 24(%0)" "\n\t" // .fpusw
"finit" "\n"
: : "r"(r) : "eax","cc","memory"
);
}
void do_fcos ( /*OUT*/Res* r, double d )
{
assert(my_offsetof(Res,arg) == 0);
assert(my_offsetof(Res,st0) == 8);
assert(my_offsetof(Res,st1) == 16);
assert(my_offsetof(Res,fpusw) == 24);
memset(r, 0, sizeof(*r));
r->arg = d;
__asm__ __volatile__(
"finit" "\n\t"
"fldpi" "\n\t"
"fldl 0(%0)" "\n\t" // .arg
"fcos" "\n\t"
"fstsw %%ax" "\n\t"
"fstpl 8(%0)" "\n\t" // .st0
"fstpl 16(%0)" "\n\t" // .st1
"movw %%ax, 24(%0)" "\n\t" // .fpusw
"finit" "\n"
: : "r"(r) : "eax","cc","memory"
);
}
void do_fsincos ( /*OUT*/Res* r, double d )
{
assert(my_offsetof(Res,arg) == 0);
assert(my_offsetof(Res,st0) == 8);
assert(my_offsetof(Res,st1) == 16);
assert(my_offsetof(Res,fpusw) == 24);
memset(r, 0, sizeof(*r));
r->arg = d;
__asm__ __volatile__(
"finit" "\n\t"
"fldpi" "\n\t"
"fldl 0(%0)" "\n\t" // .arg
"fsincos" "\n\t"
"fstsw %%ax" "\n\t"
"fstpl 8(%0)" "\n\t" // .st0
"fstpl 16(%0)" "\n\t" // .st1
"movw %%ax, 24(%0)" "\n\t" // .fpusw
"finit" "\n"
: : "r"(r) : "eax","cc","memory"
);
}
void do_fptan ( /*OUT*/Res* r, double d )
{
assert(my_offsetof(Res,arg) == 0);
assert(my_offsetof(Res,st0) == 8);
assert(my_offsetof(Res,st1) == 16);
assert(my_offsetof(Res,fpusw) == 24);
memset(r, 0, sizeof(*r));
r->arg = d;
__asm__ __volatile__(
"finit" "\n\t"
"fldpi" "\n\t"
"fldl 0(%0)" "\n\t" // .arg
"fptan" "\n\t"
"fstsw %%ax" "\n\t"
"fstpl 8(%0)" "\n\t" // .st0
"fstpl 16(%0)" "\n\t" // .st1
"movw %%ax, 24(%0)" "\n\t" // .fpusw
"finit" "\n"
: : "r"(r) : "eax","cc","memory"
);
}
void try ( char* name, void(*fn)(Res*,double), double d )
{
Res r;
fn(&r, d);
// Mask out all except C2 (range)
r.fpusw &= (1 << SHIFT_C2);
printf("%s %16e --> %16e %16e %04x\n",
name, r.arg, r.st0, r.st1, (UInt)r.fpusw);
}
int main ( void )
{
Double limit = 9223372036854775808.0; // 2^63
char* names[4] = { "fsin ", "fcos ", "fsincos", "fptan " };
void(*fns[4])(Res*,double) = { do_fsin, do_fcos, do_fsincos, do_fptan };
int i;
for (i = 0; i < 4; i++) {
char* name = names[i];
void (*fn)(Res*,double) = fns[i];
try( name, fn, 0.0 );
try( name, fn, 0.123 );
try( name, fn, -0.456 );
try( name, fn, 37.0 );
try( name, fn, -53.0 );
printf("\n");
try( name, fn, limit * 0.900000 );
try( name, fn, limit * 0.999999 );
try( name, fn, limit * 1.000000 );
try( name, fn, limit * 1.000001 );
try( name, fn, limit * 1.100000 );
printf("\n");
try( name, fn, -limit * 0.900000 );
try( name, fn, -limit * 0.999999 );
try( name, fn, -limit * 1.000000 );
try( name, fn, -limit * 1.000001 );
try( name, fn, -limit * 1.100000 );
printf("\n");
}
return 0;
}
|