From: Julian Seward Date: Tue, 13 Jul 2021 08:41:04 +0000 (+0200) Subject: amd64 front end: Make uses of 8- and 16-bit GPRs GET the entire containing register. X-Git-Tag: VALGRIND_3_18_0~106 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22bae4b1544fc5d82f131ef8fde4cea7666112c2;p=thirdparty%2Fvalgrind.git amd64 front end: Make uses of 8- and 16-bit GPRs GET the entire containing register. Until now, a read of a 32-bit GPR (eg, %ecx) in the amd64 front end actually involved GETting the containing 64-bit reg (%rcx) and dropping off its top 32-bits, in the IR translation. This makes IR optimisation work well for code that mixes 32 and 64 bit integer operations, which is very commont. In particular it helps guarantee that PUT-to-GET and redundant-GET optimisations work, hence that constant propagation/folding across such boundaries works, and indirectly helps to avoid generating code in the back end that suffers from store-forwarding or partial-register-read stalls. This commit partially extends those advantages to 8- and 16-bit GPR reads. In particular, all 16-bit GPR fetches are now a GET of the whole 64-bit register followed by an Iop_64to16 cast. The same scheme is used for 8-bit register fetches, except for the "anomalous four" (%ah, %bh, %ch, %dh), whose handling is left unchanged. With this in place, now, a wider write followed by a smaller read, will play nice with constant folding, propagation, for example (somewhat artificially): movl $17, %ecx // 32-bit write of %rcx shrl %cl, %r15 // 8-bit read of %rcx The 17 will be propagated, in IR, up to the shift. The commit also adds a couple more rewrite rules in ir_opt.c to remove some of the resulting pointless conversion pairings. --- diff --git a/VEX/priv/guest_amd64_toIR.c b/VEX/priv/guest_amd64_toIR.c index 070a1c5bc5..c6296f3987 100644 --- a/VEX/priv/guest_amd64_toIR.c +++ b/VEX/priv/guest_amd64_toIR.c @@ -912,7 +912,8 @@ static Int integerGuestReg64Offset ( UInt reg ) /* Produce the name of an integer register, for printing purposes. reg is a number in the range 0 .. 15 that has been generated from a 3-bit reg-field number and a REX extension bit. irregular denotes - the case where sz==1 and no REX byte is present. */ + the case where sz==1 and no REX byte is present and where the denoted + sub-register is bits 15:8 of the containing 64-bit register. */ static const HChar* nameIReg ( Int sz, UInt reg, Bool irregular ) @@ -929,13 +930,13 @@ const HChar* nameIReg ( Int sz, UInt reg, Bool irregular ) static const HChar* ireg8_names[16] = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" }; - static const HChar* ireg8_irregular[8] - = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" }; + static const HChar* ireg8_irregular[4] + = { "%ah", "%ch", "%dh", "%bh" }; vassert(reg < 16); if (sz == 1) { if (irregular) - vassert(reg < 8); + vassert(reg >= 4 && reg < 8); } else { vassert(irregular == False); } @@ -945,7 +946,8 @@ const HChar* nameIReg ( Int sz, UInt reg, Bool irregular ) case 4: return ireg32_names[reg]; case 2: return ireg16_names[reg]; case 1: if (irregular) { - return ireg8_irregular[reg]; + vassert(reg >= 4 && reg < 8); + return ireg8_irregular[reg - 4]; } else { return ireg8_names[reg]; } @@ -962,7 +964,7 @@ Int offsetIReg ( Int sz, UInt reg, Bool irregular ) vassert(reg < 16); if (sz == 1) { if (irregular) - vassert(reg < 8); + vassert(reg >= 4 && reg < 8); } else { vassert(irregular == False); } @@ -988,7 +990,7 @@ Int offsetIReg ( Int sz, UInt reg, Bool irregular ) static IRExpr* getIRegCL ( void ) { vassert(host_endness == VexEndnessLE); - return IRExpr_Get( OFFB_RCX, Ity_I8 ); + return unop(Iop_64to8, IRExpr_Get( OFFB_RCX, Ity_I64 )); } @@ -1020,8 +1022,8 @@ static IRExpr* getIRegRAX ( Int sz ) { vassert(host_endness == VexEndnessLE); switch (sz) { - case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 ); - case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 ); + case 1: return unop(Iop_64to8, IRExpr_Get( OFFB_RAX, Ity_I64 )); + case 2: return unop(Iop_64to16, IRExpr_Get( OFFB_RAX, Ity_I64 )); case 4: return unop(Iop_64to32, IRExpr_Get( OFFB_RAX, Ity_I64 )); case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 ); default: vpanic("getIRegRAX(amd64)"); @@ -1068,8 +1070,8 @@ static IRExpr* getIRegRDX ( Int sz ) { vassert(host_endness == VexEndnessLE); switch (sz) { - case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 ); - case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 ); + case 1: return unop(Iop_64to8, IRExpr_Get( OFFB_RDX, Ity_I64 )); + case 2: return unop(Iop_64to16, IRExpr_Get( OFFB_RDX, Ity_I64 )); case 4: return unop(Iop_64to32, IRExpr_Get( OFFB_RDX, Ity_I64 )); case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 ); default: vpanic("getIRegRDX(amd64)"); @@ -1145,8 +1147,9 @@ static const HChar* nameIReg32 ( UInt regno ) static IRExpr* getIReg16 ( UInt regno ) { vassert(host_endness == VexEndnessLE); - return IRExpr_Get( integerGuestReg64Offset(regno), - Ity_I16 ); + return unop(Iop_64to16, + IRExpr_Get( integerGuestReg64Offset(regno), + Ity_I64 )); } static void putIReg16 ( UInt regno, IRExpr* e ) @@ -1193,22 +1196,46 @@ static IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits ) { vassert(lo3bits < 8); vassert(IS_VALID_PFX(pfx)); - vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1); - if (sz == 4) { - sz = 8; - return unop(Iop_64to32, - IRExpr_Get( - offsetIReg( sz, lo3bits | (getRexB(pfx) << 3), - False/*!irregular*/ ), - szToITy(sz) - ) - ); - } else { - return IRExpr_Get( - offsetIReg( sz, lo3bits | (getRexB(pfx) << 3), - toBool(sz==1 && !haveREX(pfx)) ), - szToITy(sz) - ); + UInt regNo = (getRexB(pfx) << 3) | lo3bits; + switch (sz) { + case 8: { + return IRExpr_Get( + offsetIReg( 8, regNo, False/*!irregular*/ ), + Ity_I64 + ); + } + case 4: { + return unop(Iop_64to32, + IRExpr_Get( + offsetIReg( 8, regNo, False/*!irregular*/ ), + Ity_I64 + )); + } + case 2: { + return unop(Iop_64to16, + IRExpr_Get( + offsetIReg( 8, regNo, False/*!irregular*/ ), + Ity_I64 + )); + } + case 1: { + Bool irregular = !haveREX(pfx) && regNo >= 4 && regNo < 8; + if (irregular) { + return IRExpr_Get( + offsetIReg( 1, regNo, True/*irregular*/ ), + Ity_I8 + ); + } else { + return unop(Iop_64to8, + IRExpr_Get( + offsetIReg( 8, regNo, False/*!irregular*/ ), + Ity_I64 + )); + } + } + default: { + vpanic("getIRegRexB"); + } } } @@ -1218,9 +1245,9 @@ static void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e ) vassert(IS_VALID_PFX(pfx)); vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1); vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz)); + Bool irregular = sz == 1 && !haveREX(pfx) && lo3bits >= 4 && lo3bits < 8; stmt( IRStmt_Put( - offsetIReg( sz, lo3bits | (getRexB(pfx) << 3), - toBool(sz==1 && !haveREX(pfx)) ), + offsetIReg( sz, lo3bits | (getRexB(pfx) << 3), irregular ), sz==4 ? unop(Iop_32Uto64,e) : e )); } @@ -1269,20 +1296,39 @@ static UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm ) vassert(IS_VALID_PFX(pfx)); vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1); reg = gregOfRexRM( pfx, mod_reg_rm ); - return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) ); + Bool irregular = sz == 1 && !haveREX(pfx) && reg >= 4 && reg < 8; + return offsetIReg( sz, reg, irregular ); } static IRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm ) { - if (sz == 4) { - sz = 8; - return unop(Iop_64to32, - IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ), - szToITy(sz) )); - } else { - return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ), - szToITy(sz) ); + switch (sz) { + case 8: { + return IRExpr_Get( offsetIRegG( 8, pfx, mod_reg_rm ), Ity_I64 ); + } + case 4: { + return unop(Iop_64to32, + IRExpr_Get( offsetIRegG( 8, pfx, mod_reg_rm ), Ity_I64 )); + } + case 2: { + return unop(Iop_64to16, + IRExpr_Get( offsetIRegG( 8, pfx, mod_reg_rm ), Ity_I64 )); + } + case 1: { + UInt regNo = gregOfRexRM( pfx, mod_reg_rm ); + Bool irregular = !haveREX(pfx) && regNo >= 4 && regNo < 8; + if (irregular) { + return IRExpr_Get( offsetIRegG( 1, pfx, mod_reg_rm ), Ity_I8 ); + } else { + return unop(Iop_64to8, + IRExpr_Get( offsetIRegG( 8, pfx, mod_reg_rm ), + Ity_I64 )); + } + } + default: { + vpanic("getIRegG"); + } } } @@ -1299,19 +1345,24 @@ void putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e ) static const HChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm ) { - return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm), - toBool(sz==1 && !haveREX(pfx)) ); + UInt regNo = gregOfRexRM( pfx, mod_reg_rm ); + Bool irregular = sz == 1 && !haveREX(pfx) && regNo >= 4 && regNo < 8; + return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm), irregular ); } static IRExpr* getIRegV ( Int sz, Prefix pfx ) { + vassert(sz == 8 || sz == 4); if (sz == 4) { - sz = 8; return unop(Iop_64to32, - IRExpr_Get( offsetIReg( sz, getVexNvvvv(pfx), False ), - szToITy(sz) )); + IRExpr_Get( offsetIReg( 8, getVexNvvvv(pfx), False ), + Ity_I64 )); + } else if (sz == 2) { + return unop(Iop_64to16, + IRExpr_Get( offsetIReg( 8, getVexNvvvv(pfx), False ), + Ity_I64 )); } else { return IRExpr_Get( offsetIReg( sz, getVexNvvvv(pfx), False ), szToITy(sz) ); @@ -1321,6 +1372,7 @@ IRExpr* getIRegV ( Int sz, Prefix pfx ) static void putIRegV ( Int sz, Prefix pfx, IRExpr* e ) { + vassert(sz == 8 || sz == 4); vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz)); if (sz == 4) { e = unop(Iop_32Uto64,e); @@ -1331,6 +1383,7 @@ void putIRegV ( Int sz, Prefix pfx, IRExpr* e ) static const HChar* nameIRegV ( Int sz, Prefix pfx ) { + vassert(sz == 8 || sz == 4); return nameIReg( sz, getVexNvvvv(pfx), False ); } @@ -1348,20 +1401,39 @@ static UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm ) vassert(IS_VALID_PFX(pfx)); vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1); reg = eregOfRexRM( pfx, mod_reg_rm ); - return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) ); + Bool irregular = sz == 1 && !haveREX(pfx) && (reg >= 4 && reg < 8); + return offsetIReg( sz, reg, irregular ); } -static +static IRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm ) { - if (sz == 4) { - sz = 8; - return unop(Iop_64to32, - IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ), - szToITy(sz) )); - } else { - return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ), - szToITy(sz) ); + switch (sz) { + case 8: { + return IRExpr_Get( offsetIRegE( 8, pfx, mod_reg_rm ), Ity_I64 ); + } + case 4: { + return unop(Iop_64to32, + IRExpr_Get( offsetIRegE( 8, pfx, mod_reg_rm ), Ity_I64 )); + } + case 2: { + return unop(Iop_64to16, + IRExpr_Get( offsetIRegE( 8, pfx, mod_reg_rm ), Ity_I64 )); + } + case 1: { + UInt regNo = eregOfRexRM( pfx, mod_reg_rm ); + Bool irregular = !haveREX(pfx) && regNo >= 4 && regNo < 8; + if (irregular) { + return IRExpr_Get( offsetIRegE( 1, pfx, mod_reg_rm ), Ity_I8 ); + } else { + return unop(Iop_64to8, + IRExpr_Get( offsetIRegE( 8, pfx, mod_reg_rm ), + Ity_I64 )); + } + } + default: { + vpanic("getIRegE"); + } } } @@ -1378,8 +1450,9 @@ void putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e ) static const HChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm ) { - return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm), - toBool(sz==1 && !haveREX(pfx)) ); + UInt regNo = eregOfRexRM( pfx, mod_reg_rm ); + Bool irregular = sz == 1 && !haveREX(pfx) && regNo >= 4 && regNo < 8; + return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm), irregular ); } diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index 930fd49dd8..93dd6188ef 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -5480,6 +5480,14 @@ static IRExpr* fold_IRExpr_Unop ( IROp op, IRExpr* aa ) if (is_Unop(aa, Iop_8Uto64)) return IRExpr_Unop(Iop_8Uto32, aa->Iex.Unop.arg); break; + case Iop_64to16: + /* 64to16( 16Uto64 ( x )) --> x */ + if (is_Unop(aa, Iop_16Uto64)) + return aa->Iex.Unop.arg; + /* 64to16( 32Uto64 ( x )) --> 32to16(x) */ + if (is_Unop(aa, Iop_32Uto64)) + return IRExpr_Unop(Iop_32to16, aa->Iex.Unop.arg); + break; case Iop_32Uto64: /* 32Uto64( 8Uto32( x )) --> 8Uto64(x) */