From: Julian Seward Date: Sun, 12 Dec 2004 16:46:47 +0000 (+0000) Subject: x86 guest/host: fix enough 128-bit vector stuff that memcheck works for X-Git-Tag: svn/VALGRIND_3_0_1^2~686 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b99fb8b8794aaf568a55151c7c3199f446c1d9d;p=thirdparty%2Fvalgrind.git x86 guest/host: fix enough 128-bit vector stuff that memcheck works for SSE2. Added a new Iop_Not128 bit primop and generate at least tolerable SSE code for it. git-svn-id: svn://svn.valgrind.org/vex/trunk@648 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 7a337517ba..a67c8d3355 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -6283,9 +6283,7 @@ static UInt dis_SSE_E_to_G_all_wrk ( IRTemp addr; UChar rm = getIByte(delta); IRExpr* gpart - = invertG ? binop( Iop_Xor128, - getXMMReg(gregOfRM(rm)), - mkV128(0xFFFF) ) + = invertG ? unop(Iop_Not128, getXMMReg(gregOfRM(rm))) : getXMMReg(gregOfRM(rm)); if (epartIsReg(rm)) { putXMMReg( gregOfRM(rm), @@ -6638,14 +6636,20 @@ static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta, nameXMMReg(gregOfRM(rm)) ); } - if (needNot && all_lanes) - mask = 0xFFFF; - if (needNot && !all_lanes) + if (needNot && all_lanes) { + putXMMReg( gregOfRM(rm), + unop(Iop_Not128, mkexpr(plain)) ); + } + else + if (needNot && !all_lanes) { mask = sz==4 ? 0x000F : 0x00FF; + putXMMReg( gregOfRM(rm), + binop(Iop_Xor128, mkexpr(plain), mkV128(mask)) ); + } + else { + putXMMReg( gregOfRM(rm), mkexpr(plain) ); + } - putXMMReg( gregOfRM(rm), - needNot ? binop(Iop_Xor128, mkexpr(plain), mkV128(mask)) - : mkexpr(plain) ); return delta; } diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index cdc6287b87..f7445c3560 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -698,6 +698,25 @@ void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode ) } +/* Generate !src into a new vector register, and be sure that the code + is SSE1 compatible. Amazing that Intel doesn't offer a less crappy + way to do this. +*/ +static HReg do_sse_Not128 ( ISelEnv* env, HReg src ) +{ + HReg dst = newVRegV(env); + /* Set dst to zero. Not strictly necessary, but the idea of doing + a FP comparison on whatever junk happens to be floating around + in it is just too scary. */ + addInstr(env, X86Instr_SseReRg(Xsse_XOR, dst, dst)); + /* And now make it all 1s ... */ + addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, dst, dst)); + /* Finally, xor 'src' into it. */ + addInstr(env, X86Instr_SseReRg(Xsse_XOR, src, dst)); + return dst; +} + + /*---------------------------------------------------------*/ /*--- ISEL: Integer expressions (32/16/8 bit) ---*/ /*---------------------------------------------------------*/ @@ -2461,8 +2480,13 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) if (e->tag == Iex_Unop) { switch (e->Iex.Unop.op) { + case Iop_Not128: { + HReg arg = iselVecExpr(env, e->Iex.Unop.arg); + return do_sse_Not128(env, arg); + } + case Iop_CmpNEZ64x2: { - /* only needed for sse2, so can use sse2 code */ + /* We can use SSE2 instructions for this. */ /* Ideally, we want to do a 64Ix2 comparison against zero of the operand. Problem is no such insn exists. Solution therefore is to do a 32Ix4 comparison instead, and bitwise- @@ -2477,29 +2501,20 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) literal value is 0xB1, that is, (2 << 6) | (3 << 4) | (0 << 2) | (1 << 0) */ - X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); HReg arg = iselVecExpr(env, e->Iex.Unop.arg); HReg tmp = newVRegV(env); HReg dst = newVRegV(env); - HReg ones = newVRegV(env); - HReg r32 = newVRegI(env); - addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0xFFFFFFFF), r32)); - addInstr(env, X86Instr_Push(X86RMI_Reg(r32))); - addInstr(env, X86Instr_Push(X86RMI_Reg(r32))); - addInstr(env, X86Instr_Push(X86RMI_Reg(r32))); - addInstr(env, X86Instr_Push(X86RMI_Reg(r32))); - addInstr(env, X86Instr_SseLdSt(True/*load*/, ones, esp0)); - add_to_esp(env, 16); addInstr(env, X86Instr_SseReRg(Xsse_XOR, tmp, tmp)); addInstr(env, X86Instr_SseReRg(Xsse_CMPEQ32, arg, tmp)); - addInstr(env, X86Instr_SseReRg(Xsse_XOR, ones, tmp)); + tmp = do_sse_Not128(env, tmp); addInstr(env, X86Instr_SseShuf(0xB1, tmp, dst)); addInstr(env, X86Instr_SseReRg(Xsse_OR, tmp, dst)); return dst; } case Iop_CmpNEZ32x4: { - /* sigh, we have to generate crappy code for SSE1 */ + /* Sigh, we have to generate lousy code since this has to + work on SSE1 hosts */ /* basically, the idea is: for each lane: movl lane, %r ; negl %r (now CF = lane==0 ? 0 : 1) sbbl %r, %r (now %r = 1Sto32(CF)) @@ -2525,6 +2540,31 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) return dst; } + case Iop_CmpNEZ8x16: + case Iop_CmpNEZ16x8: { + /* We can use SSE2 instructions for this. */ + HReg arg; + HReg vec0 = newVRegV(env); + HReg vec1 = newVRegV(env); + HReg dst = newVRegV(env); + X86SseOp cmpOp + = e->Iex.Unop.op==Iop_CmpNEZ16x8 ? Xsse_CMPEQ16 + : Xsse_CMPEQ8; + addInstr(env, X86Instr_SseReRg(Xsse_XOR, vec0, vec0)); + addInstr(env, mk_vMOVsd_RR(vec0, vec1)); + addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, vec1, vec1)); + /* defer arg computation to here so as to give CMPEQF as long + as possible to complete */ + arg = iselVecExpr(env, e->Iex.Unop.arg); + /* vec0 is all 0s; vec1 is all 1s */ + addInstr(env, mk_vMOVsd_RR(arg, dst)); + /* 16x8 or 8x16 comparison == */ + addInstr(env, X86Instr_SseReRg(cmpOp, vec0, dst)); + /* invert result */ + addInstr(env, X86Instr_SseReRg(Xsse_XOR, vec1, dst)); + return dst; + } + case Iop_Recip32Fx4: op = Xsse_RCPF; goto do_32Fx4_unary; case Iop_RSqrt32Fx4: op = Xsse_RSQRTF; goto do_32Fx4_unary; case Iop_Sqrt32Fx4: op = Xsse_SQRTF; goto do_32Fx4_unary; diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 52482043cf..a71a27cd51 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -297,9 +297,12 @@ void ppIROp ( IROp op ) case Iop_128to32: vex_printf("128to32"); return; case Iop_Set128lo32: vex_printf("Set128lo32"); return; + case Iop_Not128: vex_printf("Not128"); return; case Iop_And128: vex_printf("And128"); return; case Iop_Or128: vex_printf("Or128"); return; case Iop_Xor128: vex_printf("Xor128"); return; + case Iop_CmpNEZ8x16: vex_printf("CmpNEZ8x16"); return; + case Iop_CmpNEZ16x8: vex_printf("CmpNEZ16x8"); return; case Iop_CmpNEZ32x4: vex_printf("CmpNEZ32x4"); return; case Iop_CmpNEZ64x2: vex_printf("CmpNEZ64x2"); return; @@ -1274,12 +1277,14 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_InterleaveLO32x4: case Iop_InterleaveLO64x2: BINARY(Ity_V128, Ity_V128,Ity_V128); + case Iop_Not128: case Iop_Recip32Fx4: case Iop_Recip32F0x4: case Iop_Recip64Fx2: case Iop_Recip64F0x2: case Iop_RSqrt32Fx4: case Iop_RSqrt32F0x4: case Iop_RSqrt64Fx2: case Iop_RSqrt64F0x2: case Iop_Sqrt32Fx4: case Iop_Sqrt32F0x4: case Iop_Sqrt64Fx2: case Iop_Sqrt64F0x2: + case Iop_CmpNEZ8x16: case Iop_CmpNEZ16x8: case Iop_CmpNEZ32x4: case Iop_CmpNEZ64x2: UNARY(Ity_V128, Ity_V128); diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 11d1699ac9..8d1f8b2cce 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -393,10 +393,11 @@ typedef /* ------------------ 128-bit SIMD Integer. ------------------ */ /* BITWISE OPS */ + Iop_Not128, Iop_And128, Iop_Or128, Iop_Xor128, - /* MISC (32x4 integer cmp != 0) */ - Iop_CmpNEZ32x4, Iop_CmpNEZ64x2, + /* MISC (vector integer cmp != 0) */ + Iop_CmpNEZ8x16, Iop_CmpNEZ16x8, Iop_CmpNEZ32x4, Iop_CmpNEZ64x2, /* ADDITION (normal / unsigned sat / signed sat) */ Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_Add64x2,