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
10typedef  unsigned short int      UShort;
11typedef  unsigned int            UInt;
12typedef  double                  Double;
13typedef  unsigned long long int  ULong;
14
15typedef  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
25void 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
47void 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
69void 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
91void 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
114void 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
124int 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