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