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