mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-09 00:46:12 +00:00
160 lines
4.3 KiB
C
160 lines
4.3 KiB
C
|
|
/* 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;
|
|
}
|