mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
the 'x' format specifier. Use 'll' instead. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13596
274 lines
7.2 KiB
C
274 lines
7.2 KiB
C
|
|
/* On amd64, to exercise x87, compile with
|
|
gcc4 -ffast-math -mfpmath=387 -mfancy-math-387
|
|
|
|
gcc4 really does generate all the sin cos tan stuff as
|
|
x87 insns inline. gcc 3.3 doesn't, which makes the test
|
|
pretty useless, but it should still pass. To be on the safe
|
|
side we need to link with -lm to handle the gcc 3.3 behaviour.
|
|
*/
|
|
|
|
/* 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, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
#include <math.h>
|
|
|
|
/**********************************************/
|
|
|
|
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);
|
|
// requires fprem/fprem1 -- not done
|
|
//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 long long int eflags;
|
|
/* test f(u)comi instruction */
|
|
asm("fcomi %2, %1\n"
|
|
"pushfq\n"
|
|
"popq %0\n"
|
|
: "=r" (eflags)
|
|
: "t" (a), "u" (b));
|
|
printf("fcomi(%f %f)=%08llx\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)%e = %e\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));
|
|
wa=0;//asm volatile ("fist %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", (long long int)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("pushq %3\n"\
|
|
"popfq\n"\
|
|
"fcmov" CC " %2, %0\n"\
|
|
: "=t" (res)\
|
|
: "0" (a), "u" (b), "g" ((long long int)eflags));\
|
|
printf("fcmov%s eflags=0x%04llx-> %f\n", \
|
|
CC, (long long int)eflags, res);\
|
|
}
|
|
|
|
void test_fcmov(void)
|
|
{
|
|
double a, b;
|
|
long long 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;
|
|
}
|