Dejan Jevtic 3d1369a6e0 mips32: Support for 64bit FPU on MIPS32 platforms.
Tests for 64bit FPU instructions on MIPS32 platforms.
Some mips instructions can cause SIGILL (Illegal instruction),
so we need to add SIGILL signal and a proper handler for that signal.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13817
2014-02-19 11:57:22 +00:00

280 lines
9.0 KiB
C

#include <stdio.h>
typedef enum {
CEILWS=0, CEILWD,
FLOORWS, FLOORWD,
ROUNDWS, ROUNDWD,
TRUNCWS, TRUNCWD
} flt_dir_op_t;
typedef enum {
CVTDS, CVTDW,
CVTSD, CVTSW,
CVTWS, CVTWD
} flt_round_op_t;
typedef enum {
TO_NEAREST=0, TO_ZERO, TO_PLUS_INFINITY, TO_MINUS_INFINITY } round_mode_t;
char *round_mode_name[] = { "near", "zero", "+inf", "-inf" };
const char *flt_dir_op_names[] = {
"ceil.w.s", "ceil.w.d",
"floor.w.s", "floor.w.d",
"round.w.s", "round.w.d",
"trunc.w.s", "trunc.w.d"
};
const char *flt_round_op_names[] = {
"cvt.d.s", "cvt.d.w",
"cvt.s.d", "cvt.s.w",
"cvt.w.s", "cvt.w.d"
};
const double fs_d[] = {
0, 456.25, 3, -1,
1384.5, -7.25, 1000000000, -5786.25,
1752, 0.015625, 0.03125, -248562.75,
-45786.5, 456, 34.03125, 45786.75,
1752065, 107, -45667.25, -7,
-347856.5, 356047, -1.25, 23.0625
};
const float fs_f[] = {
0, 456.25, 3, -1,
1384.5, -7.25, 1000000000, -5786.25,
1752, 0.015625, 0.03125, -248562.75,
-45786.5, 456, 34.03125, 45786.75,
1752065, 107, -45667.25, -7,
-347856.5, 356047, -1.25, 23.0625
};
const int fs_w[] = {
0, 456, 3, -1,
0xffffffff, 356, 1000000000, -5786,
1752, 24575, 10, -248562,
-45786, 456, 34, 45786,
1752065, 107, -45667, -7,
-347856, 0x80000000, 0xFFFFFFF, 23
};
#define BINOP(op) \
__asm__ volatile(op" %1, %2, %3" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=f"(fd) \
: "f"(f) , "f"(fB));
#define UNOPdd(op) \
fd_d = 0; \
__asm__ volatile(op" %1, %2" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=f"(fd_d) \
: "f"(fs_d[i]));
#define UNOPff(op) \
fd_f = 0; \
__asm__ volatile(op" %1, %2" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=f"(fd_f) \
: "f"(fs_f[i]));
#define UNOPfd(op) \
fd_d = 0; \
__asm__ volatile(op" %1, %2" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=f"(fd_d) \
: "f"(fs_f[i]));
#define UNOPdf(op) \
fd_f = 0; \
__asm__ volatile(op" %1, %2" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=f"(fd_f) \
: "f"(fs_d[i]));
#define UNOPfw(op) \
fd_w = 0; \
__asm__ volatile(op" $f0, %2" "\n\t" \
"mfc1 %1, $f0" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=r"(fd_w) \
: "f"(fs_f[i]) \
: "$f0");
#define UNOPdw(op) \
fd_w = 0; \
__asm__ volatile(op" $f0, %2" "\n\t" \
"mfc1 %1, $f0" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=r"(fd_w) \
: "f"(fs_d[i]) \
: "$f0");
#define UNOPwd(op) \
fd_d = 0; \
__asm__ volatile("mtc1 %2, $f0" "\n\t" \
op" %1, $f0" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=f"(fd_d) \
: "r"(fs_w[i]) \
: "$f0", "$f1");
#define UNOPwf(op) \
fd_f = 0; \
__asm__ volatile("mtc1 %2, $f0" "\n\t" \
op" %1, $f0" "\n\t" \
"cfc1 %0, $31" "\n\t" \
: "=r" (fcsr), "=f"(fd_f) \
: "r"(fs_w[i]) \
: "$f0");
void set_rounding_mode(round_mode_t mode)
{
switch(mode) {
case TO_NEAREST:
__asm__ volatile("ctc1 $zero, $31" "\n\t");
break;
case TO_ZERO:
__asm__ volatile("li $t0, 0x1" "\n\t"
"ctc1 $t0, $31" "\n\t");
break;
case TO_PLUS_INFINITY:
__asm__ volatile("li $t0, 0x2" "\n\t"
"ctc1 $t0, $31" "\n\t");
break;
case TO_MINUS_INFINITY:
__asm__ volatile("li $t0, 0x3" "\n\t"
"ctc1 $t0, $31" "\n\t");
break;
}
}
int directedRoundingMode(flt_dir_op_t op) {
int fd_w = 0;
int i;
int fcsr = 0;
round_mode_t rm = TO_NEAREST;
for (i = 0; i < 24; i++) {
set_rounding_mode(rm);
switch(op) {
case CEILWS:
UNOPfw("ceil.w.s");
printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case CEILWD:
UNOPdw("ceil.w.d");
printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case FLOORWS:
UNOPfw("floor.w.s");
printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case FLOORWD:
UNOPdw("floor.w.d");
printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case ROUNDWS:
UNOPfw("round.w.s");
printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case ROUNDWD:
UNOPdw("round.w.d");
printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case TRUNCWS:
UNOPfw("trunc.w.s");
printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case TRUNCWD:
UNOPdw("trunc.w.d");
printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
default:
printf("error\n");
break;
}
}
return 0;
}
int FCSRRoundingMode(flt_round_op_t op1)
{
double fd_d = 0;
float fd_f = 0;
int fd_w = 0;
int i;
int fcsr = 0;
round_mode_t rm;
for (rm = TO_NEAREST; rm <= TO_MINUS_INFINITY; rm ++) {
set_rounding_mode(rm);
printf("roundig mode: %s\n", round_mode_name[rm]);
for (i = 0; i < 24; i++) {
set_rounding_mode(rm);
switch(op1) {
case CVTDS:
UNOPfd("cvt.d.s");
printf("%s %lf %lf\n", flt_round_op_names[op1], fd_d, fs_f[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case CVTDW:
UNOPwd("cvt.d.w");
printf("%s %lf %d\n", flt_round_op_names[op1], fd_d, fs_w[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case CVTSD:
UNOPdf("cvt.s.d");
printf("%s %f %lf\n", flt_round_op_names[op1], fd_f, fs_d[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case CVTSW:
UNOPwf("cvt.s.w");
printf("%s %f %d\n", flt_round_op_names[op1], fd_f, fs_w[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case CVTWS:
UNOPfw("cvt.w.s");
printf("%s %d %f\n", flt_round_op_names[op1], fd_w, fs_f[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
case CVTWD:
UNOPdw("cvt.w.d");
printf("%s %d %lf\n", flt_round_op_names[op1], fd_w, fs_d[i]);
printf("fcsr: 0x%x\n", fcsr);
break;
default:
printf("error\n");
break;
}
}
}
return 0;
}
int main()
{
flt_dir_op_t op;
flt_round_op_t op1;
printf("-------------------------- %s --------------------------\n",
"test FPU Conversion Operations Using a Directed Rounding Mode");
for (op = CEILWS; op <= TRUNCWD; op++) {
directedRoundingMode(op);
}
printf("-------------------------- %s --------------------------\n",
"test FPU Conversion Operations Using the FCSR Rounding Mode");
for (op1 = CVTDS; op1 <= CVTWD; op1++) {
FCSRRoundingMode(op1);
}
return 0;
}