unittest: Have the JIT harness print disassembly, to make it easy to inspect results.

This commit is contained in:
Henrik Rydgard 2014-11-09 12:03:04 +01:00
parent 450227b2c6
commit 5bcdecc26b
5 changed files with 95 additions and 51 deletions

View File

@ -15,8 +15,67 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <stdlib.h>
#include "JitCommon.h"
#include "ext/disarm.h"
#include "ext/udis86/udis86.h"
namespace MIPSComp {
Jit *jit;
}
// We compile this for x86 as well because it may be useful when developing the ARM JIT on a PC.
std::vector<std::string> DisassembleArm2(const u8 *data, int size) {
std::vector<std::string> lines;
char temp[256];
for (int i = 0; i < size; i += 4) {
const u32 *codePtr = (const u32 *)(data + i);
u32 inst = codePtr[0];
u32 next = (i < size - 4) ? codePtr[1] : 0;
// MAGIC SPECIAL CASE for MOVW/MOVT readability!
if ((inst & 0x0FF00000) == 0x03000000 && (next & 0x0FF00000) == 0x03400000) {
u32 low = ((inst & 0x000F0000) >> 4) | (inst & 0x0FFF);
u32 hi = ((next & 0x000F0000) >> 4) | (next & 0x0FFF);
int reg0 = (inst & 0x0000F000) >> 12;
int reg1 = (next & 0x0000F000) >> 12;
if (reg0 == reg1) {
sprintf(temp, "MOV32 %s, %04x%04x", ArmRegName(reg0), hi, low);
// sprintf(temp, "%08x MOV32? %s, %04x%04x", (u32)inst, ArmRegName(reg0), hi, low);
lines.push_back(temp);
i += 4;
continue;
}
}
ArmDis((u32)(intptr_t)codePtr, inst, temp, sizeof(temp), false);
std::string buf = temp;
lines.push_back(buf);
}
return lines;
}
#ifndef ARM
std::vector<std::string> DisassembleX86(const u8 *data, int size) {
std::vector<std::string> lines;
ud_t ud_obj;
ud_init(&ud_obj);
#ifdef _M_X64
ud_set_mode(&ud_obj, 64);
#else
ud_set_mode(&ud_obj, 32);
#endif
ud_set_pc(&ud_obj, (intptr_t)data);
ud_set_vendor(&ud_obj, UD_VENDOR_ANY);
ud_set_syntax(&ud_obj, UD_SYN_INTEL);
ud_set_input_buffer(&ud_obj, data, size);
while (ud_disassemble(&ud_obj) != 0) {
lines.push_back(ud_insn_asm(&ud_obj));
}
return lines;
}
#endif

View File

@ -17,6 +17,9 @@
#pragma once
#include <vector>
#include <string>
#include "Common/Common.h"
struct JitBlock;
@ -56,3 +59,6 @@ struct JitBlock;
namespace MIPSComp {
extern Jit *jit;
}
std::vector<std::string> DisassembleArm2(const u8 *data, int size);
std::vector<std::string> DisassembleX86(const u8 *data, int size);

View File

