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
42void 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
70void 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
94void 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=%016llx\n", *(long long *)&a);
110    printf("la=%016llx %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
134void 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
146void 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
174void 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
227void 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
253void 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
269int main ( void )
270{
271  test_floats();
272  return 0;
273}
274