From: Julian Seward Date: Sat, 14 Jun 2003 13:22:36 +0000 (+0000) Subject: More SSE instructions. X-Git-Tag: svn/VALGRIND_2_0_0~94 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=502321e2654d4e57edeb3cc30fe556eeb691fbe1;p=thirdparty%2Fvalgrind.git More SSE instructions. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1690 --- diff --git a/coregrind/vg_from_ucode.c b/coregrind/vg_from_ucode.c index 2c60eb74b0..af63fa22f4 100644 --- a/coregrind/vg_from_ucode.c +++ b/coregrind/vg_from_ucode.c @@ -1580,6 +1580,27 @@ static void emit_SSE4 ( FlagSet uses_sflags, (UInt)third_byte, (UInt)fourth_byte ); } +static void emit_SSE5 ( FlagSet uses_sflags, + FlagSet sets_sflags, + UChar first_byte, + UChar second_byte, + UChar third_byte, + UChar fourth_byte, + UChar fifth_byte ) +{ + VG_(new_emit)(True, uses_sflags, sets_sflags); + VG_(emitB) ( first_byte ); + VG_(emitB) ( second_byte ); + VG_(emitB) ( third_byte ); + VG_(emitB) ( fourth_byte ); + VG_(emitB) ( fifth_byte ); + if (dis) + VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x:0x%x:0x%x\n", + (UInt)first_byte, (UInt)second_byte, + (UInt)third_byte, (UInt)fourth_byte, + (UInt)fifth_byte ); +} + static void emit_SSE3 ( FlagSet uses_sflags, FlagSet sets_sflags, UChar first_byte, @@ -3872,6 +3893,24 @@ static void emitUInstr ( UCodeBlock* cb, Int i, u->val3 ); break; + case SSE5: + vg_assert(u->size == 0); + vg_assert(u->tag1 == Lit16); + vg_assert(u->tag2 == Lit16); + vg_assert(u->tag3 == Lit16); + vg_assert(!anyFlagUse(u)); + if (!(*sselive)) { + emit_get_sse_state(); + *sselive = True; + } + emit_SSE5 ( u->flags_r, u->flags_w, + (u->val1 >> 8) & 0xFF, + u->val1 & 0xFF, + (u->val2 >> 8) & 0xFF, + u->val2 & 0xFF, + u->val3 & 0xFF ); + break; + case SSE4: vg_assert(u->size == 0); vg_assert(u->tag1 == Lit16); diff --git a/coregrind/vg_to_ucode.c b/coregrind/vg_to_ucode.c index c0f11fe878..a87bd65e52 100644 --- a/coregrind/vg_to_ucode.c +++ b/coregrind/vg_to_ucode.c @@ -3394,6 +3394,45 @@ Addr dis_SSE2_reg_or_mem_Imm8 ( UCodeBlock* cb, } +/* Simple SSE operations, either + op (src)xmmreg, (dst)xmmreg + or + op (src)address, (dst)xmmreg + 3 opcode bytes and an 8-bit immediate after the amode. + Supplied eip points to the first address mode byte. +*/ +static +Addr dis_SSE3_reg_or_mem_Imm8 ( UCodeBlock* cb, + UChar sorb, + Addr eip, + Int sz, + Char* name, + UChar opc1, + UChar opc2, + UChar opc3 ) +{ + UChar modrm = getUChar(eip); + UChar imm8; + if (epartIsReg(modrm)) { + /* Completely internal SSE insn. */ + eip++; + imm8 = getUChar(eip); + uInstr3(cb, SSE5, 0, /* ignore sz for internal ops */ + Lit16, (((UShort)opc1) << 8) | (UShort)opc2, + Lit16, (((UShort)opc3) << 8) | (UShort)modrm, + Lit16, (UShort)imm8 ); + if (dis) + VG_(printf)("%s %s, %s\n", name, + nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm)) ); + eip++; + } else { + VG_(core_panic)("dis_SSE3_reg_or_mem_Imm8: mem"); + } + return eip; +} + + /* Disassemble an SSE insn which is either a simple reg-reg move or a move between registers and memory. Supplied eip points to the first address mode byte. @@ -3734,6 +3773,15 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) goto decode_success; } + /* PSHUFD */ + if (sz == 2 + && insn[0] == 0x0F && insn[1] == 0x70) { + eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, + "pshufd", + 0x66, insn[0], insn[1] ); + goto decode_success; + } + /* SHUFPS */ if (insn[0] == 0x0F && insn[1] == 0xC6) { vg_assert(sz == 4); @@ -3766,7 +3814,6 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) goto decode_success; } -#if 0 /* SUBSD */ if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) { vg_assert(sz == 4); @@ -3774,7 +3821,6 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) insn[0], insn[1], insn[2] ); goto decode_success; } -#endif /* ADDSD */ if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) { @@ -3800,11 +3846,29 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) goto decode_success; } + /* PAND (src)xmmreg-or-mem, (dst)xmmreg */ + if (sz == 2 + && insn[0] == 0x0F && insn[1] == 0xDB) { + eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand", + 0x66, insn[0], insn[1] ); + goto decode_success; + } + + /* POR (src)xmmreg-or-mem, (dst)xmmreg */ + if (sz == 2 + && insn[0] == 0x0F && insn[1] == 0xEB) { + eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por", + 0x66, insn[0], insn[1] ); + goto decode_success; + } + /* PUNPCKLgg (src)xmmreg-or-mem, (dst)xmmreg */ /* 60 is BW, 61 is WD, 62 is DQ */ if (sz == 2 - && insn[0] == 0x0F && insn[1] == 0x62) { - eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "punpckldq", + && insn[0] == 0x0F + && (insn[1] == 0x61 || insn[1] == 0x62)) { + eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, + "punpckl{bw,wd,dq}", 0x66, insn[0], insn[1] ); goto decode_success; } @@ -3863,10 +3927,25 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) goto decode_success; } - /* MOVAPS (28,29) -- aligned load/store of XMM reg, or x-x reg + /* I don't understand how MOVAPD differs from MOVAPS. */ + /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg move */ - /* MOVUPS (10,11) -- unaligned load/store of XMM reg, or x-x reg + if (sz == 2 + && insn[0] == 0x0F && insn[1] == 0x28) { + UChar* name = "movapd"; + //(insn[1] == 0x10 || insn[1] == 0x11) + // ? "movups" : "movaps"; + Bool store = False; //insn[1] == 0x29 || insn[1] == 11; + eip = dis_SSE3_load_store_or_mov + ( cb, sorb, eip+2, 16, store, name, + 0x66, insn[0], insn[1] ); + goto decode_success; + } + + /* MOVAPS (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg move */ + /* MOVUPS (10,11) -- unaligned load/store of xmm reg, or xmm-xmm + reg move */ if (insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x29 || insn[1] == 0x10 @@ -5412,35 +5491,55 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) break; case 0x71: case 0x72: case 0x73: - /* PSLL/PSRA/PSRL mmxreg by imm8 */ + /* (sz==4): PSLL/PSRA/PSRL mmxreg by imm8 */ + /* (sz==2): PSLL/PSRA/PSRL xmmreg by imm8 */ { - UChar byte1, byte2, byte3, subopc, mmxreg; - vg_assert(sz == 4); - byte1 = opc; - byte2 = getUChar(eip); eip++; - byte3 = getUChar(eip); eip++; - mmxreg = byte2 & 7; + UChar byte1, byte2, byte3, subopc, mmreg; + vg_assert(sz == 4 || sz == 2); + byte1 = opc; /* 0x71/72/73 */ + byte2 = getUChar(eip); eip++; /* amode / sub-opcode */ + byte3 = getUChar(eip); eip++; /* imm8 */ + mmreg = byte2 & 7; subopc = (byte2 >> 3) & 7; if (subopc == 2 || subopc == 6 || subopc == 4) { /* 2 == 010 == SRL, 6 == 110 == SLL, 4 == 100 == SRA */ /* ok */ } else { - eip -= 2; + eip -= (sz==2 ? 3 : 2); goto decode_failure; } - uInstr2(cb, MMX3, 0, - Lit16, (((UShort)byte1) << 8) | ((UShort)byte2), - Lit16, ((UShort)byte3) ); - if (dis) - VG_(printf)("ps%s%s $%d, %s\n", - (subopc == 2 ? "rl" - : subopc == 6 ? "ll" - : subopc == 4 ? "ra" - : "??"), - nameMMXGran(opc & 3), - (Int)byte3, - nameMMXReg(mmxreg) ); - } + if (sz == 4) { + /* The leading 0x0F is implied for MMX*, so we don't + include it. */ + uInstr2(cb, MMX3, 0, + Lit16, (((UShort)byte1) << 8) | ((UShort)byte2), + Lit16, ((UShort)byte3) ); + if (dis) + VG_(printf)("ps%s%s $%d, %s\n", + (subopc == 2 ? "rl" + : subopc == 6 ? "ll" + : subopc == 4 ? "ra" + : "??"), + nameMMXGran(opc & 3), + (Int)byte3, + nameMMXReg(mmreg) ); + } else { + /* Whereas we have to include it for SSE. */ + uInstr3(cb, SSE5, 0, + Lit16, (((UShort)0x66) << 8) | ((UShort)0x0F), + Lit16, (((UShort)byte1) << 8) | ((UShort)byte2), + Lit16, ((UShort)byte3) ); + if (dis) + VG_(printf)("ps%s%s $%d, %s\n", + (subopc == 2 ? "rl" + : subopc == 6 ? "ll" + : subopc == 4 ? "ra" + : "??"), + nameMMXGran(opc & 3), + (Int)byte3, + nameXMMReg(mmreg) ); + } + } break; case 0x77: /* EMMS */ diff --git a/coregrind/vg_translate.c b/coregrind/vg_translate.c index 6de24737c7..f07bb0ee9a 100644 --- a/coregrind/vg_translate.c +++ b/coregrind/vg_translate.c @@ -569,6 +569,7 @@ Bool VG_(saneUInstr) ( Bool beforeRA, Bool beforeLiveness, UInstr* u ) case SSE3g1_RegRd: return LIT8 && SZ2 && CC0 && Ls1 && Ls2 && TR3 && XOTHER; case SSE3: return LIT0 && SZ0 && CC0 && Ls1 && Ls2 && N3 && XOTHER; case SSE4: return LIT0 && SZ0 && CCf && Ls1 && Ls2 && N3 && XOTHER; + case SSE5: return LIT0 && SZ0 && CC0 && Ls1 && Ls2 && Ls3 && XOTHER; default: if (VG_(needs).extended_UCode) return SK_(sane_XUInstr)(beforeRA, beforeLiveness, u); @@ -889,6 +890,7 @@ Char* VG_(name_UOpcode) ( Bool upper, Opcode opc ) case SSE3g1_RegRd: return "SSE3g1_RRd"; case SSE3: return "SSE3"; case SSE4: return "SSE4"; + case SSE5: return "SSE5"; case SSE3a_MemWr: return "SSE3a_MWr"; case SSE3a_MemRd: return "SSE3a_MRd"; default: @@ -1085,6 +1087,13 @@ void pp_UInstrWorker ( Int instrNo, UInstr* u, Bool ppRegsLiveness ) (u->val2 >> 8) & 0xFF, u->val2 & 0xFF ); break; + case SSE5: + VG_(printf)("0x%x:0x%x:0x%x:0x%x:0x%x", + (u->val1 >> 8) & 0xFF, u->val1 & 0xFF, + (u->val2 >> 8) & 0xFF, u->val2 & 0xFF, + u->val3 & 0xFF ); + break; + case GET: case PUT: case MOV: case LOAD: case STORE: case CMOV: case GETSEG: case PUTSEG: VG_(pp_UOperand)(u, 1, u->size, u->opcode==LOAD); @@ -1243,7 +1252,7 @@ Int VG_(get_reg_usage) ( UInstr* u, Tag tag, Int* regs, Bool* isWrites ) case MMX2_RegRd: RD(2); break; case MMX2_RegWr: WR(2); break; - case SSE4: case SSE3: + case SSE4: case SSE3: case SSE5: case MMX1: case MMX2: case MMX3: case NOP: case FPU: case INCEIP: case CALLM_S: case CALLM_E: case CLEAR: case CALLM: case LOCK: break; @@ -1399,7 +1408,7 @@ Int maybe_uinstrReadsArchReg ( UInstr* u ) case SSE3a_MemWr: case SSE3a_MemRd: case SSE3g_RegRd: case SSE3g_RegWr: case SSE3g1_RegWr: case SSE3g1_RegRd: - case SSE4: case SSE3: + case SSE4: case SSE3: case SSE5: case WIDEN: /* GETSEG and USESEG are to do with ArchRegS, not ArchReg */ case GETSEG: case PUTSEG: @@ -2289,7 +2298,7 @@ void VG_(translate) ( /*IN*/ ThreadState* tst, UChar* final_code; UCodeBlock* cb; Bool notrace_until_done; - UInt notrace_until_limit = 1900; + UInt notrace_until_limit = 18000; VGP_PUSHCC(VgpTranslate); debugging_translation