CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/MIPS/JitCommon/JitCommon.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "ppsspp_config.h"18#include <cstdlib>19#include <mutex>2021#include "ext/disarm.h"22#include "ext/riscv-disas.h"23#include "ext/udis86/udis86.h"2425#include "Common/LogReporting.h"26#include "Common/StringUtils.h"27#include "Common/Serialize/Serializer.h"28#include "Common/Serialize/SerializeFuncs.h"2930#include "Core/Util/DisArm64.h"31#include "Core/Config.h"3233#include "Core/MIPS/IR/IRJit.h"34#include "Core/MIPS/JitCommon/JitCommon.h"35#include "Core/MIPS/JitCommon/JitState.h"36#include "Core/MIPS/MIPSCodeUtils.h"37#include "Core/MIPS/MIPSTables.h"3839#if PPSSPP_ARCH(ARM)40#include "../ARM/ArmJit.h"41#elif PPSSPP_ARCH(ARM64)42#include "../ARM64/Arm64Jit.h"43#include "../ARM64/Arm64IRJit.h"44#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)45#include "../x86/Jit.h"46#include "../x86/X64IRJit.h"47#elif PPSSPP_ARCH(MIPS)48#include "../MIPS/MipsJit.h"49#elif PPSSPP_ARCH(RISCV64)50#include "../RiscV/RiscVJit.h"51#else52#include "../fake/FakeJit.h"53#endif5455namespace MIPSComp {56JitInterface *jit;57std::recursive_mutex jitLock;5859void JitAt() {60// TODO: We could probably check for a bad pc here, and fire an exception. Could spare us from some crashes.61// Although, we just tried to load from this address to check for a JIT block, and if we're here, that succeeded..62jit->Compile(currentMIPS->pc);63}6465void DoDummyJitState(PointerWrap &p) {66// This is here so the savestate matches between jit and non-jit.67auto s = p.Section("Jit", 1, 2);68if (!s)69return;7071bool dummy = false;72Do(p, dummy);73if (s >= 2) {74dummy = true;75Do(p, dummy);76}77}7879BranchInfo::BranchInfo(u32 pc, MIPSOpcode o, MIPSOpcode delayO, bool al, bool l)80: compilerPC(pc), op(o), delaySlotOp(delayO), likely(l), andLink(al) {81delaySlotInfo = MIPSGetInfo(delaySlotOp).value;82delaySlotIsBranch = (delaySlotInfo & (IS_JUMP | IS_CONDBRANCH)) != 0;83}8485u32 ResolveNotTakenTarget(const BranchInfo &branchInfo) {86u32 notTakenTarget = branchInfo.compilerPC + 8;87if ((branchInfo.delaySlotInfo & (IS_JUMP | IS_CONDBRANCH)) != 0) {88// If a branch has a j/jr/jal/jalr as a delay slot, that is run if the branch is not taken.89// TODO: Technically, in the likely case, we should somehow suppress andLink on this exit.90bool isJump = (branchInfo.delaySlotInfo & IS_JUMP) != 0;91// If the delay slot is a branch, likely skips it.92if (isJump || !branchInfo.likely)93notTakenTarget -= 4;9495// For a branch (not a jump), it actually should try the delay slot and take its target potentially.96// This is similar to the VFPU case and has not been seen, so just report it.97if (!isJump && SignExtend16ToU32(branchInfo.delaySlotOp) != SignExtend16ToU32(branchInfo.op) - 1)98ERROR_LOG_REPORT(Log::JIT, "Branch in branch delay slot at %08x with different target", branchInfo.compilerPC);99if (isJump && branchInfo.likely && (branchInfo.delaySlotInfo & (OUT_RA | OUT_RD)) != 0)100ERROR_LOG_REPORT(Log::JIT, "Jump in likely branch delay slot with link at %08x", branchInfo.compilerPC);101}102return notTakenTarget;103}104105JitInterface *CreateNativeJit(MIPSState *mipsState, bool useIR) {106#if PPSSPP_ARCH(ARM)107return new MIPSComp::ArmJit(mipsState);108#elif PPSSPP_ARCH(ARM64)109if (useIR)110return new MIPSComp::Arm64IRJit(mipsState);111return new MIPSComp::Arm64Jit(mipsState);112#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)113if (useIR)114return new MIPSComp::X64IRJit(mipsState);115return new MIPSComp::Jit(mipsState);116#elif PPSSPP_ARCH(MIPS)117return new MIPSComp::MipsJit(mipsState);118#elif PPSSPP_ARCH(RISCV64)119return new MIPSComp::RiscVJit(mipsState);120#else121return new MIPSComp::FakeJit(mipsState);122#endif123}124125}126#if PPSSPP_PLATFORM(WINDOWS) && !defined(__LIBRETRO__)127#define DISASM_ALL 1128#endif129130#if PPSSPP_ARCH(ARM) || defined(DISASM_ALL)131// We compile this for x86 as well because it may be useful when developing the ARM JIT on a PC.132std::vector<std::string> DisassembleArm2(const u8 *data, int size) {133std::vector<std::string> lines;134135char temp[256];136int bkpt_count = 0;137lines.reserve(size / 4);138for (int i = 0; i < size; i += 4) {139const u32 *codePtr = (const u32 *)(data + i);140u32 inst = codePtr[0];141u32 next = (i < size - 4) ? codePtr[1] : 0;142// MAGIC SPECIAL CASE for MOVW/MOVT readability!143if ((inst & 0x0FF00000) == 0x03000000 && (next & 0x0FF00000) == 0x03400000) {144u32 low = ((inst & 0x000F0000) >> 4) | (inst & 0x0FFF);145u32 hi = ((next & 0x000F0000) >> 4) | (next & 0x0FFF);146int reg0 = (inst & 0x0000F000) >> 12;147int reg1 = (next & 0x0000F000) >> 12;148if (reg0 == reg1) {149snprintf(temp, sizeof(temp), "MOV32 %s, %04x%04x", ArmRegName(reg0), hi, low);150lines.push_back(temp);151i += 4;152continue;153}154}155ArmDis((u32)(intptr_t)codePtr, inst, temp, sizeof(temp), false);156std::string buf = temp;157if (buf == "BKPT 1") {158bkpt_count++;159} else {160if (bkpt_count) {161lines.push_back(StringFromFormat("BKPT 1 (x%d)", bkpt_count));162bkpt_count = 0;163}164lines.push_back(buf);165}166}167if (bkpt_count) {168lines.push_back(StringFromFormat("BKPT 1 (x%d)", bkpt_count));169}170return lines;171}172#endif173174std::string AddAddress(const std::string &buf, uint64_t addr) {175char buf2[16];176snprintf(buf2, sizeof(buf2), "%04x%08x", (uint32_t)(addr >> 32), (uint32_t)(addr & 0xFFFFFFFF));177return std::string(buf2) + " " + buf;178}179180#if PPSSPP_ARCH(ARM64) || defined(DISASM_ALL)181182static bool Arm64SymbolCallback(char *buffer, int bufsize, uint8_t *address) {183std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);184if (MIPSComp::jit) {185std::string name;186if (MIPSComp::jit->DescribeCodePtr(address, name)) {187truncate_cpy(buffer, bufsize, name.c_str());188return true;189}190}191return false;192}193194std::vector<std::string> DisassembleArm64(const u8 *data, int size) {195std::vector<std::string> lines;196197char temp[256];198int bkpt_count = 0;199lines.reserve(size / 4);200for (int i = 0; i < size; i += 4) {201const u32 *codePtr = (const u32 *)(data + i);202uint64_t addr = (intptr_t)codePtr;203u32 inst = codePtr[0];204u32 next = (i < size - 4) ? codePtr[1] : 0;205// MAGIC SPECIAL CASE for MOVZ+MOVK readability!206if (((inst >> 21) & 0x3FF) == 0x294 && ((next >> 21) & 0x3FF) == 0x395) {207u32 low = (inst >> 5) & 0xFFFF;208u32 hi = (next >> 5) & 0xFFFF;209int reg0 = inst & 0x1F;210int reg1 = next & 0x1F;211char r = (inst >> 31) ? 'x' : 'w';212if (reg0 == reg1) {213snprintf(temp, sizeof(temp), "movi32 %c%d, %04x%04x", r, reg0, hi, low);214lines.push_back(AddAddress(temp, addr));215i += 4;216continue;217}218}219Arm64Dis((intptr_t)codePtr, inst, temp, sizeof(temp), false, Arm64SymbolCallback);220std::string buf = temp;221if (buf == "BKPT 1") {222bkpt_count++;223} else {224if (bkpt_count) {225lines.push_back(StringFromFormat("BKPT 1 (x%d)", bkpt_count));226bkpt_count = 0;227}228if (true) {229buf = AddAddress(buf, addr);230}231lines.push_back(buf);232}233}234if (bkpt_count) {235lines.push_back(StringFromFormat("BKPT 1 (x%d)", bkpt_count));236}237return lines;238}239#endif240241#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)242243const char *ppsspp_resolver(struct ud*,244uint64_t addr,245int64_t *offset) {246// For some reason these don't seem to trigger..247if (addr >= (uint64_t)(¤tMIPS->r[0]) && addr < (uint64_t)¤tMIPS->r[32]) {248*offset = addr - (uint64_t)(¤tMIPS->r[0]);249return "mips.r";250} else if (addr >= (uint64_t)(¤tMIPS->v[0]) && addr < (uint64_t)¤tMIPS->v[128]) {251*offset = addr - (uint64_t)(¤tMIPS->v[0]);252return "mips.v";253} else if (addr == (uint64_t)(¤tMIPS->downcount)) {254return "mips.downcount";255} else if (addr == (uint64_t)(¤tMIPS->fpcond)) {256return "mips.fpcond";257} else if (addr == (uint64_t)(¤tMIPS->temp)) {258return "mips.temp";259} else if (addr == (uint64_t)(¤tMIPS->pc)) {260return "mips.pc";261} else if (addr == (uint64_t)(¤tMIPS->hi)) {262return "mips.hi";263} else if (addr == (uint64_t)(¤tMIPS->lo)) {264return "mips.lo";265} else if (addr == (uint64_t)(¤tMIPS->fcr31)) {266return "mips.fcr31";267} else if (addr >= (uint64_t)(¤tMIPS->vfpuCtrl[0]) && addr < (uint64_t)(¤tMIPS->vfpuCtrl[16])) {268return "mips.vfpuCtrl";269}270271// But these do.272273// UGLY HACK because the API is terrible274static char buf[128];275std::string str;276277std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);278if (MIPSComp::jit && MIPSComp::jit->DescribeCodePtr((u8 *)(uintptr_t)addr, str)) {279*offset = 0;280truncate_cpy(buf, sizeof(buf), str.c_str());281return buf;282}283return NULL;284}285286std::vector<std::string> DisassembleX86(const u8 *data, int size) {287std::vector<std::string> lines;288ud_t ud_obj;289ud_init(&ud_obj);290ud_set_mode(&ud_obj, sizeof(void*) * 8);291ud_set_pc(&ud_obj, (intptr_t)data);292ud_set_vendor(&ud_obj, UD_VENDOR_ANY);293ud_set_syntax(&ud_obj, UD_SYN_INTEL);294ud_set_sym_resolver(&ud_obj, &ppsspp_resolver);295296ud_set_input_buffer(&ud_obj, data, size);297298int int3_count = 0;299while (ud_disassemble(&ud_obj) != 0) {300const char *buf = ud_insn_asm(&ud_obj);301if (!buf) {302lines.push_back("[bad]");303continue;304}305std::string str = buf;306if (str == "int3") {307int3_count++;308} else {309if (int3_count) {310lines.push_back(StringFromFormat("int3 (x%d)", int3_count));311int3_count = 0;312}313lines.push_back(str);314}315}316if (int3_count) {317lines.push_back(StringFromFormat("int3 (x%d)", int3_count));318}319return lines;320}321322#endif323324#if PPSSPP_ARCH(RISCV64) || defined(DISASM_ALL)325std::vector<std::string> DisassembleRV64(const u8 *data, int size) {326std::vector<std::string> lines;327328int invalid_count = 0;329auto invalid_flush = [&]() {330if (invalid_count != 0) {331lines.push_back(StringFromFormat("(%d invalid bytes)", invalid_count));332invalid_count = 0;333}334};335336char temp[512];337rv_inst inst;338size_t len;339for (int i = 0; i < size; ) {340riscv_inst_fetch(data + i, &inst, &len);341if (len == 0) {342// Force align in case we're somehow unaligned.343len = 2 - ((uintptr_t)data & 1);344invalid_count += (int)len;345i += (int)len;346continue;347}348349invalid_flush();350riscv_disasm_inst(temp, sizeof(temp), rv64, (uintptr_t)data + i, inst);351lines.push_back(ReplaceAll(temp, "\t", " "));352353i += (int)len;354}355356invalid_flush();357return lines;358}359#endif360361362