mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Refactor fastmem/trampoline code.
Simplication to avoid reading back the generated instructions, allowing us to handle all possible cases.
This commit is contained in:
@ -29,7 +29,6 @@ set(SRCS Analytics.cpp
|
||||
TraversalClient.cpp
|
||||
Version.cpp
|
||||
x64ABI.cpp
|
||||
x64Analyzer.cpp
|
||||
x64Emitter.cpp
|
||||
Crypto/bn.cpp
|
||||
Crypto/ec.cpp
|
||||
|
@ -133,7 +133,6 @@
|
||||
<ClInclude Include="TraversalClient.h" />
|
||||
<ClInclude Include="TraversalProto.h" />
|
||||
<ClInclude Include="x64ABI.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
<ClInclude Include="Crypto\bn.h" />
|
||||
<ClInclude Include="Crypto\ec.h" />
|
||||
@ -178,7 +177,6 @@
|
||||
<ClCompile Include="ucrtFreadWorkaround.cpp" />
|
||||
<ClCompile Include="Version.cpp" />
|
||||
<ClCompile Include="x64ABI.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
<ClCompile Include="x64CPUDetect.cpp" />
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
<ClCompile Include="x64FPURoundMode.cpp" />
|
||||
|
@ -62,7 +62,6 @@
|
||||
<ClInclude Include="Thread.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="x64ABI.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
<ClInclude Include="Logging\ConsoleListener.h">
|
||||
<Filter>Logging</Filter>
|
||||
@ -253,7 +252,6 @@
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="Version.cpp" />
|
||||
<ClCompile Include="x64ABI.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
<ClCompile Include="x64CPUDetect.cpp" />
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
<ClCompile Include="x64FPURoundMode.cpp" />
|
||||
|
@ -1,233 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/x64Analyzer.h"
|
||||
|
||||
bool DisassembleMov(const unsigned char* codePtr, InstructionInfo* info)
|
||||
{
|
||||
unsigned const char* startCodePtr = codePtr;
|
||||
u8 rex = 0;
|
||||
u32 opcode;
|
||||
int opcode_length;
|
||||
|
||||
// Check for regular prefix
|
||||
info->operandSize = 4;
|
||||
info->zeroExtend = false;
|
||||
info->signExtend = false;
|
||||
info->hasImmediate = false;
|
||||
info->isMemoryWrite = false;
|
||||
info->byteSwap = false;
|
||||
|
||||
u8 modRMbyte = 0;
|
||||
u8 sibByte = 0;
|
||||
bool hasModRM = false;
|
||||
|
||||
int displacementSize = 0;
|
||||
|
||||
if (*codePtr == 0x66)
|
||||
{
|
||||
info->operandSize = 2;
|
||||
codePtr++;
|
||||
}
|
||||
else if (*codePtr == 0x67)
|
||||
{
|
||||
codePtr++;
|
||||
}
|
||||
|
||||
// Check for REX prefix
|
||||
if ((*codePtr & 0xF0) == 0x40)
|
||||
{
|
||||
rex = *codePtr;
|
||||
if (rex & 8) // REX.W
|
||||
{
|
||||
info->operandSize = 8;
|
||||
}
|
||||
codePtr++;
|
||||
}
|
||||
|
||||
opcode = *codePtr++;
|
||||
opcode_length = 1;
|
||||
if (opcode == 0x0F)
|
||||
{
|
||||
opcode = (opcode << 8) | *codePtr++;
|
||||
opcode_length = 2;
|
||||
if ((opcode & 0xFB) == 0x38)
|
||||
{
|
||||
opcode = (opcode << 8) | *codePtr++;
|
||||
opcode_length = 3;
|
||||
}
|
||||
}
|
||||
|
||||
switch (opcode_length)
|
||||
{
|
||||
case 1:
|
||||
if ((opcode & 0xF0) == 0x80 || ((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02))
|
||||
{
|
||||
modRMbyte = *codePtr++;
|
||||
hasModRM = true;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) ||
|
||||
((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) || (opcode & 0xF0) == 0x30 ||
|
||||
(opcode & 0xFF) == 0x77 || (opcode & 0xF0) == 0x80 || (opcode & 0xF8) == 0xC8)
|
||||
{
|
||||
// No mod R/M byte
|
||||
}
|
||||
else
|
||||
{
|
||||
modRMbyte = *codePtr++;
|
||||
hasModRM = true;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// TODO: support more 3-byte opcode instructions
|
||||
if ((opcode & 0xFE) == 0xF0)
|
||||
{
|
||||
modRMbyte = *codePtr++;
|
||||
hasModRM = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasModRM)
|
||||
{
|
||||
ModRM mrm(modRMbyte, rex);
|
||||
info->regOperandReg = mrm.reg;
|
||||
if (mrm.mod < 3)
|
||||
{
|
||||
if (mrm.rm == 4)
|
||||
{
|
||||
// SIB byte
|
||||
sibByte = *codePtr++;
|
||||
info->scaledReg = (sibByte >> 3) & 7;
|
||||
info->otherReg = (sibByte & 7);
|
||||
if (rex & 2)
|
||||
info->scaledReg += 8;
|
||||
if (rex & 1)
|
||||
info->otherReg += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// info->scaledReg =
|
||||
}
|
||||
}
|
||||
if (mrm.mod == 1 || mrm.mod == 2)
|
||||
{
|
||||
if (mrm.mod == 1)
|
||||
displacementSize = 1;
|
||||
else
|
||||
displacementSize = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementSize == 1)
|
||||
info->displacement = (s32)(s8)*codePtr;
|
||||
else
|
||||
info->displacement = *((s32*)codePtr);
|
||||
codePtr += displacementSize;
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 0xC6: // mem <- imm8
|
||||
info->isMemoryWrite = true;
|
||||
info->hasImmediate = true;
|
||||
info->immediate = *codePtr;
|
||||
info->operandSize = 1;
|
||||
codePtr++;
|
||||
break;
|
||||
|
||||
case 0xC7: // mem <- imm16/32
|
||||
info->isMemoryWrite = true;
|
||||
switch (info->operandSize)
|
||||
{
|
||||
case 2:
|
||||
info->hasImmediate = true;
|
||||
info->immediate = *(u16*)codePtr;
|
||||
codePtr += 2;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
info->hasImmediate = true;
|
||||
info->immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
info->zeroExtend = true;
|
||||
info->immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x88: // mem <- r8
|
||||
info->isMemoryWrite = true;
|
||||
if (info->operandSize != 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
info->operandSize = 1;
|
||||
break;
|
||||
|
||||
case 0x89: // mem <- r16/32/64
|
||||
info->isMemoryWrite = true;
|
||||
break;
|
||||
|
||||
case 0x8A: // r8 <- mem
|
||||
if (info->operandSize != 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
info->operandSize = 1;
|
||||
break;
|
||||
|
||||
case 0x8B: // r16/32/64 <- mem
|
||||
break;
|
||||
|
||||
case 0x0FB6: // movzx on byte
|
||||
info->zeroExtend = true;
|
||||
info->operandSize = 1;
|
||||
break;
|
||||
|
||||
case 0x0FB7: // movzx on short
|
||||
info->zeroExtend = true;
|
||||
info->operandSize = 2;
|
||||
break;
|
||||
|
||||
case 0x0FBE: // movsx on byte
|
||||
info->signExtend = true;
|
||||
info->operandSize = 1;
|
||||
break;
|
||||
|
||||
case 0x0FBF: // movsx on short
|
||||
info->signExtend = true;
|
||||
info->operandSize = 2;
|
||||
break;
|
||||
|
||||
case 0x0F38F0: // movbe read
|
||||
info->byteSwap = true;
|
||||
break;
|
||||
|
||||
case 0x0F38F1: // movbe write
|
||||
info->byteSwap = true;
|
||||
info->isMemoryWrite = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
info->instructionSize = (int)(codePtr - startCodePtr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InstructionInfo::operator==(const InstructionInfo& other) const
|
||||
{
|
||||
return operandSize == other.operandSize && instructionSize == other.instructionSize &&
|
||||
regOperandReg == other.regOperandReg && otherReg == other.otherReg &&
|
||||
scaledReg == other.scaledReg && zeroExtend == other.zeroExtend &&
|
||||
signExtend == other.signExtend && hasImmediate == other.hasImmediate &&
|
||||
isMemoryWrite == other.isMemoryWrite && byteSwap == other.byteSwap &&
|
||||
immediate == other.immediate && displacement == other.displacement;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
struct InstructionInfo
|
||||
{
|
||||
int operandSize; // 8, 16, 32, 64
|
||||
int instructionSize;
|
||||
int regOperandReg;
|
||||
int otherReg;
|
||||
int scaledReg;
|
||||
bool zeroExtend;
|
||||
bool signExtend;
|
||||
bool hasImmediate;
|
||||
bool isMemoryWrite;
|
||||
bool byteSwap;
|
||||
u64 immediate;
|
||||
s32 displacement;
|
||||
|
||||
bool operator==(const InstructionInfo& other) const;
|
||||
};
|
||||
|
||||
struct ModRM
|
||||
{
|
||||
int mod, reg, rm;
|
||||
ModRM(u8 modRM, u8 rex)
|
||||
{
|
||||
mod = modRM >> 6;
|
||||
reg = ((modRM >> 3) & 7) | ((rex & 4) ? 8 : 0);
|
||||
rm = modRM & 7;
|
||||
}
|
||||
};
|
||||
|
||||
enum AccessType
|
||||
{
|
||||
OP_ACCESS_READ = 0,
|
||||
OP_ACCESS_WRITE = 1
|
||||
};
|
||||
|
||||
bool DisassembleMov(const unsigned char* codePtr, InstructionInfo* info);
|
@ -1046,8 +1046,14 @@ void XEmitter::MOVBE(int bits, const OpArg& dest, X64Reg src)
|
||||
WriteMOVBE(bits, 0xF1, src, dest);
|
||||
}
|
||||
|
||||
void XEmitter::LoadAndSwap(int size, X64Reg dst, const OpArg& src, bool sign_extend)
|
||||
void XEmitter::LoadAndSwap(int size, X64Reg dst, const OpArg& src, bool sign_extend, MovInfo* info)
|
||||
{
|
||||
if (info)
|
||||
{
|
||||
info->address = GetWritableCodePtr();
|
||||
info->nonAtomicSwapStore = false;
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 8:
|
||||
@ -1083,20 +1089,28 @@ void XEmitter::LoadAndSwap(int size, X64Reg dst, const OpArg& src, bool sign_ext
|
||||
}
|
||||
}
|
||||
|
||||
u8* XEmitter::SwapAndStore(int size, const OpArg& dst, X64Reg src)
|
||||
void XEmitter::SwapAndStore(int size, const OpArg& dst, X64Reg src, MovInfo* info)
|
||||
{
|
||||
u8* mov_location = GetWritableCodePtr();
|
||||
if (cpu_info.bMOVBE)
|
||||
{
|
||||
if (info)
|
||||
{
|
||||
info->address = GetWritableCodePtr();
|
||||
info->nonAtomicSwapStore = false;
|
||||
}
|
||||
MOVBE(size, dst, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
BSWAP(size, src);
|
||||
mov_location = GetWritableCodePtr();
|
||||
if (info)
|
||||
{
|
||||
info->address = GetWritableCodePtr();
|
||||
info->nonAtomicSwapStore = true;
|
||||
info->nonAtomicSwapStoreSrc = src;
|
||||
}
|
||||
MOV(size, dst, R(src));
|
||||
}
|
||||
return mov_location;
|
||||
}
|
||||
|
||||
void XEmitter::LEA(int bits, X64Reg dest, OpArg src)
|
||||
|
@ -203,6 +203,15 @@ enum FloatOp
|
||||
|
||||
class XEmitter;
|
||||
|
||||
// Information about a generated MOV op
|
||||
struct MovInfo final
|
||||
{
|
||||
u8* address;
|
||||
bool nonAtomicSwapStore;
|
||||
// valid iff nonAtomicSwapStore is true
|
||||
X64Reg nonAtomicSwapStoreSrc;
|
||||
};
|
||||
|
||||
// RIP addressing does not benefit from micro op fusion on Core arch
|
||||
struct OpArg
|
||||
{
|
||||
@ -272,6 +281,27 @@ struct OpArg
|
||||
return (s8)offset;
|
||||
}
|
||||
|
||||
OpArg AsImm64() const
|
||||
{
|
||||
_dbg_assert_(DYNA_REC, IsImm());
|
||||
return OpArg((u64)offset, SCALE_IMM64);
|
||||
}
|
||||
OpArg AsImm32() const
|
||||
{
|
||||
_dbg_assert_(DYNA_REC, IsImm());
|
||||
return OpArg((u32)offset, SCALE_IMM32);
|
||||
}
|
||||
OpArg AsImm16() const
|
||||
{
|
||||
_dbg_assert_(DYNA_REC, IsImm());
|
||||
return OpArg((u16)offset, SCALE_IMM16);
|
||||
}
|
||||
OpArg AsImm8() const
|
||||
{
|
||||
_dbg_assert_(DYNA_REC, IsImm());
|
||||
return OpArg((u8)offset, SCALE_IMM8);
|
||||
}
|
||||
|
||||
void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const;
|
||||
bool IsImm() const
|
||||
{
|
||||
@ -625,8 +655,9 @@ public:
|
||||
// Available only on Atom or >= Haswell so far. Test with cpu_info.bMOVBE.
|
||||
void MOVBE(int bits, X64Reg dest, const OpArg& src);
|
||||
void MOVBE(int bits, const OpArg& dest, X64Reg src);
|
||||
void LoadAndSwap(int size, X64Reg dst, const OpArg& src, bool sign_extend = false);
|
||||
u8* SwapAndStore(int size, const OpArg& dst, X64Reg src);
|
||||
void LoadAndSwap(int size, X64Reg dst, const OpArg& src, bool sign_extend = false,
|
||||
MovInfo* info = nullptr);
|
||||
void SwapAndStore(int size, const OpArg& dst, X64Reg src, MovInfo* info = nullptr);
|
||||
|
||||
// Available only on AMD >= Phenom or Intel >= Haswell
|
||||
void LZCNT(int bits, X64Reg dest, const OpArg& src);
|
||||
|
Reference in New Issue
Block a user