From 362c8afa1202cae3f2c79a19df826ae934b5a2be Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Mon, 26 Sep 2011 16:19:43 +0000 Subject: [PATCH] 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 --- VEX/priv/guest_arm_toIR.c | 27 ++++++++++++++++++++++++++- VEX/priv/host_arm_defs.c | 17 +++++++++++++++++ VEX/priv/host_arm_defs.h | 6 +++++- VEX/priv/host_arm_isel.c | 5 ++++- VEX/priv/ir_defs.c | 10 +++++++--- VEX/pub/libvex_ir.h | 4 ++++ 6 files changed, 63 insertions(+), 6 deletions(-) diff --git a/VEX/priv/guest_arm_toIR.c b/VEX/priv/guest_arm_toIR.c index 675e1b3302..6b93da52e6 100644 --- a/VEX/priv/guest_arm_toIR.c +++ b/VEX/priv/guest_arm_toIR.c @@ -11991,6 +11991,16 @@ static Bool decode_NV_instruction ( /*MOD*/DisResult* dres, 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 @@ DisResult disInstr_THUMB_WRK ( } /* -------------- 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 @@ DisResult disInstr_THUMB_WRK ( /* ---------------------- 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 @@ DisResult disInstr_THUMB_WRK ( } 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 @@ DisResult disInstr_THUMB_WRK ( } 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 @@ DisResult disInstr_THUMB_WRK ( /* 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 @@ DisResult disInstr_THUMB_WRK ( /* 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/VEX/priv/host_arm_defs.c b/VEX/priv/host_arm_defs.c index 95236074d8..6749f49a6d 100644 --- a/VEX/priv/host_arm_defs.c +++ b/VEX/priv/host_arm_defs.c @@ -1338,6 +1338,11 @@ ARMInstr* ARMInstr_MFence ( void ) { 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 @@ void ppARMInstr ( ARMInstr* i ) { 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 @@ void getRegUsage_ARMInstr ( HRegUsage* u, ARMInstr* i, Bool mode64 ) 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 @@ void mapRegs_ARMInstr ( HRegRemap* m, ARMInstr* i, Bool mode64 ) 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 @@ Int emit_ARMInstr ( UChar* buf, Int nbuf, ARMInstr* i, *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/VEX/priv/host_arm_defs.h b/VEX/priv/host_arm_defs.h index 92bdbe06f9..989f79e30e 100644 --- a/VEX/priv/host_arm_defs.h +++ b/VEX/priv/host_arm_defs.h @@ -1,4 +1,3 @@ - /*---------------------------------------------------------------*/ /*--- begin host_arm_defs.h ---*/ /*---------------------------------------------------------------*/ @@ -587,6 +586,7 @@ typedef ARMin_VCvtID, ARMin_FPSCR, ARMin_MFence, + ARMin_CLREX, /* Neon */ ARMin_NLdStQ, ARMin_NLdStD, @@ -827,6 +827,9 @@ typedef */ struct { } MFence; + /* A CLREX instruction. */ + struct { + } CLREX; /* Neon data processing instruction: 3 registers of the same length */ struct { @@ -940,6 +943,7 @@ extern ARMInstr* ARMInstr_VCvtID ( Bool iToD, Bool syned, 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/VEX/priv/host_arm_isel.c b/VEX/priv/host_arm_isel.c index 35c4c65b6b..f347eb0d62 100644 --- a/VEX/priv/host_arm_isel.c +++ b/VEX/priv/host_arm_isel.c @@ -5908,7 +5908,10 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) 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/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index e586d17854..c604ad20c4 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -1139,8 +1139,12 @@ void ppIRJumpKind ( IRJumpKind kind ) 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 @@ void tcStmt ( IRSB* bb, IRStmt* stmt, IRType gWordTy ) 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/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 3cd6618bdd..435090fc20 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -1772,6 +1772,10 @@ IRDirty* unsafeIRDirty_1_N ( IRTemp dst, 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; -- 2.47.2