1
2 /* On amd64, to exercise x87, compile with
3 gcc4 -ffast-math -mfpmath=387 -mfancy-math-387
4
5 gcc4 really does generate all the sin cos tan stuff as
6 x87 insns inline. gcc 3.3 doesn't, which makes the test
7 pretty useless, but it should still pass. To be on the safe
8 side we need to link with -lm to handle the gcc 3.3 behaviour.
9 */
10
11 /* Derived from: */
12
13 /*
14 * x86 CPU test
15 *
16 * Copyright (c) 2003 Fabrice Bellard
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <inttypes.h>
38 #include <math.h>
39
40 /**********************************************/
41
test_fops(double a,double b)42 void test_fops(double a, double b)
43 {
44 printf("a=%f b=%f a+b=%f\n", a, b, a + b);
45 printf("a=%f b=%f a-b=%f\n", a, b, a - b);
46 printf("a=%f b=%f a*b=%f\n", a, b, a * b);
47 printf("a=%f b=%f a/b=%f\n", a, b, a / b);
48 // requires fprem/fprem1 -- not done
49 //printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b));
50 printf("a=%f sqrt(a)=%f\n", a, sqrt(a));
51 printf("a=%f sin(a)=%f\n", a, sin(a));
52 printf("a=%f cos(a)=%f\n", a, cos(a));
53 printf("a=%f tan(a)=%f\n", a, tan(a));
54 printf("a=%f log(a)=%f\n", a, log(a));
55 printf("a=%f exp(a)=%f\n", a, exp(a));
56 printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b));
57 /* just to test some op combining */
58 printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a)));
59 printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a)));
60 printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a)));
61 }
62 #define CC_C 0x0001
63 #define CC_P 0x0004
64 #define CC_A 0x0010
65 #define CC_Z 0x0040
66 #define CC_S 0x0080
67 #define CC_O 0x0800
68
69
test_fcmp(double a,double b)70 void test_fcmp(double a, double b)
71 {
72 printf("(%f<%f)=%d\n",
73 a, b, a < b);
74 printf("(%f<=%f)=%d\n",
75 a, b, a <= b);
76 printf("(%f==%f)=%d\n",
77 a, b, a == b);
78 printf("(%f>%f)=%d\n",
79 a, b, a > b);
80 printf("(%f<=%f)=%d\n",
81 a, b, a >= b);
82 {
83 unsigned long long int eflags;
84 /* test f(u)comi instruction */
85 asm("fcomi %2, %1\n"
86 "pushfq\n"
87 "popq %0\n"
88 : "=r" (eflags)
89 : "t" (a), "u" (b));
90 printf("fcomi(%f %f)=%08llx\n", a, b, eflags & (CC_Z | CC_P | CC_C));
91 }
92 }
93
test_fcvt(double a)94 void test_fcvt(double a)
95 {
96 float fa;
97 long double la;
98 int16_t fpuc;
99 int i;
100 int64_t lla;
101 int ia;
102 int16_t wa;
103 double ra;
104
105 fa = a;
106 la = a;
107 printf("(float)%e = %e\n", a, fa);
108 printf("(long double)%f = %Lf\n", a, la);
109 printf("a=%016Lx\n", *(long long *)&a);
110 printf("la=%016Lx %04x\n", *(long long *)&la,
111 *(unsigned short *)((char *)(&la) + 8));
112
113 /* test all roundings */
114 asm volatile ("fstcw %0" : "=m" (fpuc));
115 for(i=0;i<4;i++) {
116 int16_t tmp = (fpuc & ~0x0c00) | (i << 10);
117 asm volatile ("fldcw %0" : : "m" (tmp));
118 wa=0;//asm volatile ("fist %0" : "=m" (wa) : "t" (a));
119 asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
120 asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
121 asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
122 asm volatile ("fldcw %0" : : "m" (fpuc));
123 printf("(short)a = %d\n", wa);
124 printf("(int)a = %d\n", ia);
125 printf("(int64_t)a = %lld\n", (long long int)lla);
126 printf("rint(a) = %f\n", ra);
127 }
128 }
129
130 #define TEST(N) \
131 asm("fld" #N : "=t" (a)); \
132 printf("fld" #N "= %f\n", a);
133
test_fconst(void)134 void test_fconst(void)
135 {
136 double a;
137 TEST(1);
138 TEST(l2t);
139 TEST(l2e);
140 TEST(pi);
141 TEST(lg2);
142 TEST(ln2);
143 TEST(z);
144 }
145
test_fbcd(double a)146 void test_fbcd(double a)
147 {
148 unsigned short bcd[5];
149 double b;
150
151 asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st");
152 asm("fbld %1" : "=t" (b) : "m" (bcd[0]));
153 printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n",
154 a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
155 }
156
157 #define TEST_ENV(env, save, restore)\
158 {\
159 memset((env), 0xaa, sizeof(*(env)));\
160 for(i=0;i<5;i++)\
161 asm volatile ("fldl %0" : : "m" (dtab[i]));\
162 asm(save " %0\n" : : "m" (*(env)));\
163 asm(restore " %0\n": : "m" (*(env)));\
164 for(i=0;i<5;i++)\
165 asm volatile ("fstpl %0" : "=m" (rtab[i]));\
166 for(i=0;i<5;i++)\
167 printf("res[%d]=%f\n", i, rtab[i]);\
168 printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
169 (env)->fpuc,\
170 (env)->fpus & 0xff00,\
171 (env)->fptag);\
172 }
173
test_fenv(void)174 void test_fenv(void)
175 {
176 struct __attribute__((packed)) {
177 uint16_t fpuc;
178 uint16_t dummy1;
179 uint16_t fpus;
180 uint16_t dummy2;
181 uint16_t fptag;
182 uint16_t dummy3;
183 uint32_t ignored[4];
184 long double fpregs[8];
185 } float_env32;
186 struct __attribute__((packed)) {
187 uint16_t fpuc;
188 uint16_t fpus;
189 uint16_t fptag;
190 uint16_t ignored[4];
191 long double fpregs[8];
192 } float_env16;
193 double dtab[8];
194 double rtab[8];
195 int i;
196
197 for(i=0;i<8;i++)
198 dtab[i] = i + 1;
199
200 TEST_ENV(&float_env16, "data16 fnstenv", "data16 fldenv");
201 TEST_ENV(&float_env16, "data16 fnsave", "data16 frstor");
202 TEST_ENV(&float_env32, "fnstenv", "fldenv");
203 TEST_ENV(&float_env32, "fnsave", "frstor");
204
205 /* test for ffree */
206 for(i=0;i<5;i++)
207 asm volatile ("fldl %0" : : "m" (dtab[i]));
208 asm volatile("ffree %st(2)");
209 asm volatile ("fnstenv %0\n" : : "m" (float_env32));
210 asm volatile ("fninit");
211 printf("fptag=%04x\n", float_env32.fptag);
212 }
213
214
215 #define TEST_FCMOV(a, b, eflags, CC)\
216 {\
217 double res;\
218 asm("pushq %3\n"\
219 "popfq\n"\
220 "fcmov" CC " %2, %0\n"\
221 : "=t" (res)\
222 : "0" (a), "u" (b), "g" ((long long int)eflags));\
223 printf("fcmov%s eflags=0x%04llx-> %f\n", \
224 CC, (long long int)eflags, res);\
225 }
226
test_fcmov(void)227 void test_fcmov(void)
228 {
229 double a, b;
230 long long int eflags, i;
231
232 a = 1.0;
233 b = 2.0;
234 for(i = 0; i < 4; i++) {
235 eflags = 0;
236 if (i & 1)
237 eflags |= CC_C;
238 if (i & 2)
239 eflags |= CC_Z;
240 TEST_FCMOV(a, b, eflags, "b");
241 TEST_FCMOV(a, b, eflags, "e");
242 TEST_FCMOV(a, b, eflags, "be");
243 TEST_FCMOV(a, b, eflags, "nb");
244 TEST_FCMOV(a, b, eflags, "ne");
245 TEST_FCMOV(a, b, eflags, "nbe");
246 }
247 TEST_FCMOV(a, b, 0, "u");
248 TEST_FCMOV(a, b, CC_P, "u");
249 TEST_FCMOV(a, b, 0, "nu");
250 TEST_FCMOV(a, b, CC_P, "nu");
251 }
252
test_floats(void)253 void test_floats(void)
254 {
255 test_fops(2, 3);
256 test_fops(1.4, -5);
257 test_fcmp(2, -1);
258 test_fcmp(2, 2);
259 test_fcmp(2, 3);
260 test_fcvt(0.5);
261 test_fcvt(-0.5);
262 test_fcvt(1.0/7.0);
263 test_fcvt(-1.0/9.0);
264 test_fcvt(32768);
265 test_fcvt(-1e20);
266 test_fconst();
267 }
268
main(void)269 int main ( void )
270 {
271 test_floats();
272 return 0;
273 }
274