void recMTSAH() { if( GPR_IS_CONST1(_Rs_) ) { xMOV(ptr32[&cpuRegs.sa], ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 1); } else { _eeMoveGPRtoR(eax, _Rs_); xAND(eax, 0x7); xXOR(eax, _Imm_&0x7); xSHL(eax, 1); xMOV(ptr[&cpuRegs.sa], eax); } }
// ------------------------------------------------------------------------ // Internal implementation of EmitSibMagic which has been custom tailored // to optimize special forms of the Lea instructions accordingly, such // as when a LEA can be replaced with a "MOV reg,imm" or "MOV reg,reg". // // preserve_flags - set to ture to disable use of SHL on [Index*Base] forms // of LEA, which alters flags states. // static void EmitLeaMagic( const xRegisterInt& to, const xIndirectVoid& src, bool preserve_flags ) { int displacement_size = (src.Displacement == 0) ? 0 : ( ( src.IsByteSizeDisp() ) ? 1 : 2 ); // See EmitSibMagic for commenting on SIB encoding. if( !NeedsSibMagic( src ) ) { // LEA Land: means we have either 1-register encoding or just an offset. // offset is encodable as an immediate MOV, and a register is encodable // as a register MOV. if( src.Index.IsEmpty() ) { xMOV( to, src.Displacement ); return; } else if( displacement_size == 0 ) { _xMovRtoR( to, src.Index ); return; } else { if( !preserve_flags ) { // encode as MOV and ADD combo. Make sure to use the immediate on the // ADD since it can encode as an 8-bit sign-extended value. _xMovRtoR( to, src.Index ); xADD( to, src.Displacement ); return; } else { // note: no need to do ebp+0 check since we encode all 0 displacements as // register assignments above (via MOV) xWrite8( 0x8d ); ModRM( displacement_size, to.Id, src.Index.Id ); } } } else { if( src.Base.IsEmpty() ) { if( !preserve_flags && (displacement_size == 0) ) { // Encode [Index*Scale] as a combination of Mov and Shl. // This is more efficient because of the bloated LEA format which requires // a 32 bit displacement, and the compact nature of the alternative. // // (this does not apply to older model P4s with the broken barrel shifter, // but we currently aren't optimizing for that target anyway). _xMovRtoR( to, src.Index ); xSHL( to, src.Scale ); return; } xWrite8( 0x8d ); ModRM( 0, to.Id, ModRm_UseSib ); SibSB( src.Scale, src.Index.Id, ModRm_UseDisp32 ); xWrite32( src.Displacement ); return; } else { if( src.Scale == 0 ) { if( !preserve_flags ) { if( src.Index == esp ) { // ESP is not encodable as an index (ix86 ignores it), thus: _xMovRtoR( to, src.Base ); // will do the trick! if( src.Displacement ) xADD( to, src.Displacement ); return; } else if( src.Displacement == 0 ) { _xMovRtoR( to, src.Base ); _g1_EmitOp( G1Type_ADD, to, src.Index ); return; } } else if( (src.Index == esp) && (src.Displacement == 0) ) { // special case handling of ESP as Index, which is replaceable with // a single MOV even when preserve_flags is set! :D _xMovRtoR( to, src.Base ); return; } } if( src.Base == ebp && displacement_size == 0 ) displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]! xWrite8( 0x8d ); ModRM( displacement_size, to.Id, ModRm_UseSib ); SibSB( src.Scale, src.Index.Id, src.Base.Id ); } } if( displacement_size != 0 ) { if( displacement_size == 1 ) xWrite<s8>( src.Displacement ); else xWrite<s32>( src.Displacement ); } }