Home | History | Annotate | Download | only in amd64
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    269 int main ( void )
    270 {
    271   test_floats();
    272   return 0;
    273 }
    274