@ -24,8 +24,6 @@
#include "ui/view.h"
#include "ui/viewgroup.h"
#include "ui/ui.h"
#include "ext/disarm.h"
#include "ext/udis86/udis86.h"
#include "Common/LogManager.h"
#include "Common/CPUDetect.h"
@ -432,37 +430,6 @@ void JitCompareScreen::CreateViews() {
OnCurrentBlock(ignore);
}
#ifdef ARM
std::vector<std::string> DisassembleArm2(const u8 *data, int size) {
std::vector<std::string> lines;
char temp[256];
for (int i = 0; i < size; i += 4) {
const u32 *codePtr = (const u32 *)(data + i);
u32 inst = codePtr[0];
u32 next = (i < size - 4) ? codePtr[1] : 0;
// MAGIC SPECIAL CASE for MOVW/MOVT readability!
if ((inst & 0x0FF00000) == 0x03000000 && (next & 0x0FF00000) == 0x03400000) {
u32 low = ((inst & 0x000F0000) >> 4) | (inst & 0x0FFF);
u32 hi = ((next & 0x000F0000) >> 4) | (next & 0x0FFF);
int reg0 = (inst & 0x0000F000) >> 12;
int reg1 = (next & 0x0000F000) >> 12;
if (reg0 == reg1) {
sprintf(temp, "MOV32 %s, %04x%04x", ArmRegName(reg0), hi, low);
// sprintf(temp, "%08x MOV32? %s, %04x%04x", (u32)inst, ArmRegName(reg0), hi, low);
lines.push_back(temp);
i += 4;
continue;
}
}
ArmDis((u32)(intptr_t)codePtr, inst, temp, sizeof(temp), false);
std::string buf = temp;
lines.push_back(buf);
}
return lines;
}
#endif
void JitCompareScreen::UpdateDisasm() {
leftDisasm_->Clear();
rightDisasm_->Clear();
@ -494,26 +461,12 @@ void JitCompareScreen::UpdateDisasm() {
#if defined(ARM)
std::vector<std::string> targetDis = DisassembleArm2(block->normalEntry, block->codeSize);
#else
std::vector<std::string> targetDis = DisassembleX86(block->normalEntry, block->codeSize);
#endif
for (size_t i = 0; i < targetDis.size(); i++) {
rightDisasm_->Add(new TextView(targetDis[i]));
}
#else
ud_t ud_obj;
ud_init(&ud_obj);
#ifdef _M_X64
ud_set_mode(&ud_obj, 64);
#else
ud_set_mode(&ud_obj, 32);
#endif
ud_set_pc(&ud_obj, (intptr_t)block->normalEntry);
ud_set_vendor(&ud_obj, UD_VENDOR_ANY);
ud_set_syntax(&ud_obj, UD_SYN_INTEL);
ud_set_input_buffer(&ud_obj, block->normalEntry, block->codeSize);
while (ud_disassemble(&ud_obj) != 0) {
rightDisasm_->Add(new TextView(ud_insn_asm(&ud_obj)));
}
#endif
}
UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) {

View File

@ -138,6 +138,10 @@ static std::vector<PendingMessage> pendingMessages;
static Thin3DContext *thin3d;
static UIContext *uiContext;
Thin3DContext *GetThin3D() {
return thin3d;
}
std::thread *graphicsLoadThread;
class AndroidLogger : public LogListener {

View File

@ -15,6 +15,8 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include "base/timeutil.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/MIPS/MIPSCodeUtils.h"
@ -128,6 +130,7 @@ bool TestJit() {
*p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8);
*/
for (size_t j = 0; j < ARRAY_SIZE(lines); ++j) {
if (i == 0) printf("%s\n", lines[j]);
if (!MIPSAsm::MipsAssembleOpcode(lines[j], currentDebugMIPS, addr, *p++)) {
printf("ERROR: %s\n", MIPSAsm::GetAssembleError());
compileSuccess = false;
@ -139,15 +142,34 @@ bool TestJit() {
*p++ = MIPS_MAKE_SYSCALL("UnitTestFakeSyscalls", "UnitTestTerminator");
*p++ = MIPS_MAKE_BREAK(1);
printf("\n");
double jit_speed, interp_speed;
if (compileSuccess) {
interp_speed = ExecCPUTest();
mipsr4k.UpdateCore(CPU_JIT);
jit_speed = ExecCPUTest();
printf("Jit was %fx faster than interp.\n", jit_speed / interp_speed);
// Disassemble
JitBlockCache *cache = MIPSComp::jit->GetBlockCache();
JitBlock *block = cache->GetBlock(0); // Should only be one block.
#ifdef ARM
std::vector<std::string> lines = DisassembleArm2(block->normalEntry, block->codeSize);
#else
std::vector<std::string> lines = DisassembleX86(block->normalEntry, block->codeSize);
#endif
printf("Jit was %fx faster than interp.\n\n", jit_speed / interp_speed);
// Cut off at 25 due to the repetition above. Might need tweaking for large instructions.
const int cutoff = 25;
for (int i = 0; i < std::min((int)lines.size(), cutoff); i++) {
printf("%s\n", lines[i].c_str());
}
if (lines.size() > cutoff)
printf("...\n");
}
printf("\n");
DestroyJitHarness();
return jit_speed >= interp_speed;