mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-08-31 17:55:23 +02:00
130 lines
4.2 KiB
C++
130 lines
4.2 KiB
C++
#include "ppsspp_config.h"
|
|
|
|
#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"
|
|
#include "Core/MIPS/JitCommon/JitState.h"
|
|
#include "Core/MIPS/JitCommon/JitCommon.h"
|
|
#include "Core/MIPS/MIPSVFPUUtils.h"
|
|
#include "ext/disarm.h"
|
|
|
|
#include "UnitTest.h"
|
|
|
|
static const u8 *prevStart = NULL;
|
|
|
|
static bool CheckLast(const Gen::XEmitter &emit, const char *comp) {
|
|
auto vec = DisassembleX86(prevStart, (int)(emit.GetCodePointer() - prevStart));
|
|
EXPECT_EQ_STR(vec[0], std::string(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.operandSizeInBytes, 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);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
bool TestX64Emitter() {
|
|
using namespace Gen;
|
|
|
|
u32 code[512];
|
|
XEmitter emitter((u8 *)code);
|
|
|
|
bool prevAVX = cpu_info.bAVX;
|
|
cpu_info.bAVX = true;
|
|
|
|
prevStart = emitter.GetCodePointer();
|
|
emitter.VADDSD(XMM0, XMM1, R(XMM7));
|
|
RET(CheckLast(emitter, "vaddsd xmm0, xmm1, xmm7"));
|
|
|
|
prevStart = emitter.GetCodePointer();
|
|
emitter.VMULSD(XMM0, XMM1, R(XMM7));
|
|
RET(CheckLast(emitter, "vmulsd xmm0, xmm1, xmm7"));
|
|
|
|
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;
|
|
}
|
|
|
|
#else
|
|
|
|
bool TestX64Emitter() {
|
|
return true;
|
|
}
|
|
|
|
#endif
|