From: Julian Seward Date: Sat, 4 Dec 2004 01:38:37 +0000 (+0000) Subject: x86 guest/host: a whole bunch more SSE instructions. X-Git-Tag: svn/VALGRIND_3_0_1^2~719 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b69ba13305dc9126c90afaaf6ab8054ed8fa8930;p=thirdparty%2Fvalgrind.git x86 guest/host: a whole bunch more SSE instructions. git-svn-id: svn://svn.valgrind.org/vex/trunk@615 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 2baa1fa91b..b2a98d8ce6 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -605,6 +605,11 @@ static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno ) return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 ); } +static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno ) +{ + return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 ); +} + static void putXMMReg ( UInt xmmreg, IRExpr* e ) { vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128); @@ -623,6 +628,12 @@ static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e ) stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) ); } +static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e ) +{ + vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32); + stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) ); +} + static void assign ( IRTemp dst, IRExpr* e ) { stmt( IRStmt_Tmp(dst, e) ); @@ -6927,7 +6938,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, /*OUT*/ Addr64* whereNext ) { IRType ty; - IRTemp addr, t1, t2, t3, t4; + IRTemp addr, t0, t1, t2, t3, t4; Int alen; UChar opc, modrm, abyte; UInt d32; @@ -6955,7 +6966,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, assert. */ *size = 0; - addr = t1 = t2 = t3 = t4 = IRTemp_INVALID; + addr = t0 = t1 = t2 = t3 = t4 = IRTemp_INVALID; DIP("\t0x%x: ", guest_eip_bbstart+delta); @@ -7040,69 +7051,82 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, insn = (UChar*)&guest_code[delta]; /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */ + /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */ if (insn[0] == 0x0F && insn[1] == 0x12) { - delta += 2; - addr = disAMode ( &alen, sorb, delta, dis_buf ); - delta += alen; - - putXMMRegLane64( gregOfRM(insn[2]), 0/*lower lane*/, - loadLE(Ity_I64, mkexpr(addr)) ); - - DIP("movlps %s, %s\n", - dis_buf, nameXMMReg( gregOfRM(insn[2]) )); - + vassert(sz == 4); + modrm = getIByte(delta+2); + if (epartIsReg(modrm)) { + delta += 2+1; + putXMMRegLane64( gregOfRM(modrm), + 0/*lower lane*/, + getXMMRegLane64( eregOfRM(modrm), 1 )); + DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm))); + } else { + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + delta += 2+alen; + putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/, + loadLE(Ity_I64, mkexpr(addr)) ); + DIP("movlps %s, %s\n", + dis_buf, nameXMMReg( gregOfRM(modrm) )); + } goto decode_success; } /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */ if (insn[0] == 0x0F && insn[1] == 0x13) { - delta += 2; - addr = disAMode ( &alen, sorb, delta, dis_buf ); - delta += alen; - - storeLE( mkexpr(addr), - getXMMRegLane64( gregOfRM(insn[2]), - 0/*lower lane*/ ) ); - - DIP("movlps %s, %s\n", - nameXMMReg( gregOfRM(insn[2]) ), - dis_buf); - - goto decode_success; + if (!epartIsReg(insn[2])) { + vassert(sz == 4); + delta += 2; + addr = disAMode ( &alen, sorb, delta, dis_buf ); + delta += alen; + storeLE( mkexpr(addr), + getXMMRegLane64( gregOfRM(insn[2]), + 0/*lower lane*/ ) ); + DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ), + dis_buf); + goto decode_success; + } + /* else fall through */ } /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */ + /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */ if (insn[0] == 0x0F && insn[1] == 0x16) { vassert(sz == 4); - delta += 2; - addr = disAMode ( &alen, sorb, delta, dis_buf ); - delta += alen; - - putXMMRegLane64( gregOfRM(insn[2]), 1/*upper lane*/, - loadLE(Ity_I64, mkexpr(addr)) ); - - DIP("movhps %s, %s\n", - dis_buf, nameXMMReg( gregOfRM(insn[2]) )); - + modrm = getIByte(delta+2); + if (epartIsReg(modrm)) { + delta += 2+1; + putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/, + getXMMRegLane64( eregOfRM(modrm), 0 ) ); + DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm))); + } else { + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + delta += 2+alen; + putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/, + loadLE(Ity_I64, mkexpr(addr)) ); + DIP("movhps %s,%s\n", dis_buf, + nameXMMReg( gregOfRM(insn[2]) )); + } goto decode_success; } /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */ if (insn[0] == 0x0F && insn[1] == 0x17) { - vassert(sz == 4); - delta += 2; - addr = disAMode ( &alen, sorb, delta, dis_buf ); - delta += alen; - - storeLE( mkexpr(addr), - getXMMRegLane64( gregOfRM(insn[2]), - 1/*upper lane*/ ) ); - - DIP("movhps %s, %s\n", - nameXMMReg( gregOfRM(insn[2]) ), - dis_buf); - - goto decode_success; + if (!epartIsReg(insn[2])) { + vassert(sz == 4); + delta += 2; + addr = disAMode ( &alen, sorb, delta, dis_buf ); + delta += alen; + storeLE( mkexpr(addr), + getXMMRegLane64( gregOfRM(insn[2]), + 1/*upper lane*/ ) ); + DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ), + dis_buf); + goto decode_success; + } + /* else fall through */ } /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */ @@ -7393,6 +7417,158 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } + /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */ + /* 0F 10 = MOVAPS -- move from E (mem or xmm) to G (xmm). */ + if (insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) { + vassert(sz == 4); + modrm = getIByte(delta+2); + + if (epartIsReg(modrm)) { + putXMMReg( gregOfRM(modrm), + getXMMReg( eregOfRM(modrm) )); + DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm))); + delta += 2+1; + } else { + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + putXMMReg( gregOfRM(modrm), + loadLE(Ity_V128, mkexpr(addr)) ); + DIP("mov[ua]ps %s,%s\n", dis_buf, + nameXMMReg(gregOfRM(modrm))); + delta += 2+alen; + } + goto decode_success; + } + + /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E) + to 4 lowest bits of ireg(G) */ + if (insn[0] == 0x0F && insn[1] == 0x50) { + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + Int src; + vassert(sz == 4); + modrm = getIByte(delta+2); + delta += 2+1; + src = eregOfRM(modrm); + assign( t0, binop( Iop_And32, + binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)), + mkU32(1) )); + assign( t1, binop( Iop_And32, + binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)), + mkU32(2) )); + assign( t2, binop( Iop_And32, + binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)), + mkU32(4) )); + assign( t3, binop( Iop_And32, + binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)), + mkU32(8) )); + putIReg(4, gregOfRM(modrm), + binop(Iop_Or32, + binop(Iop_Or32, mkexpr(t0), mkexpr(t1)), + binop(Iop_Or32, mkexpr(t2), mkexpr(t3)) + ) + ); + DIP("movmskps %s,%s\n", nameXMMReg(src), + nameIReg(4, gregOfRM(modrm))); + goto decode_success; + } + + /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */ + if (insn[0] == 0x0F && insn[1] == 0x2B) { + modrm = getIByte(delta+2); + if (!epartIsReg(modrm)) { + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) ); + DIP("movntps %s,%s\n", dis_buf, + nameXMMReg(gregOfRM(modrm))); + delta += 2+alen; + goto decode_success; + } + /* else fall through */ + } + + /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the + Intel manual does not say anything about the usual business of + the FP reg tags getting trashed whenever an MMX insn happens. + So we just leave them alone. + */ + if (insn[0] == 0x0F && insn[1] == 0xE7) { + modrm = getIByte(delta+2); + if (!epartIsReg(modrm)) { + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) ); + DIP("movntq %s,%s\n", dis_buf, + nameMMXReg(gregOfRM(modrm))); + delta += 2+alen; + goto decode_success; + } + /* else fall through */ + } + + /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G + (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */ + if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) { + vassert(sz == 4); + modrm = getIByte(delta+3); + if (epartIsReg(modrm)) { + putXMMRegLane32( gregOfRM(modrm), 0, + getXMMRegLane32( eregOfRM(modrm), 0 )); + DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm))); + delta += 3+1; + } else { + addr = disAMode ( &alen, sorb, delta+3, dis_buf ); + putXMMReg( gregOfRM(modrm), mkV128(0) ); + putXMMRegLane32( gregOfRM(modrm), 0, + loadLE(Ity_I32, mkexpr(addr)) ); + DIP("movss %s,%s\n", dis_buf, + nameXMMReg(gregOfRM(modrm))); + delta += 3+alen; + } + goto decode_success; + } + + /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem + or lo 1/4 xmm). */ + if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) { + vassert(sz == 4); + modrm = getIByte(delta+3); + if (epartIsReg(modrm)) { + /* fall through, we don't yet have a test case */ + } else { + addr = disAMode ( &alen, sorb, delta+3, dis_buf ); + storeLE( mkexpr(addr), + getXMMRegLane32(eregOfRM(modrm), 0) ); + DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)), + dis_buf); + delta += 3+alen; + goto decode_success; + } + } + + /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */ + if (insn[0] == 0x0F && insn[1] == 0x59) { + vassert(sz == 4); + delta = dis_SSE_E_to_G( sorb, delta+2, "mulps", Iop_Mul32Fx4 ); + goto decode_success; + } + + /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */ + if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) { + vassert(sz == 4); + delta = dis_SSE_E_to_G( sorb, delta+3, "mulss", Iop_Mul32F0x4 ); + goto decode_success; + } + + /* 0F 56 = ORPS -- G = G and E */ + if (insn[0] == 0x0F && insn[1] == 0x56) { + vassert(sz == 4); + delta = dis_SSE_E_to_G( sorb, delta+2, "orps", Iop_Or128 ); + goto decode_success; + } + //-- //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */ //-- if (insn[0] == 0x0F && insn[1] == 0xAE diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index fef64e5fc9..2e7f854fe1 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -2353,6 +2353,7 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) case Xin_Sse128: *p++ = 0x0F; switch (i->Xin.Sse128.op) { + case Xsse_OR: *p++ = 0x56; break; case Xsse_XOR: *p++ = 0x57; break; case Xsse_AND: *p++ = 0x54; break; default: goto bad; @@ -2369,6 +2370,7 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) case Xsse_DIVF: *p++ = 0x5E; break; case Xsse_MAXF: *p++ = 0x5F; break; case Xsse_MINF: *p++ = 0x5D; break; + case Xsse_MULF: *p++ = 0x59; break; case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break; case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break; @@ -2389,6 +2391,7 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) case Xsse_DIVF: *p++ = 0x5E; break; case Xsse_MAXF: *p++ = 0x5F; break; case Xsse_MINF: *p++ = 0x5D; break; + case Xsse_MULF: *p++ = 0x59; break; case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break; case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break; diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index d05d00a876..0347d14d17 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -2475,6 +2475,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) } case Iop_And128: op = Xsse_AND; goto do_128; + case Iop_Or128: op = Xsse_OR; goto do_128; case Iop_Xor128: op = Xsse_XOR; goto do_128; do_128: { @@ -2493,6 +2494,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) case Iop_Div32Fx4: op = Xsse_DIVF; goto do_32Fx4; case Iop_Max32Fx4: op = Xsse_MAXF; goto do_32Fx4; case Iop_Min32Fx4: op = Xsse_MINF; goto do_32Fx4; + case Iop_Mul32Fx4: op = Xsse_MULF; goto do_32Fx4; do_32Fx4: { HReg argL = iselVecExpr(env, e->Iex.Binop.arg1); @@ -2510,6 +2512,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) case Iop_Div32F0x4: op = Xsse_DIVF; goto do_32F0x4; case Iop_Max32F0x4: op = Xsse_MAXF; goto do_32F0x4; case Iop_Min32F0x4: op = Xsse_MINF; goto do_32F0x4; + case Iop_Mul32F0x4: op = Xsse_MULF; goto do_32F0x4; do_32F0x4: { HReg argL = iselVecExpr(env, e->Iex.Binop.arg1); HReg argR = iselVecExpr(env, e->Iex.Binop.arg2); @@ -2581,6 +2584,11 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) Xalu_MOV, X86RI_Reg(vHi), X86AMode_IR(4, rA))); return; } + if (tyd == Ity_V128) { + HReg r = iselVecExpr(env, stmt->Ist.STle.data); + addInstr(env, X86Instr_SseLdSt(False/*store*/, r, am)); + return; + } break; } diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 2939053cc8..0434c2f813 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -236,6 +236,9 @@ void ppIROp ( IROp op ) case Iop_Min32Fx4: vex_printf("Min32Fx4"); return; case Iop_Min32F0x4: vex_printf("Min32F0x4"); return; + case Iop_Mul32Fx4: vex_printf("Mul32Fx4"); return; + case Iop_Mul32F0x4: vex_printf("Mul32F0x4"); return; + case Iop_CmpEQ32Fx4: vex_printf("CmpEQ32Fx4"); return; case Iop_CmpLT32Fx4: vex_printf("CmpLT32Fx4"); return; case Iop_CmpLE32Fx4: vex_printf("CmpLE32Fx4"); return; @@ -1113,6 +1116,7 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_Div32Fx4: case Iop_Div32F0x4: case Iop_Max32Fx4: case Iop_Max32F0x4: case Iop_Min32Fx4: case Iop_Min32F0x4: + case Iop_Mul32Fx4: case Iop_Mul32F0x4: case Iop_And128: case Iop_Or128: case Iop_Xor128: BINARY(Ity_V128, Ity_V128,Ity_V128);