From: Julian Seward Date: Sat, 13 May 2017 16:40:59 +0000 (+0000) Subject: Bug 367543 - bt/btc/btr/bts x86/x86_64 instructions are poorly-handled wrt flags. X-Git-Tag: svn/VALGRIND_3_13_0^2~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f42fe83c685d8d8dd3486c942bb04a03331f51e2;p=thirdparty%2Fvalgrind.git Bug 367543 - bt/btc/btr/bts x86/x86_64 instructions are poorly-handled wrt flags. This fixes the flag handling to be like Skylake. git-svn-id: svn://svn.valgrind.org/vex/trunk@3367 --- diff --git a/VEX/priv/guest_amd64_toIR.c b/VEX/priv/guest_amd64_toIR.c index 708b776ddc..5bca7fd60f 100644 --- a/VEX/priv/guest_amd64_toIR.c +++ b/VEX/priv/guest_amd64_toIR.c @@ -8215,18 +8215,31 @@ ULong dis_bt_G_E ( const VexAbiInfo* vbi, } } - /* 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. */ + /* Side effect done; now get selected bit into Carry flag. The Intel docs + (as of 2015, at least) say that C holds the result, Z is unchanged, and + O,S,A and P are undefined. However, on Skylake it appears that O,S,A,P + are also unchanged, so let's do that. */ + const ULong maskC = AMD64G_CC_MASK_C; + const ULong maskOSZAP = AMD64G_CC_MASK_O | AMD64G_CC_MASK_S + | AMD64G_CC_MASK_Z | AMD64G_CC_MASK_A + | AMD64G_CC_MASK_P; + + IRTemp old_rflags = newTemp(Ity_I64); + assign(old_rflags, mk_amd64g_calculate_rflags_all()); + + IRTemp new_rflags = newTemp(Ity_I64); + assign(new_rflags, + binop(Iop_Or64, + binop(Iop_And64, mkexpr(old_rflags), mkU64(maskOSZAP)), + binop(Iop_And64, + binop(Iop_Shr64, + unop(Iop_8Uto64, mkexpr(t_fetched)), + mkexpr(t_bitno2)), + mkU64(maskC)))); + stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) )); stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) )); - stmt( IRStmt_Put( - OFFB_CC_DEP1, - binop(Iop_And64, - binop(Iop_Shr64, - unop(Iop_8Uto64, mkexpr(t_fetched)), - mkexpr(t_bitno2)), - mkU64(1))) - ); + stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) )); /* Set NDEP even though it isn't used. This makes redundant-PUT elimination of previous stores to this field work better. */ stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));