From 05b2ad5a3035ab179a249c0de43896f77fe3814c Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Sat, 28 Jun 2014 22:11:16 +0000 Subject: [PATCH] arm64: change the representation of FPSR.QC so that it can be used efficiently to record SIMD saturation, and remove support for all other bits of FPSR, since we don't model them anyway. git-svn-id: svn://svn.valgrind.org/vex/trunk@2894 --- VEX/priv/guest_arm64_helpers.c | 27 ++++++++++++++++++++++--- VEX/priv/guest_arm64_toIR.c | 37 +++++++++++++++++++++++++--------- VEX/pub/libvex_guest_arm64.h | 29 ++++++++++++++++++-------- 3 files changed, 72 insertions(+), 21 deletions(-) diff --git a/VEX/priv/guest_arm64_helpers.c b/VEX/priv/guest_arm64_helpers.c index 3196d424b4..eaa8d6fb84 100644 --- a/VEX/priv/guest_arm64_helpers.c +++ b/VEX/priv/guest_arm64_helpers.c @@ -1177,6 +1177,28 @@ ULong LibVEX_GuestARM64_get_nzcv ( /*IN*/const VexGuestARM64State* vex_state ) return nzcv; } +/* VISIBLE TO LIBVEX CLIENT */ +ULong LibVEX_GuestARM64_get_fpsr ( const VexGuestARM64State* vex_state ) +{ + UInt w32 = vex_state->guest_QCFLAG[0] | vex_state->guest_QCFLAG[1] + | vex_state->guest_QCFLAG[2] | vex_state->guest_QCFLAG[3]; + ULong fpsr = 0; + // QC + if (w32 != 0) + fpsr |= (1 << 27); + return fpsr; +} + +void LibVEX_GuestARM64_set_fpsr ( /*MOD*/VexGuestARM64State* vex_state, + ULong fpsr ) +{ + // QC + vex_state->guest_QCFLAG[0] = (UInt)((fpsr >> 27) & 1); + vex_state->guest_QCFLAG[1] = 0; + vex_state->guest_QCFLAG[2] = 0; + vex_state->guest_QCFLAG[3] = 0; +} + /* VISIBLE TO LIBVEX CLIENT */ void LibVEX_GuestARM64_initialise ( /*OUT*/VexGuestARM64State* vex_state ) { @@ -1345,7 +1367,7 @@ VexGuestLayout /* Describe any sections to be regarded by Memcheck as 'always-defined'. */ - .n_alwaysDefd = 10, + .n_alwaysDefd = 9, /* flags thunk: OP is always defd, whereas DEP1 and DEP2 have to be tracked. See detailed comment in gdefs.h on @@ -1359,8 +1381,7 @@ VexGuestLayout /* 5 */ ALWAYSDEFD(guest_CMLEN), /* 6 */ ALWAYSDEFD(guest_NRADDR), /* 7 */ ALWAYSDEFD(guest_IP_AT_SYSCALL), - /* 8 */ ALWAYSDEFD(guest_FPCR), - /* 9 */ ALWAYSDEFD(guest_FPSR) + /* 8 */ ALWAYSDEFD(guest_TPIDR_EL0) } }; diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c index 36934cad20..166a7276c1 100644 --- a/VEX/priv/guest_arm64_toIR.c +++ b/VEX/priv/guest_arm64_toIR.c @@ -697,14 +697,7 @@ static IRExpr* narrowFrom64 ( IRType dstTy, IRExpr* e ) #define OFFB_Q31 offsetof(VexGuestARM64State,guest_Q31) #define OFFB_FPCR offsetof(VexGuestARM64State,guest_FPCR) -#define OFFB_FPSR offsetof(VexGuestARM64State,guest_FPSR) -//ZZ #define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO) -//ZZ #define OFFB_ITSTATE offsetof(VexGuestARMState,guest_ITSTATE) -//ZZ #define OFFB_QFLAG32 offsetof(VexGuestARMState,guest_QFLAG32) -//ZZ #define OFFB_GEFLAG0 offsetof(VexGuestARMState,guest_GEFLAG0) -//ZZ #define OFFB_GEFLAG1 offsetof(VexGuestARMState,guest_GEFLAG1) -//ZZ #define OFFB_GEFLAG2 offsetof(VexGuestARMState,guest_GEFLAG2) -//ZZ #define OFFB_GEFLAG3 offsetof(VexGuestARMState,guest_GEFLAG3) +#define OFFB_QCFLAG offsetof(VexGuestARM64State,guest_QCFLAG) #define OFFB_CMSTART offsetof(VexGuestARM64State,guest_CMSTART) #define OFFB_CMLEN offsetof(VexGuestARM64State,guest_CMLEN) @@ -4879,16 +4872,37 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn, /* Cases for FPSR 0xD51B44 001 Rt MSR fpsr, rT 0xD53B44 001 Rt MSR rT, fpsr + The only part of this we model is FPSR.QC. All other bits + are ignored when writing to it and RAZ when reading from it. */ if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4420 /*MSR*/ || (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4420 /*MRS*/) { Bool toSys = INSN(21,21) == 0; UInt tt = INSN(4,0); if (toSys) { - stmt( IRStmt_Put( OFFB_FPSR, getIReg32orZR(tt)) ); + /* Just deal with FPSR.QC. Make up a V128 value which is + zero if Xt[27] is zero and any other value if Xt[27] is + nonzero. */ + IRTemp qc64 = newTemp(Ity_I64); + assign(qc64, binop(Iop_And64, + binop(Iop_Shr64, getIReg64orZR(tt), mkU8(27)), + mkU64(1))); + IRExpr* qcV128 = binop(Iop_64HLtoV128, mkexpr(qc64), mkexpr(qc64)); + stmt( IRStmt_Put( OFFB_QCFLAG, qcV128 ) ); DIP("msr fpsr, %s\n", nameIReg64orZR(tt)); } else { - putIReg32orZR(tt, IRExpr_Get(OFFB_FPSR, Ity_I32)); + /* Generate a value which is all zeroes except for bit 27, + which must be zero if QCFLAG is all zeroes and one otherwise. */ + IRTemp qcV128 = newTemp(Ity_V128); + assign(qcV128, IRExpr_Get( OFFB_QCFLAG, Ity_V128 )); + IRTemp qc64 = newTemp(Ity_I64); + assign(qc64, binop(Iop_Or64, unop(Iop_V128HIto64, mkexpr(qcV128)), + unop(Iop_V128to64, mkexpr(qcV128)))); + IRExpr* res = binop(Iop_Shl64, + unop(Iop_1Uto64, + binop(Iop_CmpNE64, mkexpr(qc64), mkU64(0))), + mkU8(27)); + putIReg64orZR(tt, res); DIP("mrs %s, fpsr\n", nameIReg64orZR(tt)); } return True; @@ -4896,6 +4910,9 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn, /* Cases for NZCV D51B42 000 Rt MSR nzcv, rT D53B42 000 Rt MRS rT, nzcv + The only parts of NZCV that actually exist are bits 31:28, which + are the N Z C and V bits themselves. Hence the flags thunk provides + all the state we need. */ if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4200 /*MSR*/ || (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4200 /*MRS*/) { diff --git a/VEX/pub/libvex_guest_arm64.h b/VEX/pub/libvex_guest_arm64.h index 1253c59fad..ac22432883 100644 --- a/VEX/pub/libvex_guest_arm64.h +++ b/VEX/pub/libvex_guest_arm64.h @@ -123,6 +123,13 @@ typedef U128 guest_Q30; U128 guest_Q31; + /* A 128-bit value which is used to represent the FPSR.QC (sticky + saturation) flag, when necessary. If the value stored here + is zero, FPSR.QC is currently zero. If it is any other value, + FPSR.QC is currently one. We don't currently represent any + other bits of FPSR, so this is all that that is for FPSR. */ + U128 guest_QCFLAG; + /* Various pseudo-regs mandated by Vex or Valgrind. */ /* Emulation notes */ UInt guest_EMNOTE; @@ -152,15 +159,9 @@ typedef note of bits 23 and 22. */ UInt guest_FPCR; - /* The complete FPSR. As with FPCR, the guest may write and - read any values here, and the emulation ignores it, with the - exception of bit 27 (QC, the sticky saturation bit) which - does get set when required. */ - UInt guest_FPSR; - /* Padding to make it have an 16-aligned size */ - UInt pad_end_0; - ULong pad_end_1; + /* UInt pad_end_0; */ + /* ULong pad_end_1; */ } VexGuestARM64State; @@ -182,6 +183,18 @@ extern ULong LibVEX_GuestARM64_get_nzcv ( /*IN*/ const VexGuestARM64State* vex_state ); +/* Calculate the ARM64 FPSR state from the saved data, in the format + 36x0:qc:27x0 */ +extern +ULong LibVEX_GuestARM64_get_fpsr ( /*IN*/ + const VexGuestARM64State* vex_state ); + +/* Set the ARM64 FPSR representation from the given FPSR value. */ +extern +void LibVEX_GuestARM64_set_fpsr ( /*MOD*/VexGuestARM64State* vex_state, + ULong fpsr ); + + #endif /* ndef __LIBVEX_PUB_GUEST_ARM64_H */ -- 2.47.2