/* Derived from: */ /* * x86 CPU test * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include /**********************************************/ void test_fops(double a, double b) { printf("a=%f b=%f a+b=%f\n", a, b, a + b); printf("a=%f b=%f a-b=%f\n", a, b, a - b); printf("a=%f b=%f a*b=%f\n", a, b, a * b); printf("a=%f b=%f a/b=%f\n", a, b, a / b); printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b)); printf("a=%f sqrt(a)=%f\n", a, sqrt(a)); printf("a=%f sin(a)=%f\n", a, sin(a)); printf("a=%f cos(a)=%f\n", a, cos(a)); printf("a=%f tan(a)=%f\n", a, tan(a)); printf("a=%f log(a)=%f\n", a, log(a)); printf("a=%f exp(a)=%f\n", a, exp(a)); printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b)); /* just to test some op combining */ printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a))); printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a))); printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a))); } #define CC_C 0x0001 #define CC_P 0x0004 #define CC_A 0x0010 #define CC_Z 0x0040 #define CC_S 0x0080 #define CC_O 0x0800 void test_fcmp(double a, double b) { printf("(%f<%f)=%d\n", a, b, a < b); printf("(%f<=%f)=%d\n", a, b, a <= b); printf("(%f==%f)=%d\n", a, b, a == b); printf("(%f>%f)=%d\n", a, b, a > b); printf("(%f<=%f)=%d\n", a, b, a >= b); { unsigned int eflags; /* test f(u)comi instruction */ asm("fcomi %2, %1\n" "pushf\n" "pop %0\n" : "=r" (eflags) : "t" (a), "u" (b)); printf("fcomi(%f %f)=%08x\n", a, b, eflags & (CC_Z | CC_P | CC_C)); } } void test_fcvt(double a) { float fa; long double la; int16_t fpuc; int i; int64_t lla; int ia; int16_t wa; double ra; fa = a; la = a; printf("(float)%f = %f\n", a, fa); printf("(long double)%f = %Lf\n", a, la); printf("a=%016llx\n", *(long long *)&a); printf("la=%016llx %04x\n", *(long long *)&la, *(unsigned short *)((char *)(&la) + 8)); /* test all roundings */ asm volatile ("fstcw %0" : "=m" (fpuc)); for(i=0;i<4;i++) { int16_t tmp = (fpuc & ~0x0c00) | (i << 10); asm volatile ("fldcw %0" : : "m" (tmp)); asm volatile ("fists %0" : "=m" (wa) : "t" (a)); asm volatile ("fistl %0" : "=m" (ia) : "t" (a)); asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st"); asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a)); asm volatile ("fldcw %0" : : "m" (fpuc)); printf("(short)a = %d\n", wa); printf("(int)a = %d\n", ia); printf("(int64_t)a = %lld\n", lla); printf("rint(a) = %f\n", ra); } } #define TEST(N) \ asm("fld" #N : "=t" (a)); \ printf("fld" #N "= %f\n", a); void test_fconst(void) { double a; TEST(1); TEST(l2t); TEST(l2e); TEST(pi); TEST(lg2); TEST(ln2); TEST(z); } void test_fbcd(double a) { unsigned short bcd[5]; double b; asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st"); asm("fbld %1" : "=t" (b) : "m" (bcd[0])); printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); } #define TEST_ENV(env, save, restore)\ {\ memset((env), 0xaa, sizeof(*(env)));\ for(i=0;i<5;i++)\ asm volatile ("fldl %0" : : "m" (dtab[i]));\ asm(save " %0\n" : : "m" (*(env)));\ asm(restore " %0\n": : "m" (*(env)));\ for(i=0;i<5;i++)\ asm volatile ("fstpl %0" : "=m" (rtab[i]));\ for(i=0;i<5;i++)\ printf("res[%d]=%f\n", i, rtab[i]);\ printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ (env)->fpuc,\ (env)->fpus & 0xff00,\ (env)->fptag);\ } void test_fenv(void) { struct __attribute__((packed)) { uint16_t fpuc; uint16_t dummy1; uint16_t fpus; uint16_t dummy2; uint16_t fptag; uint16_t dummy3; uint32_t ignored[4]; long double fpregs[8]; } float_env32; struct __attribute__((packed)) { uint16_t fpuc; uint16_t fpus; uint16_t fptag; uint16_t ignored[4]; long double fpregs[8]; } float_env16; double dtab[8]; double rtab[8]; int i; for(i=0;i<8;i++) dtab[i] = i + 1; TEST_ENV(&float_env16, "data16/fnstenv", "data16/fldenv"); TEST_ENV(&float_env16, "data16/fnsave", "data16/frstor"); TEST_ENV(&float_env32, "fnstenv", "fldenv"); TEST_ENV(&float_env32, "fnsave", "frstor"); /* test for ffree */ for(i=0;i<5;i++) asm volatile ("fldl %0" : : "m" (dtab[i])); asm volatile("ffree %st(2)"); asm volatile ("fnstenv %0\n" : : "m" (float_env32)); asm volatile ("fninit"); printf("fptag=%04x\n", float_env32.fptag); } #define TEST_FCMOV(a, b, eflags, CC)\ {\ double res;\ asm("push %3\n"\ "popf\n"\ "fcmov" CC " %2, %0\n"\ : "=t" (res)\ : "0" (a), "u" (b), "g" (eflags));\ printf("fcmov%s eflags=0x%04x-> %f\n", \ CC, eflags, res);\ } void test_fcmov(void) { double a, b; int eflags, i; a = 1.0; b = 2.0; for(i = 0; i < 4; i++) { eflags = 0; if (i & 1) eflags |= CC_C; if (i & 2) eflags |= CC_Z; TEST_FCMOV(a, b, eflags, "b"); TEST_FCMOV(a, b, eflags, "e"); TEST_FCMOV(a, b, eflags, "be"); TEST_FCMOV(a, b, eflags, "nb"); TEST_FCMOV(a, b, eflags, "ne"); TEST_FCMOV(a, b, eflags, "nbe"); } TEST_FCMOV(a, b, 0, "u"); TEST_FCMOV(a, b, CC_P, "u"); TEST_FCMOV(a, b, 0, "nu"); TEST_FCMOV(a, b, CC_P, "nu"); } void test_floats(void) { test_fops(2, 3); test_fops(1.4, -5); test_fcmp(2, -1); test_fcmp(2, 2); test_fcmp(2, 3); test_fcvt(0.5); test_fcvt(-0.5); test_fcvt(1.0/7.0); test_fcvt(-1.0/9.0); test_fcvt(32768); test_fcvt(-1e20); test_fconst(); } int main ( void ) { test_floats(); return 0; }