mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
x64Analyzer: add movss/movups/movaps support and an instruction class field
The crash handler's instruction analyzer only understood mov/movzx/movsx, so a fault on an FP or SIMD load/store (used for lwc1/swc1 and lv.q/sv.q in the x86 JIT) couldn't be classified. Add decoding for movss (scalar, distinguished from movups by the mandatory 0xF3 prefix), movups, and movaps, and add an InstructionClass field (GPR/FP/FP_SIMD) so callers know how to interpret the decoded register operand. Covered by new unit tests in TestX64Emitter.cpp that emit each instruction and check the analyzer's output against it.
This commit is contained in:
1 parent
6a873df4ea
commit
2c315be708
3 files changed
+110
-2
No files matched your search
@@ -3,6 +3,7 @@
|
||||
#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86)
|
||||
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/x64Analyzer.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/MIPS/x86/RegCacheFPU.h"
|
||||
#include "Core/MIPS/x86/Jit.h"
|
||||
@@ -21,6 +22,22 @@ static bool CheckLast(const Gen::XEmitter &emit, const char *comp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Emits nothing itself - runs the x64 crash-handler instruction analyzer (Common/x64Analyzer.cpp)
|
||||
// on the instruction most recently emitted (from prevStart to the emitter's current position),
|
||||
// and checks that it decoded it the way we expect.
|
||||
static bool CheckAnalyze(const Gen::XEmitter &emit, bool expectWrite, InstructionClass expectClass, int expectOperandSize, bool expectZeroExtend = false, bool expectSignExtend = false) {
|
||||
LSInstructionInfo info{};
|
||||
bool success = X86AnalyzeMOV(prevStart, info);
|
||||
EXPECT_TRUE(success);
|
||||
EXPECT_EQ_INT(info.instructionSize, (int)(emit.GetCodePointer() - prevStart));
|
||||
EXPECT_EQ_INT(info.isMemoryWrite, expectWrite);
|
||||
EXPECT_EQ_INT((int)info.instructionClass, (int)expectClass);
|
||||
EXPECT_EQ_INT(info.operandSize, expectOperandSize);
|
||||
EXPECT_EQ_INT(info.zeroExtend, expectZeroExtend);
|
||||
EXPECT_EQ_INT(info.signExtend, expectSignExtend);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PrintLast(const Gen::XEmitter &emit) {
|
||||
for (const u8 *p = prevStart; p < emit.GetCodePointer(); p++) {
|
||||
printf("%02x ", *p);
|
||||
@@ -47,6 +64,57 @@ bool TestX64Emitter() {
|
||||
|
||||
cpu_info.bAVX = prevAVX;
|
||||
|
||||
// Exercise Common/x64Analyzer.cpp (used by the JIT crash handler to figure out what a faulting
|
||||
// load/store instruction was doing) against instructions written by the emitter, for the most
|
||||
// common memory access instructions.
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOV(32, R(EAX), MDisp(RCX, 4));
|
||||
RET(CheckAnalyze(emitter, false, InstructionClass::GPR, 4));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOV(32, MDisp(RCX, 4), R(EAX));
|
||||
RET(CheckAnalyze(emitter, true, InstructionClass::GPR, 4));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVZX(32, 8, EAX, MDisp(RCX, 4));
|
||||
RET(CheckAnalyze(emitter, false, InstructionClass::GPR, 1, true, false));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVZX(32, 16, EAX, MDisp(RCX, 4));
|
||||
RET(CheckAnalyze(emitter, false, InstructionClass::GPR, 2, true, false));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVSX(32, 8, EAX, MDisp(RCX, 4));
|
||||
RET(CheckAnalyze(emitter, false, InstructionClass::GPR, 1, false, true));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVSX(32, 16, EAX, MDisp(RCX, 4));
|
||||
RET(CheckAnalyze(emitter, false, InstructionClass::GPR, 2, false, true));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVSS(XMM0, MDisp(RCX, 4));
|
||||
RET(CheckAnalyze(emitter, false, InstructionClass::FP, 4));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVSS(MDisp(RCX, 4), XMM0);
|
||||
RET(CheckAnalyze(emitter, true, InstructionClass::FP, 4));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVUPS(XMM0, MDisp(RCX, 4));
|
||||
RET(CheckAnalyze(emitter, false, InstructionClass::FP_SIMD, 16));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVUPS(MDisp(RCX, 4), XMM0);
|
||||
RET(CheckAnalyze(emitter, true, InstructionClass::FP_SIMD, 16));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVAPS(XMM0, MDisp(RCX, 4));
|
||||
RET(CheckAnalyze(emitter, false, InstructionClass::FP_SIMD, 16));
|
||||
|
||||
prevStart = emitter.GetCodePointer();
|
||||
emitter.MOVAPS(MDisp(RCX, 4), XMM0);
|
||||
RET(CheckAnalyze(emitter, true, InstructionClass::FP_SIMD, 16));
|
||||
|
||||
// Just for checking.
|
||||
PrintLast(emitter);
|
||||
return true;
|
||||
|
||||
Reference in new issue
Block a user