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