- Implement bt/bts/btc/btr, using the same hack as UCode (forcing
everything into memory).
- Fill in a few other minor integer instructions.
git-svn-id: svn://svn.valgrind.org/vex/trunk@235 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest-x86/toIR.c b/priv/guest-x86/toIR.c
index 4683f5c..ecb7e2b 100644
--- a/priv/guest-x86/toIR.c
+++ b/priv/guest-x86/toIR.c
@@ -3931,154 +3931,148 @@
}
-//-- /* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
-//-- required. */
-//--
-//-- typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
-//--
-//-- static Char* nameBtOp ( BtOp op )
-//-- {
-//-- switch (op) {
-//-- case BtOpNone: return "";
-//-- case BtOpSet: return "s";
-//-- case BtOpReset: return "r";
-//-- case BtOpComp: return "c";
-//-- default: VG_(core_panic)("nameBtOp");
-//-- }
-//-- }
-//--
-//--
-//-- static
-//-- Addr dis_bt_G_E ( UCodeBlock* cb,
-//-- UChar sorb,
-//-- Int sz, Addr eip, BtOp op )
-//-- {
-//-- UInt pair;
-//-- Char dis_buf[50];
-//-- UChar modrm;
-//--
-//-- Int t_addr, t_bitno, t_mask, t_fetched, t_esp, temp, lit;
-//--
-//-- vg_assert(sz == 2 || sz == 4);
-//--
-//-- t_addr = t_bitno = t_mask
-//-- = t_fetched = t_esp = temp = INVALID_TEMPREG;
-//--
-//-- t_fetched = newTemp(cb);
-//-- t_bitno = newTemp(cb);
-//-- temp = newTemp(cb);
-//-- lit = newTemp(cb);
-//--
-//-- modrm = getUChar(eip);
-//--
-//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t_bitno);
-//--
-//-- if (sz == 2) {
-//-- uInstr1(cb, WIDEN, 4, TempReg, t_bitno);
-//-- uWiden(cb, 2, False);
-//-- }
-//--
-//-- if (epartIsReg(modrm)) {
-//-- eip++;
-//-- /* Get it onto the client's stack. */
-//-- t_esp = newTemp(cb);
-//-- t_addr = newTemp(cb);
-//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t_esp);
-//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t_esp);
-//-- uLiteral(cb, sz);
-//-- uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
-//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, temp);
-//-- uInstr2(cb, STORE, sz, TempReg, temp, TempReg, t_esp);
-//-- /* Make t_addr point at it. */
-//-- uInstr2(cb, MOV, 4, TempReg, t_esp, TempReg, t_addr);
-//-- /* Mask out upper bits of the shift amount, since we're doing a
-//-- reg. */
-//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
-//-- uLiteral(cb, sz == 4 ? 31 : 15);
-//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
-//-- } else {
-//-- pair = disAMode ( cb, sorb, eip, dis_buf );
-//-- t_addr = LOW24(pair);
-//-- eip += HI8(pair);
-//-- }
-//--
-//-- /* At this point: t_addr points to the address being operated on. If
-//-- it was a reg, we will have pushed it onto the client's stack.
-//-- t_bitno is the bit number, suitable masked in the case of a reg. */
-//--
-//-- /* Now the main sequence. */
-//--
-//-- uInstr2(cb, MOV, 4, TempReg, t_bitno, TempReg, temp);
-//-- uInstr2(cb, SAR, 4, Literal, 0, TempReg, temp);
-//-- uLiteral(cb, 3);
-//-- uInstr2(cb, ADD, 4, TempReg, temp, TempReg, t_addr);
-//-- /* t_addr now holds effective address */
-//--
-//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
-//-- uLiteral(cb, 7);
-//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
-//-- /* t_bitno contains offset of bit within byte */
-//--
-//-- if (op != BtOpNone) {
-//-- t_mask = newTemp(cb);
-//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_mask);
-//-- uLiteral(cb, 1);
-//-- uInstr2(cb, SHL, 4, TempReg, t_bitno, TempReg, t_mask);
-//-- }
-//-- /* t_mask is now a suitable byte mask */
-//--
-//-- uInstr2(cb, LOAD, 1, TempReg, t_addr, TempReg, t_fetched);
-//-- if (op != BtOpNone) {
-//-- uInstr2(cb, MOV, 4, TempReg, t_fetched, TempReg, temp);
-//-- switch (op) {
-//-- case BtOpSet:
-//-- uInstr2(cb, OR, 4, TempReg, t_mask, TempReg, temp);
-//-- break;
-//-- case BtOpComp:
-//-- uInstr2(cb, XOR, 4, TempReg, t_mask, TempReg, temp);
-//-- break;
-//-- case BtOpReset:
-//-- uInstr1(cb, NOT, 4, TempReg, t_mask);
-//-- uInstr2(cb, AND, 4, TempReg, t_mask, TempReg, temp);
-//-- break;
-//-- default:
-//-- VG_(core_panic)("dis_bt_G_E");
-//-- }
-//-- uInstr2(cb, STORE, 1, TempReg, temp, TempReg, t_addr);
-//-- }
-//--
-//-- /* Side effect done; now get selected bit into Carry flag */
-//--
-//-- uInstr2(cb, SHR, 4, TempReg, t_bitno, TempReg, t_fetched);
-//-- /* at bit 0 of fetched */
-//--
-//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
-//-- uLiteral(cb, 1);
-//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_fetched);
-//-- /* t_fetched is now 1 or 0 */
-//--
-//-- /* NEG is a handy way to convert zero/nonzero into the carry
-//-- flag. */
-//-- uInstr1(cb, NEG, 4, TempReg, t_fetched);
-//-- setFlagsFromUOpcode(cb, NEG);
-//-- /* t_fetched is now in carry flag */
-//--
-//-- /* Move reg operand from stack back to reg */
-//-- if (epartIsReg(modrm)) {
-//-- /* t_esp still points at it. */
-//-- uInstr2(cb, LOAD, sz, TempReg, t_esp, TempReg, temp);
-//-- uInstr2(cb, PUT, sz, TempReg, temp, ArchReg, eregOfRM(modrm));
-//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t_esp);
-//-- uLiteral(cb, sz);
-//-- uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
-//-- }
-//--
-//-- DIP("bt%s%c %s, %s\n",
-//-- nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
-//-- ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
-//--
-//-- return eip;
-//-- }
+/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
+ required. */
+
+typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
+
+static Char* nameBtOp ( BtOp op )
+{
+ switch (op) {
+ case BtOpNone: return "";
+ case BtOpSet: return "s";
+ case BtOpReset: return "r";
+ case BtOpComp: return "c";
+ default: vpanic("nameBtOp(x86)");
+ }
+}
+
+
+static
+UInt dis_bt_G_E ( UChar sorb, Int sz, UInt delta, BtOp op )
+{
+ Char dis_buf[50];
+ UChar modrm;
+ Int len;
+ IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
+ t_addr1, t_esp, t_mask;
+
+ vassert(sz == 2 || sz == 4);
+
+ t_fetched = t_bitno0 = t_bitno1 = t_bitno2
+ = t_addr0 = t_addr1 = t_esp = t_mask = INVALID_IRTEMP;
+
+ t_fetched = newTemp(Ity_I8);
+ t_bitno0 = newTemp(Ity_I32);
+ t_bitno1 = newTemp(Ity_I32);
+ t_bitno2 = newTemp(Ity_I8);
+ t_addr1 = newTemp(Ity_I32);
+ modrm = getIByte(delta);
+
+ assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
+
+ if (epartIsReg(modrm)) {
+ vassert(0); /* awaiting test case */
+ delta++;
+ /* Get it onto the client's stack. */
+ t_esp = newTemp(Ity_I32);
+ t_addr0 = newTemp(Ity_I32);
+
+ assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
+ putIReg(4, R_ESP, mkexpr(t_esp));
+
+ storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
+
+ /* Make t_addr0 point at it. */
+ assign( t_addr0, mkexpr(t_esp) );
+
+ /* Mask out upper bits of the shift amount, since we're doing a
+ reg. */
+ assign( t_bitno1, binop(Iop_And32,
+ mkexpr(t_bitno0),
+ mkU32(sz == 4 ? 31 : 15)) );
+
+ } else {
+ t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
+ delta += len;
+ assign( t_bitno1, mkexpr(t_bitno0) );
+ }
+
+ /* At this point: t_addr0 is the address being operated on. If it
+ was a reg, we will have pushed it onto the client's stack.
+ t_bitno1 is the bit number, suitably masked in the case of a
+ reg. */
+
+ /* Now the main sequence. */
+ assign( t_addr1,
+ binop(Iop_Add32,
+ mkexpr(t_addr0),
+ binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
+
+ /* t_addr1 now holds effective address */
+
+ assign( t_bitno2,
+ unop(Iop_32to8,
+ binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
+
+ /* t_bitno2 contains offset of bit within byte */
+
+ if (op != BtOpNone) {
+ t_mask = newTemp(Ity_I8);
+ assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
+ }
+ /* t_mask is now a suitable byte mask */
+
+ assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
+
+ if (op != BtOpNone) {
+ switch (op) {
+ case BtOpSet:
+ storeLE( mkexpr(t_addr1),
+ binop(Iop_Or8, mkexpr(t_fetched),
+ mkexpr(t_mask)) );
+ break;
+ case BtOpComp:
+ storeLE( mkexpr(t_addr1),
+ binop(Iop_Xor8, mkexpr(t_fetched),
+ mkexpr(t_mask)) );
+ break;
+ case BtOpReset:
+ storeLE( mkexpr(t_addr1),
+ binop(Iop_And8, mkexpr(t_fetched),
+ unop(Iop_Not8, mkexpr(t_mask))) );
+ break;
+ default:
+ vpanic("dis_bt_G_E(x86)");
+ }
+ }
+
+ /* Side effect done; now get selected bit into Carry flag */
+ /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
+ stmt( IRStmt_Put(
+ OFFB_CC_SRC,
+ binop(Iop_And32,
+ binop(Iop_Shr32,
+ unop(Iop_8Uto32, mkexpr(t_fetched)),
+ mkexpr(t_bitno2)),
+ mkU32(1)))
+ );
+
+ /* Move reg operand from stack back to reg */
+ if (epartIsReg(modrm)) {
+ /* t_esp still points at it. */
+ putIReg(sz, eregOfRM(modrm), loadLE(sz, mkexpr(t_esp)) );
+ putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
+ }
+
+ DIP("bt%s%c %s, %s\n",
+ nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
+ ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
+
+ return delta;
+}
@@ -6694,26 +6688,23 @@
//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
//-- break;
-//--
-//-- /* ------------------------ CWD/CDQ -------------------- */
-//--
-//-- case 0x98: /* CBW */
-//-- t1 = newTemp(cb);
-//-- if (sz == 4) {
-//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
-//-- uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
-//-- uWiden(cb, 2, True);
-//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
-//-- DIP("cwd\n");
-//-- } else {
+
+ /* ------------------------ CWD/CDQ -------------------- */
+
+ case 0x98: /* CBW */
+ if (sz == 4) {
+ putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
+ DIP("cwde\n");
+ } else {
+ vassert(0);
//-- vg_assert(sz == 2);
//-- uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
//-- uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
//-- uWiden(cb, 1, True);
//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
//-- DIP("cbw\n");
-//-- }
-//-- break;
+ }
+ break;
case 0x99: /* CWD/CDQ */
ty = szToITy(sz);
@@ -7065,9 +7056,9 @@
delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
break;
-//-- case 0x34: /* XOR Ib, AL */
-//-- delta = dis_op_imm_A( 1, XOR, True, delta, "xor" );
-//-- break;
+ case 0x34: /* XOR Ib, AL */
+ delta = dis_op_imm_A( 1, Iop_Xor8, True, delta, "xor" );
+ break;
case 0x35: /* XOR Iv, eAX */
delta = dis_op_imm_A( sz, Iop_Xor8, True, delta, "xor" );
break;
@@ -7086,8 +7077,8 @@
delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
break;
-//-- /* ------------------------ opl Ev, Gv ----------------- */
-//--
+ /* ------------------------ opl Ev, Gv ----------------- */
+
//-- case 0x02: /* ADD Eb,Gb */
//-- delta = dis_op2_E_G ( cb, sorb, False, ADD, True, 1, delta, "add" );
//-- break;
@@ -7116,9 +7107,9 @@
delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
break;
-//-- case 0x22: /* AND Eb,Gb */
-//-- delta = dis_op2_E_G ( sorb, False, AND, True, 1, delta, "and" );
-//-- break;
+ case 0x22: /* AND Eb,Gb */
+ delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
+ break;
case 0x23: /* AND Ev,Gv */
delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
break;
@@ -7487,7 +7478,7 @@
//--
//-- case 0xAA: /* STOS, no REP prefix */
//-- case 0xAB:
-//-- dis_string_op( cb, dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
+//-- dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
//-- break;
//--
//-- case 0xAC: /* LODS, no REP prefix */
@@ -7893,7 +7884,7 @@
//-- case 0xCC:
//-- case 0xCD:
case 0xCE:
-//-- case 0xCF: /* BSWAP %edi */
+ case 0xCF: /* BSWAP %edi */
/* AFAICS from the Intel docs, this only exists at size 4. */
vassert(sz == 4);
t1 = newTemp(Ity_I32);
@@ -7922,17 +7913,17 @@
DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
break;
-//-- /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
-//--
-//-- case 0xA3: /* BT Gv,Ev */
-//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpNone );
-//-- break;
+ /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
+
+ case 0xA3: /* BT Gv,Ev */
+ delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
+ break;
//-- case 0xB3: /* BTR Gv,Ev */
//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpReset );
//-- break;
-//-- case 0xAB: /* BTS Gv,Ev */
-//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpSet );
-//-- break;
+ case 0xAB: /* BTS Gv,Ev */
+ delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
+ break;
//-- case 0xBB: /* BTC Gv,Ev */
//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpComp );
//-- break;