Support ARM and Thumb "CLREX" instructions since Dalvik generates
them. Mucho hassle for something that is used considerably less often
than once in a blue moon.
git-svn-id: svn://svn.valgrind.org/vex/trunk@2209 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_arm_toIR.c b/priv/guest_arm_toIR.c
index 675e1b3..6b93da5 100644
--- a/priv/guest_arm_toIR.c
+++ b/priv/guest_arm_toIR.c
@@ -11991,6 +11991,16 @@
break;
}
+ /* ------------------- CLREX ------------------ */
+ if (insn == 0xF57FF01F) {
+ /* AFAICS, this simply cancels a (all?) reservations made by a
+ (any?) preceding LDREX(es). Arrange to hand it through to
+ the back end. */
+ stmt( IRStmt_MBE(Imbe_CancelReservation) );
+ DIP("clrex\n");
+ return True;
+ }
+
/* ------------------- NEON ------------------- */
if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
Bool ok_neon = decode_NEON_instruction(
@@ -17987,6 +17997,7 @@
}
/* -------------- v7 barrier insns -------------- */
if (INSN0(15,0) == 0xF3BF && (INSN1(15,0) & 0xFF00) == 0x8F00) {
+ /* FIXME: should this be unconditional? */
/* XXX this isn't really right, is it? The generated IR does
them unconditionally. I guess it doesn't matter since it
doesn't do any harm to do them even when the guarding
@@ -18025,6 +18036,7 @@
/* ---------------------- PLD{,W} ---------------------- */
if ((INSN0(15,4) & 0xFFD) == 0xF89 && INSN1(15,12) == 0xF) {
+ /* FIXME: should this be unconditional? */
/* PLD/PLDW immediate, encoding T1 */
UInt rN = INSN0(3,0);
UInt bW = INSN0(5,5);
@@ -18034,6 +18046,7 @@
}
if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,8) == 0xFC) {
+ /* FIXME: should this be unconditional? */
/* PLD/PLDW immediate, encoding T2 */
UInt rN = INSN0(3,0);
UInt bW = INSN0(5,5);
@@ -18043,6 +18056,7 @@
}
if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,6) == 0x3C0) {
+ /* FIXME: should this be unconditional? */
/* PLD/PLDW register, encoding T1 */
UInt rN = INSN0(3,0);
UInt rM = INSN1(3,0);
@@ -18062,8 +18076,8 @@
/* I don't know whether this is really v7-only. But anyway, we
have to support it since arm-linux uses TPIDRURO as a thread
state register. */
-
if ((INSN0(15,0) == 0xEE1D) && (INSN1(11,0) == 0x0F70)) {
+ /* FIXME: should this be unconditional? */
UInt rD = INSN1(15,12);
if (!isBadRegT(rD)) {
putIRegT(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32), IRTemp_INVALID);
@@ -18073,6 +18087,17 @@
/* fall through */
}
+ /* ------------------- CLREX ------------------ */
+ if (INSN0(15,0) == 0xF3BF && INSN1(15,0) == 0x8F2F) {
+ /* AFAICS, this simply cancels a (all?) reservations made by a
+ (any?) preceding LDREX(es). Arrange to hand it through to
+ the back end. */
+ mk_skip_over_T32_if_cond_is_false( condT );
+ stmt( IRStmt_MBE(Imbe_CancelReservation) );
+ DIP("clrex\n");
+ goto decode_success;
+ }
+
/* ------------------- NOP ------------------ */
if (INSN0(15,0) == 0xF3AF && INSN1(15,0) == 0x8000) {
DIP("nop\n");
diff --git a/priv/host_arm_defs.c b/priv/host_arm_defs.c
index 9523607..6749f49 100644
--- a/priv/host_arm_defs.c
+++ b/priv/host_arm_defs.c
@@ -1338,6 +1338,11 @@
i->tag = ARMin_MFence;
return i;
}
+ARMInstr* ARMInstr_CLREX( void ) {
+ ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+ i->tag = ARMin_CLREX;
+ return i;
+}
ARMInstr* ARMInstr_NLdStQ ( Bool isLoad, HReg dQ, ARMAModeN *amode ) {
ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
@@ -1759,6 +1764,9 @@
vex_printf("mfence (mcr 15,0,r0,c7,c10,4; 15,0,r0,c7,c10,5; "
"15,0,r0,c7,c5,4)");
return;
+ case ARMin_CLREX:
+ vex_printf("clrex");
+ return;
case ARMin_NLdStQ:
if (i->ARMin.NLdStQ.isLoad)
vex_printf("vld1.32 {");
@@ -2097,6 +2105,8 @@
return;
case ARMin_MFence:
return;
+ case ARMin_CLREX:
+ return;
case ARMin_NLdStQ:
if (i->ARMin.NLdStQ.isLoad)
addHRegUse(u, HRmWrite, i->ARMin.NLdStQ.dQ);
@@ -2275,6 +2285,8 @@
return;
case ARMin_MFence:
return;
+ case ARMin_CLREX:
+ return;
case ARMin_NLdStQ:
i->ARMin.NLdStQ.dQ = lookupHRegRemap(m, i->ARMin.NLdStQ.dQ);
mapRegs_ARMAModeN(m, i->ARMin.NLdStQ.amode);
@@ -3286,6 +3298,11 @@
*p++ = 0xEE070F95; /* mcr 15,0,r0,c7,c5,4 (ISB) */
goto done;
}
+ case ARMin_CLREX: {
+ *p++ = 0xF57FF01F; /* clrex */
+ goto done;
+ }
+
case ARMin_NLdStQ: {
UInt regD = qregNo(i->ARMin.NLdStQ.dQ) << 1;
UInt regN, regM;
diff --git a/priv/host_arm_defs.h b/priv/host_arm_defs.h
index 92bdbe0..989f79e 100644
--- a/priv/host_arm_defs.h
+++ b/priv/host_arm_defs.h
@@ -1,4 +1,3 @@
-
/*---------------------------------------------------------------*/
/*--- begin host_arm_defs.h ---*/
/*---------------------------------------------------------------*/
@@ -587,6 +586,7 @@
ARMin_VCvtID,
ARMin_FPSCR,
ARMin_MFence,
+ ARMin_CLREX,
/* Neon */
ARMin_NLdStQ,
ARMin_NLdStD,
@@ -827,6 +827,9 @@
*/
struct {
} MFence;
+ /* A CLREX instruction. */
+ struct {
+ } CLREX;
/* Neon data processing instruction: 3 registers of the same
length */
struct {
@@ -940,6 +943,7 @@
HReg dst, HReg src );
extern ARMInstr* ARMInstr_FPSCR ( Bool toFPSCR, HReg iReg );
extern ARMInstr* ARMInstr_MFence ( void );
+extern ARMInstr* ARMInstr_CLREX ( void );
extern ARMInstr* ARMInstr_NLdStQ ( Bool isLoad, HReg, ARMAModeN* );
extern ARMInstr* ARMInstr_NLdStD ( Bool isLoad, HReg, ARMAModeN* );
extern ARMInstr* ARMInstr_NUnary ( ARMNeonUnOp, HReg, HReg, UInt, Bool );
diff --git a/priv/host_arm_isel.c b/priv/host_arm_isel.c
index 35c4c65..f347eb0 100644
--- a/priv/host_arm_isel.c
+++ b/priv/host_arm_isel.c
@@ -5908,7 +5908,10 @@
case Ist_MBE:
switch (stmt->Ist.MBE.event) {
case Imbe_Fence:
- addInstr(env,ARMInstr_MFence());
+ addInstr(env, ARMInstr_MFence());
+ return;
+ case Imbe_CancelReservation:
+ addInstr(env, ARMInstr_CLREX());
return;
default:
break;
diff --git a/priv/ir_defs.c b/priv/ir_defs.c
index e586d17..c604ad2 100644
--- a/priv/ir_defs.c
+++ b/priv/ir_defs.c
@@ -1139,8 +1139,12 @@
void ppIRMBusEvent ( IRMBusEvent event )
{
switch (event) {
- case Imbe_Fence: vex_printf("Fence"); break;
- default: vpanic("ppIRMBusEvent");
+ case Imbe_Fence:
+ vex_printf("Fence"); break;
+ case Imbe_CancelReservation:
+ vex_printf("CancelReservation"); break;
+ default:
+ vpanic("ppIRMBusEvent");
}
}
@@ -3408,7 +3412,7 @@
break;
case Ist_MBE:
switch (stmt->Ist.MBE.event) {
- case Imbe_Fence:
+ case Imbe_Fence: case Imbe_CancelReservation:
break;
default: sanityCheckFail(bb,stmt,"IRStmt.MBE.event: unknown");
break;
diff --git a/pub/libvex_ir.h b/pub/libvex_ir.h
index 3cd6618..435090f 100644
--- a/pub/libvex_ir.h
+++ b/pub/libvex_ir.h
@@ -1772,6 +1772,10 @@
typedef
enum {
Imbe_Fence=0x18000,
+ /* Needed only on ARM. It cancels a reservation made by a
+ preceding Linked-Load, and needs to be handed through to the
+ back end, just as LL and SC themselves are. */
+ Imbe_CancelReservation
}
IRMBusEvent;