|
From: <sv...@va...> - 2010-08-09 08:57:38
|
Author: sewardj
Date: 2010-08-09 09:57:27 +0100 (Mon, 09 Aug 2010)
New Revision: 2006
Log:
- add infrastructure to deal with CPSR.Q (sticky saturation flag)
- add new Thumb insns needed for Ubuntu 10.04
Modified:
branches/THUMB/priv/guest_arm_defs.h
branches/THUMB/priv/guest_arm_helpers.c
branches/THUMB/priv/guest_arm_toIR.c
branches/THUMB/pub/libvex_guest_arm.h
Modified: branches/THUMB/priv/guest_arm_defs.h
===================================================================
--- branches/THUMB/priv/guest_arm_defs.h 2010-08-08 11:47:23 UTC (rev 2005)
+++ branches/THUMB/priv/guest_arm_defs.h 2010-08-09 08:57:27 UTC (rev 2006)
@@ -118,14 +118,16 @@
#define ARMG_CC_SHIFT_Z 30
#define ARMG_CC_SHIFT_C 29
#define ARMG_CC_SHIFT_V 28
+#define ARMG_CC_SHIFT_Q 27
#define ARMG_CC_MASK_N (1 << ARMG_CC_SHIFT_N)
#define ARMG_CC_MASK_Z (1 << ARMG_CC_SHIFT_Z)
#define ARMG_CC_MASK_C (1 << ARMG_CC_SHIFT_C)
#define ARMG_CC_MASK_V (1 << ARMG_CC_SHIFT_V)
+#define ARMG_CC_MASK_Q (1 << ARMG_CC_SHIFT_Q)
/* Flag thunk descriptors. A four-word thunk is used to record
- details of the most recent flag-setting operation, so the flags can
+ details of the most recent flag-setting operation, so NZCV can
be computed later if needed.
The four words are:
Modified: branches/THUMB/priv/guest_arm_helpers.c
===================================================================
--- branches/THUMB/priv/guest_arm_helpers.c 2010-08-08 11:47:23 UTC (rev 2005)
+++ branches/THUMB/priv/guest_arm_helpers.c 2010-08-09 08:57:27 UTC (rev 2006)
@@ -525,6 +525,7 @@
vex_state->guest_CC_DEP1 = 0;
vex_state->guest_CC_DEP2 = 0;
vex_state->guest_CC_NDEP = 0;
+ vex_state->guest_QFLAG32 = 0;
vex_state->guest_EMWARN = 0;
vex_state->guest_TISTART = 0;
Modified: branches/THUMB/priv/guest_arm_toIR.c
===================================================================
--- branches/THUMB/priv/guest_arm_toIR.c 2010-08-08 11:47:23 UTC (rev 2005)
+++ branches/THUMB/priv/guest_arm_toIR.c 2010-08-09 08:57:27 UTC (rev 2006)
@@ -52,6 +52,8 @@
add specialisations for armg_calculate_flag_c and _v, as they
are moderately often needed in Thumb code.
+
+ Correctness: ITSTATE handling in Thumb SVCs is wrong.
*/
/* Limitations, etc
@@ -419,6 +421,7 @@
#define OFFB_FPSCR offsetof(VexGuestARMState,guest_FPSCR)
#define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
#define OFFB_ITSTATE offsetof(VexGuestARMState,guest_ITSTATE)
+#define OFFB_QFLAG32 offsetof(VexGuestARMState,guest_QFLAG32)
/* ---------------- Integer registers ---------------- */
@@ -839,7 +842,8 @@
IRTemp guardT /* :: Ity_I32, 0 or 1 */)
{
switch (gsoffset) {
- case OFFB_FPSCR: break;
+ case OFFB_FPSCR: break;
+ case OFFB_QFLAG32: break;
default: vassert(0); /* awaiting more cases */
}
vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
@@ -872,7 +876,27 @@
stmt( IRStmt_Put( OFFB_ITSTATE, mkexpr(t)) );
}
+static IRTemp get_QFLAG32 ( void )
+{
+ IRTemp t = newTemp(Ity_I32);
+ assign(t, IRExpr_Get( OFFB_QFLAG32, Ity_I32));
+ return t;
+}
+static void put_QFLAG32 ( IRTemp t, IRTemp condT )
+{
+ putMiscReg32( OFFB_QFLAG32, mkexpr(t), condT );
+}
+
+static void or_into_QFLAG32 ( IRTemp t, IRTemp condT )
+{
+ IRTemp old = get_QFLAG32();
+ IRTemp nyu = newTemp(Ity_I32);
+ assign(nyu, binop(Iop_Or32, mkexpr(old), mkexpr(t)) );
+ put_QFLAG32(nyu, condT);
+}
+
+
/* ---------------- FPSCR stuff ---------------- */
/* Generate IR to get hold of the rounding mode bits in FPSCR, and
@@ -10652,9 +10676,13 @@
imm = ROR32(imm, rot);
imm &= 0xFF000000;
imm &= (ARMG_CC_MASK_N | ARMG_CC_MASK_Z
- | ARMG_CC_MASK_V | ARMG_CC_MASK_C);
+ | ARMG_CC_MASK_V | ARMG_CC_MASK_C | ARMG_CC_MASK_Q);
assign( immT, mkU32(imm & 0xF0000000) );
setFlags_D1(ARMG_CC_OP_COPY, immT, condT);
+ // Set QFLAG32 to a zero or nonzero value, depending on #imm8.
+ IRTemp qnewT = newTemp(Ity_I32);
+ assign(qnewT, mkU32( imm & ARMG_CC_MASK_Q ));
+ put_QFLAG32(qnewT, condT);
DIP("msr%s cpsr_f, #0x%08x\n", nCC(INSN_COND), imm);
goto decode_success;
}
@@ -10668,10 +10696,15 @@
if (bitR == 0 && INSN(19,16) == BITS4(1,0,0,0)
&& INSN(11,4) == BITS8(0,0,0,0,0,0,0,0)
&& INSN(3,0) != 15) {
- UInt rM = INSN(3,0);
+ UInt rM = INSN(3,0);
+ IRTemp rMt = newTemp(Ity_I32);
+ assign(rMt, getIRegA(rM));
IRTemp immT = newTemp(Ity_I32);
- assign(immT, binop(Iop_And32, getIRegA(rM), mkU32(0xF0000000)) );
+ assign(immT, binop(Iop_And32, mkexpr(rMt), mkU32(0xF0000000)) );
setFlags_D1(ARMG_CC_OP_COPY, immT, condT);
+ IRTemp qnewT = newTemp(Ity_I32);
+ assign(qnewT, binop(Iop_And32, mkexpr(rMt), mkU32(ARMG_CC_MASK_Q)));
+ put_QFLAG32(qnewT, condT);
DIP("msr%s cpsr_f, r%u\n", nCC(INSN_COND), rM);
goto decode_success;
}
@@ -10685,9 +10718,23 @@
UInt bitR = (insn >> 22) & 1;
UInt rD = INSN(15,12);
if (bitR == 0 && rD != 15) {
- IRTemp res = newTemp(Ity_I32);
- assign( res, mk_armg_calculate_flags_nzcv() );
- putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
+ IRTemp res1 = newTemp(Ity_I32);
+ // Get NZCV
+ assign( res1, mk_armg_calculate_flags_nzcv() );
+ /// OR in the Q value
+ IRTemp res2 = newTemp(Ity_I32);
+ assign(
+ res2,
+ binop(Iop_Or32,
+ mkexpr(res1),
+ binop(Iop_Shl32,
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkexpr(get_QFLAG32()),
+ mkU32(0))),
+ mkU8(ARMG_CC_SHIFT_Q)))
+ );
+ putIRegA( rD, mkexpr(res2), condT, Ijk_Boring );
DIP("mrs%s r%u, cpsr\n", nCC(INSN_COND), rD);
goto decode_success;
}
@@ -12093,6 +12140,28 @@
switch (INSN0(15,8)) {
+ case BITS8(1,1,0,1,1,1,1,1): {
+ /* ---------------- SVC ---------------- */
+ UInt imm8 = INSN0(7,0);
+ if (imm8 == 0) {
+ /* A syscall. We can't do this conditionally, hence: */
+ mk_skip_over_T16_if_cond_is_false( condT );
+ // FIXME: what if we have to back up and restart this insn?
+ // then ITSTATE will be wrong (we'll have it as "used")
+ // when it isn't. Correct is to save ITSTATE in a
+ // stash pseudo-reg, and back up from that if we have to
+ // restart.
+ // uncond after here
+ irsb->next = mkU32( (guest_R15_curr_instr_notENC + 2) | 1 );
+ irsb->jumpkind = Ijk_Sys_syscall;
+ dres.whatNext = Dis_StopHere;
+ DIP("svc #0x%08x\n", imm8);
+ goto decode_success;
+ }
+ /* else fall through */
+ break;
+ }
+
case BITS8(0,1,0,0,0,1,0,0): {
/* ---------------- ADD(HI) Rd, Rm ---------------- */
UInt h1 = INSN0(7,7);
@@ -13209,7 +13278,7 @@
UInt rN = INSN0(3,0);
UInt rD = INSN1(11,8);
Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
- /* but allow "sub.w sp, sp, #constT" */
+ /* but allow "sub.w sp, sp, #constT" */
if (!valid && !isRSB && rN == 13 && rD == 13)
valid = True;
if (valid) {
@@ -13359,6 +13428,11 @@
&& rN == 13 && imm5 == 0 && how == 0) {
valid = True;
}
+ /* also allow "sub.w sp, sp, reg w/ no shift */
+ if (!valid && INSN0(8,5) == BITS4(1,1,0,1) // add
+ && rD == 13 && rN == 13 && imm5 == 0 && how == 0) {
+ valid = True;
+ }
if (valid) {
Bool swap = False;
IROp op = Iop_INVALID;
@@ -14540,6 +14614,23 @@
}
}
+ /* ------------------ (T2) ADR ------------------ */
+ if ((INSN0(15,0) == 0xF2AF || INSN0(15,0) == 0xF6AF)
+ && INSN1(15,15) == 0) {
+ /* rD = align4(PC) - imm32 */
+ UInt rD = INSN1(11,8);
+ if (!isBadRegT(rD)) {
+ UInt imm32 = (INSN0(10,10) << 11)
+ | (INSN1(14,12) << 8) | INSN1(7,0);
+ putIRegT(rD, binop(Iop_Sub32,
+ binop(Iop_And32, getIRegT(15), mkU32(~3UL)),
+ mkU32(imm32)),
+ condT);
+ DIP("sub r%u, pc, #%u\n", rD, imm32);
+ goto decode_success;
+ }
+ }
+
/* ------------------- (T1) BFI ------------------- */
/* ------------------- (T1) BFC ------------------- */
if (INSN0(15,4) == 0xF36 && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
@@ -14662,6 +14753,30 @@
}
}
+ /* ------------------- (T1) CLZ ------------------- */
+ if (INSN0(15,4) == 0xFAB
+ && INSN1(15,12) == BITS4(1,1,1,1)
+ && INSN1(7,4) == BITS4(1,0,0,0)) {
+ UInt rM1 = INSN0(3,0);
+ UInt rD = INSN1(11,8);
+ UInt rM2 = INSN1(3,0);
+ if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
+ IRTemp arg = newTemp(Ity_I32);
+ IRTemp res = newTemp(Ity_I32);
+ assign(arg, getIRegT(rM1));
+ assign(res, IRExpr_Mux0X(
+ unop(Iop_1Uto8,binop(Iop_CmpEQ32,
+ mkexpr(arg),
+ mkU32(0))),
+ unop(Iop_Clz32, mkexpr(arg)),
+ mkU32(32)
+ ));
+ putIRegT(rD, mkexpr(res), condT);
+ DIP("clz r%u, r%u\n", rD, rM1);
+ goto decode_success;
+ }
+ }
+
/* ----------------------------------------------------------- */
/* -- VFP (CP 10, CP 11) instructions (in Thumb mode) -- */
/* ----------------------------------------------------------- */
Modified: branches/THUMB/pub/libvex_guest_arm.h
===================================================================
--- branches/THUMB/pub/libvex_guest_arm.h 2010-08-08 11:47:23 UTC (rev 2005)
+++ branches/THUMB/pub/libvex_guest_arm.h 2010-08-09 08:57:27 UTC (rev 2006)
@@ -75,6 +75,12 @@
UInt guest_CC_DEP2;
UInt guest_CC_NDEP;
+ /* A 32-bit value which is used to compute the APSR.Q (sticky
+ saturation) flag, when necessary. If the value stored here
+ is zero, APSR.Q is currently zero. If it is any other value,
+ APSR.Q is currently one. */
+ UInt guest_QFLAG32;
+
/* Various pseudo-regs mandated by Vex or Valgrind. */
/* Emulation warnings */
UInt guest_EMWARN;
|