Index: valgrind/VEX/priv/guest-ppc/toIR.c =================================================================== --- valgrind/VEX/priv/guest-ppc/toIR.c (revision 1773) +++ valgrind/VEX/priv/guest-ppc/toIR.c (working copy) @@ -333,6 +333,7 @@ } PPC_GST; #define MASK_FPSCR_RN 0x3 +#define MASK_FPSCR_FPRF 0x1F000 #define MASK_VSCR_VALID 0x00010001 @@ -2142,7 +2143,7 @@ /* We're only keeping track of the rounding mode, so if the mask isn't asking for this, just return 0x0 */ - if (mask & 0x3) { + if (mask & (MASK_FPSCR_RN|MASK_FPSCR_FPRF)) { assign( val, IRExpr_Get( OFFB_FPROUND, Ity_I32 ) ); } else { assign( val, mkU32(0x0) ); @@ -2271,7 +2272,7 @@ switch (reg) { case PPC_GST_FPSCR: { /* Allow writes to Rounding Mode */ - if (mask & 0x3) { + if (mask & (MASK_FPSCR_RN|MASK_FPSCR_FPRF)) { /* construct new fpround from new and old values as per mask: new fpround = (src & (3 & mask)) | (fpround & (3 & ~mask)) */ stmt( @@ -2279,11 +2280,11 @@ OFFB_FPROUND, binop( Iop_Or32, - binop(Iop_And32, src, mkU32(3 & mask)), + binop(Iop_And32, src, mkU32((MASK_FPSCR_RN|MASK_FPSCR_FPRF) & mask)), binop( Iop_And32, IRExpr_Get(OFFB_FPROUND,Ity_I32), - mkU32(3 & ~mask) + mkU32((MASK_FPSCR_RN|MASK_FPSCR_FPRF) & ~mask) ) ) ) @@ -3224,6 +3225,48 @@ // TODO: alternatively: assign(rA, verbose_Clz64(rS)); break; + case 0x1FC: // cmpb (Power6: compare bytes) + DIP("cmpb r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr); + + if (mode64) + assign( rA, unop( Iop_V128to64, + binop( Iop_CmpEQ8x16, + binop( Iop_64HLtoV128, mkU64(0), mkexpr(rS) ), + binop( Iop_64HLtoV128, mkU64(0), mkexpr(rB) ) + )) ); + else + assign( rA, unop( Iop_V128to32, + binop( Iop_CmpEQ8x16, + unop( Iop_32UtoV128, mkexpr(rS) ), + unop( Iop_32UtoV128, mkexpr(rB) ) + )) ); + break; + + case 0x2DF: { // mftgpr (move floating-point to general purpose register) + IRTemp frB = newTemp(Ity_F64); + DIP("mftgpr r%u,fr%u\n", rS_addr, rB_addr); + + assign( frB, getFReg(rB_addr)); // always F64 + if (mode64) + assign( rA, unop( Iop_ReinterpF64asI64, mkexpr(frB)) ); + else + assign( rA, unop( Iop_64to32, unop( Iop_ReinterpF64asI64, mkexpr(frB))) ); + + putIReg( rS_addr, mkexpr(rA)); + return True; + } + case 0x25F: { // mffgpr (move floating-point from general purpose register) + IRTemp frA = newTemp(Ity_F64); + DIP("mffgpr fr%u,r%u\n", rS_addr, rB_addr); + + if (mode64) + assign( frA, unop( Iop_ReinterpI64asF64, mkexpr(rB)) ); + else + assign( frA, unop( Iop_ReinterpI64asF64, unop( Iop_32Uto64, mkexpr(rB))) ); + + putFReg( rS_addr, mkexpr(frA)); + return True; + } default: vex_printf("dis_int_logic(ppc)(opc2)\n"); return False; @@ -6462,6 +6505,45 @@ binop(Iop_I64toF64, rm, mkexpr(r_tmp64)) ); break; + case 0x188: case 0x1A8: case 0x1C8: case 0x1E8: // frin, friz, frip, frim + switch(opc2) { + case 0x188: // frin (Floating Round to Integer Nearest) + DIP("frin%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr); + assign( r_tmp64, + binop(Iop_F64toI64, mkU32(Irrm_NEAREST), mkexpr(frB)) ); + break; + case 0x1A8: // friz (Floating Round to Integer Toward Zero) + DIP("friz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr); + assign( r_tmp64, + binop(Iop_F64toI64, mkU32(Irrm_ZERO), mkexpr(frB)) ); + break; + case 0x1C8: // frip (Floating Round to Integer Plus) + DIP("frip%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr); + assign( r_tmp64, + binop(Iop_F64toI64, mkU32(Irrm_PosINF), mkexpr(frB)) ); + break; + case 0x1E8: // frim (Floating Round to Integer Minus) + DIP("frim%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr); + assign( r_tmp64, + binop(Iop_F64toI64, mkU32(Irrm_NegINF), mkexpr(frB)) ); + break; + } + + /* don't use the rounded integer if frB is outside -9e18..9e18 */ + /* F64 has only log10(2**52) significant digits anyway */ + /* need to preserve sign of zero */ + /* frD = (fabs(frB) > 9e18) ? frB : + (sign(frB)) ? -fabs((double)r_tmp64) : (double)r_tmp64 */ + assign( frD, IRExpr_Mux0X( unop( Iop_32to8, binop( Iop_CmpF64, + IRExpr_Const(IRConst_F64(9e18)), unop( Iop_AbsF64, mkexpr(frB)))), + IRExpr_Mux0X( unop( Iop_32to8, binop( Iop_Shr32, unop( Iop_64HIto32, + unop(Iop_ReinterpF64asI64, mkexpr(frB))), mkU8(31))), + binop( Iop_I64toF64, mkU32(0), mkexpr(r_tmp64) ), + unop( Iop_NegF64, unop( Iop_AbsF64, + binop(Iop_I64toF64, mkU32(0), mkexpr(r_tmp64)) )) ), + mkexpr(frB) )); + break; + default: vex_printf("dis_fp_round(ppc)(opc2)\n"); return False; @@ -9068,6 +9150,10 @@ case 0x32E: // fctid case 0x32F: // fctidz case 0x34E: // fcfid + case 0x188: // frin (Power5+) + case 0x1A8: // friz (Power5+) + case 0x1C8: // frip (Power5+) + case 0x1E8: // frim (Power5+) if (dis_fp_round(theInstr)) goto decode_success; goto decode_failure; @@ -9145,6 +9231,10 @@ if (dis_int_arith( theInstr )) goto decode_success; goto decode_failure; + case 0x1FC: // cmpb + if (dis_int_logic( theInstr )) goto decode_success; + goto decode_failure; + default: break; // Fall through... } @@ -9163,6 +9253,7 @@ case 0x11C: case 0x3BA: case 0x39A: // eqv, extsb, extsh case 0x1DC: case 0x07C: case 0x1BC: // nand, nor, or case 0x19C: case 0x13C: // orc, xor + case 0x2DF: case 0x25F: // mftgpr, mffgpr if (dis_int_logic( theInstr )) goto decode_success; goto decode_failure; Index: valgrind/none/tests/ppc32/Makefile.am =================================================================== --- valgrind/none/tests/ppc32/Makefile.am (revision 6738) +++ valgrind/none/tests/ppc32/Makefile.am (working copy) @@ -18,13 +18,15 @@ test_gx.stderr.exp test_gx.stdout.exp test_gx.vgtest \ testVMX.stderr.exp testVMX.stdout.exp testVMX.vgtest \ twi.stderr.exp twi.stdout.exp twi.vgtest \ - xlc_dbl_u32.stderr.exp xlc_dbl_u32.stdout.exp xlc_dbl_u32.vgtest + xlc_dbl_u32.stderr.exp xlc_dbl_u32.stdout.exp xlc_dbl_u32.vgtest \ + power5+_round.stderr.exp power5+_round.stdout.exp power5+_round.vgtest \ + power6_cmpb.stderr.exp power6_cmpb.stdout.exp power6_cmpb.vgtest check_PROGRAMS = \ bug129390-ppc32 \ bug139050-ppc32 \ ldstrev lsw jm-insns mftocrf mcrfs round test_fx test_gx \ - testVMX twi xlc_dbl_u32 + testVMX twi xlc_dbl_u32 power5+_round power6_cmpb AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -g -I$(top_srcdir)/include \ @FLAG_M32@ Index: valgrind/none/tests/ppc64/Makefile.am =================================================================== --- valgrind/none/tests/ppc64/Makefile.am (revision 6738) +++ valgrind/none/tests/ppc64/Makefile.am (working copy) @@ -8,10 +8,12 @@ lsw.stderr.exp lsw.stdout.exp lsw.vgtest \ std_reg_imm.vgtest std_reg_imm.stderr.exp std_reg_imm.stdout.exp \ round.stderr.exp round.stdout.exp round.vgtest \ - twi_tdi.stderr.exp twi_tdi.stdout.exp twi_tdi.vgtest + twi_tdi.stderr.exp twi_tdi.stdout.exp twi_tdi.vgtest \ + power6_cmpb.stderr.exp power6_cmpb.stdout.exp power6_cmpb.vgtest \ + power6_mf_gpr.stderr.exp power6_mf_gpr.stdout.exp power6_mf_gpr.vgtest check_PROGRAMS = \ - jm-insns lsw round std_reg_imm twi_tdi + jm-insns lsw round std_reg_imm twi_tdi power6_cmpb power6_mf_gpr AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -g -I$(top_srcdir)/include \ @FLAG_M64@ Index: valgrind/none/tests/ppc32/power5+_round.c =================================================================== --- valgrind/none/tests/ppc32/power5+_round.c (revision 0) +++ valgrind/none/tests/ppc32/power5+_round.c (revision 0) @@ -0,0 +1,146 @@ +/* Copyright (C) 2007 Pete Eberlein eberlein@us.ibm.com + + 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., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + + + +#include +#include +#include + +#define POS_NORMAL 0x4000 +#define NEG_NORMAL 0x8000 +#define POS_INF 0x5000 +#define NEG_INF 0x9000 +#define POS_ZERO 0x2000 +#define NEG_ZERO 0x12000 +#define POS_DENORMAL 0x14000 +#define NEG_DENORMAL 0x18000 +#define NAN 0x11000 +#define FPRF_MASK 0x1F000 + + +int main (int argc, char* argv[]) { + + double inf, neg0, nan; + union { + double d; + struct { unsigned int dummy, dummy2: 15, fprf:17; }; + } fpscr; + + inf = strtod("inf", NULL); + neg0 = strtod("-0", NULL); + nan = strtod("nan", NULL); + + + /* This set is disabled until fprf is implemented. */ + if (0) { + double set[] = {inf, 1.5, 0, neg0, -1.5, -inf, nan}; + int i, j, fprf; + for (i=0; i<7; ++i) { + for (j=0; j<7; ++j) { + asm ("fcmpu 1, %1, %2\n\t" \ + "mffs %0\n" \ + : "=f" (fpscr.d) \ + : "f" (set[i]), "f" (set[j]) \ + ); + + if (i == 6 || j == 6) { + fprf = 0x1000; // Unordered + } else if (i == j || (i==2 && j==3) || (i==3 && j==2)) { + fprf = 0x2000; // Equal + } else if (i < j) { + fprf = 0x4000; // Greater Than + } else if (i > j) { + fprf = 0x8000; // Less Than + } + + printf("fcmpu\t%.1f\t%.1f\t%x\t%s\n", set[i], set[j], fpscr.fprf, + fpscr.fprf == fprf ? "PASS" : "FAIL"); + } + } + } + + { + double set[] = {inf, 1.9, 1.1, 0, neg0, -1.1, -1.9, -inf, nan}; + double frin[] = {inf, 2.0, 1.0, 0, neg0, -1.0, -2.0, -inf, nan}; + double friz[] = {inf, 1.0, 1.0, 0, neg0, -1.0, -1.0, -inf, nan}; + double frip[] = {inf, 2.0, 2.0, 0, neg0, -1.0, -1.0, -inf, nan}; + double frim[] = {inf, 1.0, 1.0, 0, neg0, -2.0, -2.0, -inf, nan}; + int fprf[] = {POS_INF, POS_NORMAL, POS_NORMAL, POS_ZERO, NEG_ZERO, + NEG_NORMAL, NEG_NORMAL, NEG_INF, NAN}; + double set2[] = {0.9, 0.1, -0.1, -0.9, 1e-40, -1e-40}; + double frin2[] = {1.0, 0.0, -0.0, -1.0, 0.0, -0.0}; + int frin2rf[] = {POS_NORMAL,POS_ZERO,NEG_ZERO,NEG_NORMAL,POS_ZERO,NEG_ZERO}; + double friz2[] = {0.0, 0.0, -0.0, -0.0, 0.0, -0.0}; + int friz2rf[] = {POS_ZERO,POS_ZERO,NEG_ZERO,NEG_ZERO,POS_ZERO,NEG_ZERO}; + double frip2[] = {1.0, 1.0, -0.0, -0.0, 1.0, -0.0}; + int frip2rf[] = {POS_NORMAL,POS_NORMAL,NEG_ZERO,NEG_ZERO,POS_NORMAL,NEG_ZERO}; + double frim2[] = {0.0, 0.0, -1.0, -1.0, 0.0, -1.0}; + int frim2rf[] = {POS_ZERO,POS_ZERO,NEG_NORMAL,NEG_NORMAL,POS_ZERO,NEG_NORMAL}; + double ret; + int i; + +#define DO_TEST(op,in,out,rf) for (i=0; i +#include +#include + +#define CMPB(result,a,b) \ + asm __volatile ("cmpb %0, %1, %2\n" : "=r"(result) : "r"(a), "r"(b)) + + +int main (int argc, char* argv[]) { + int i,j,k; + long mask; + for (i=1; i<16; i++) { + mask = 0; + if(i&1) mask+=0xff; + if(i&2) mask+=0xff00; + if(i&4) mask+=0xff0000; + if(i&8) mask+=0xff000000; + + for (j=0; j<256; j++) + for (k=0; k<256; k++) + if (j!=k) { + + long a, b, result; + a = (mask & (j*0x1010101)) + ((~mask) & (k*0x1010101)); + b = j*0x1010101; + CMPB(result, a, b); + if (result != mask) + printf("%8x %8x %8x %8x\n", mask, a, b, result); + exit(1); + } + + } + + return 0; +} + Index: valgrind/none/tests/ppc32/power6_cmpb.stderr.exp =================================================================== --- valgrind/none/tests/ppc32/power6_cmpb.stderr.exp (revision 0) +++ valgrind/none/tests/ppc32/power6_cmpb.stderr.exp (revision 0) @@ -0,0 +1,2 @@ + + Index: valgrind/none/tests/ppc32/power6_cmpb.stdout.exp =================================================================== Index: valgrind/none/tests/ppc32/power6_cmpb.vgtest =================================================================== --- valgrind/none/tests/ppc32/power6_cmpb.vgtest (revision 0) +++ valgrind/none/tests/ppc32/power6_cmpb.vgtest (revision 0) @@ -0,0 +1 @@ +prog: power6_cmpb Index: valgrind/none/tests/ppc64/power6_cmpb.c =================================================================== --- valgrind/none/tests/ppc64/power6_cmpb.c (revision 0) +++ valgrind/none/tests/ppc64/power6_cmpb.c (revision 0) @@ -0,0 +1,61 @@ +/* Copyright (C) 2007 Pete Eberlein eberlein@us.ibm.com + + 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., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + + +#include +#include +#include + +#define CMPB(result,a,b) \ + asm ("cmpb %0, %1, %2\n" : "=r"(result) : "r"(a), "r"(b)) + + +int main (int argc, char* argv[]) { + int i,j,k; + unsigned long mask; + for (i=1; i<256; i++) { + mask = 0; + if(i&1) mask+=0xff; + if(i&2) mask+=0xff00; + if(i&4) mask+=0xff0000; + if(i&8) mask+=0xff000000; + if(i&16) mask+=0xff00000000; + if(i&32) mask+=0xff0000000000; + if(i&64) mask+=0xff000000000000; + if(i&128) mask+=0xff00000000000000; + + for (j=0; j<256; j++) + for (k=0; k<256; k++) + if (j!=k) { + + unsigned long a, b, result; + a = (mask & (j*0x101010101010101)) + ((~mask) & (k*0x101010101010101)); + b = j*0x101010101010101; + CMPB(result, a, b); + if (result != mask) + printf("%8lx %8lx %8lx %8lx\n", mask, a, b, result); + exit(1); + } + + } + + return 0; +} + Index: valgrind/none/tests/ppc64/power6_cmpb.stderr.exp =================================================================== --- valgrind/none/tests/ppc64/power6_cmpb.stderr.exp (revision 0) +++ valgrind/none/tests/ppc64/power6_cmpb.stderr.exp (revision 0) @@ -0,0 +1,2 @@ + + Index: valgrind/none/tests/ppc64/power6_cmpb.stdout.exp =================================================================== Index: valgrind/none/tests/ppc64/power6_cmpb.vgtest =================================================================== --- valgrind/none/tests/ppc64/power6_cmpb.vgtest (revision 0) +++ valgrind/none/tests/ppc64/power6_cmpb.vgtest (revision 0) @@ -0,0 +1 @@ +prog: power6_cmpb Index: valgrind/none/tests/ppc64/power6_mf_gpr.c =================================================================== --- valgrind/none/tests/ppc64/power6_mf_gpr.c (revision 0) +++ valgrind/none/tests/ppc64/power6_mf_gpr.c (revision 0) @@ -0,0 +1,47 @@ +/* Copyright (C) 2007 Pete Eberlein eberlein@us.ibm.com + + 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., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include +#include + + + +int main (int argc, char* argv[]) +{ + + long i; + double f; + + i = 0; + f = 100.0; + + printf("%lx %f\n", i, f); + + asm ("mftgpr %0, %1\n" : "=r"(i) : "f"(f)); + + f=0.0; + printf("%lx %f\n", i, f); + + asm ("mffgpr %0, %1\n" : "=f"(f) : "r"(i)); + + printf("%lx %f\n", i, f); + + return 0; +} Index: valgrind/none/tests/ppc64/power6_mf_gpr.stderr.exp =================================================================== --- valgrind/none/tests/ppc64/power6_mf_gpr.stderr.exp (revision 0) +++ valgrind/none/tests/ppc64/power6_mf_gpr.stderr.exp (revision 0) @@ -0,0 +1,2 @@ + + Index: valgrind/none/tests/ppc64/power6_mf_gpr.stdout.exp =================================================================== --- valgrind/none/tests/ppc64/power6_mf_gpr.stdout.exp (revision 0) +++ valgrind/none/tests/ppc64/power6_mf_gpr.stdout.exp (revision 0) @@ -0,0 +1,3 @@ +0 100.000000 +4059000000000000 0.000000 +4059000000000000 100.000000 Index: valgrind/none/tests/ppc64/power6_mf_gpr.vgtest =================================================================== --- valgrind/none/tests/ppc64/power6_mf_gpr.vgtest (revision 0) +++ valgrind/none/tests/ppc64/power6_mf_gpr.vgtest (revision 0) @@ -0,0 +1 @@ +prog: power6_mf_gpr