1 // Copyright (c) 2012- PPSSPP Project. 2 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, version 2.0 or later versions. 6 7 // This program is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 // GNU General Public License 2.0 for more details. 11 12 // A copy of the GPL 2.0 should have been included with the program. 13 // If not, see http://www.gnu.org/licenses/ 14 15 // Official git repository and contact information can be found at 16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. 17 18 #pragma once 19 20 #include <string> 21 #include <vector> 22 23 #include "Common/CommonTypes.h" 24 #include "Common/File/Path.h" 25 #include "Core/MIPS/MIPS.h" 26 27 class DebugInterface; 28 29 namespace MIPSAnalyst 30 { 31 const int MIPS_NUM_GPRS = 32; 32 33 struct RegisterAnalysisResults { 34 bool used; 35 int firstRead; 36 int lastRead; 37 int firstWrite; 38 int lastWrite; 39 int firstReadAsAddr; 40 int lastReadAsAddr; 41 42 int readCount; 43 int writeCount; 44 int readAsAddrCount; 45 TotalReadCountRegisterAnalysisResults46 int TotalReadCount() const { return readCount + readAsAddrCount; } FirstReadRegisterAnalysisResults47 int FirstRead() const { return firstReadAsAddr < firstRead ? firstReadAsAddr : firstRead; } LastReadRegisterAnalysisResults48 int LastRead() const { return lastReadAsAddr > lastRead ? lastReadAsAddr : lastRead; } 49 MarkReadRegisterAnalysisResults50 void MarkRead(u32 addr) { 51 if (firstRead == -1) 52 firstRead = addr; 53 lastRead = addr; 54 readCount++; 55 used = true; 56 } 57 MarkReadAsAddrRegisterAnalysisResults58 void MarkReadAsAddr(u32 addr) { 59 if (firstReadAsAddr == -1) 60 firstReadAsAddr = addr; 61 lastReadAsAddr = addr; 62 readAsAddrCount++; 63 used = true; 64 } 65 MarkWriteRegisterAnalysisResults66 void MarkWrite(u32 addr) { 67 if (firstWrite == -1) 68 firstWrite = addr; 69 lastWrite = addr; 70 writeCount++; 71 used = true; 72 } 73 }; 74 75 struct AnalysisResults { 76 RegisterAnalysisResults r[MIPS_NUM_GPRS]; 77 }; 78 79 AnalysisResults Analyze(u32 address); 80 81 // This tells us if the reg is used within intrs of addr (also includes likely delay slots.) 82 bool IsRegisterUsed(MIPSGPReg reg, u32 addr, int instrs); 83 // This tells us if the reg is clobbered within intrs of addr (e.g. it is surely not used.) 84 bool IsRegisterClobbered(MIPSGPReg reg, u32 addr, int instrs); 85 86 struct AnalyzedFunction { 87 u32 start; 88 u32 end; 89 u64 hash; 90 u32 size; 91 bool isStraightLeaf; 92 bool hasHash; 93 bool usesVFPU; 94 bool foundInSymbolMap; 95 char name[64]; 96 }; 97 98 struct ReplacementTableEntry; 99 100 void Reset(); 101 102 bool IsRegisterUsed(u32 reg, u32 addr); 103 // This will not only create a database of "AnalyzedFunction" structs, it also 104 // will insert all the functions it finds into the symbol map, if insertSymbols is true. 105 106 // If we have loaded symbols from the elf, we'll register functions as they are touched 107 // so that we don't just dump them all in the cache. 108 void RegisterFunction(u32 startAddr, u32 size, const char *name); 109 // Returns new insertSymbols value for FinalizeScan(). 110 bool ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols); 111 void FinalizeScan(bool insertSymbols); 112 void ForgetFunctions(u32 startAddr, u32 endAddr); 113 void PrecompileFunctions(); 114 void PrecompileFunction(u32 startAddr, u32 length); 115 116 void SetHashMapFilename(const std::string& filename = ""); 117 void LoadBuiltinHashMap(); 118 void LoadHashMap(const Path &filename); 119 void StoreHashMap(Path filename = Path()); 120 121 const char *LookupHash(u64 hash, u32 funcSize); 122 void ReplaceFunctions(); 123 124 void UpdateHashMap(); 125 void ApplyHashMap(); 126 127 std::vector<MIPSGPReg> GetInputRegs(MIPSOpcode op); 128 std::vector<MIPSGPReg> GetOutputRegs(MIPSOpcode op); 129 130 MIPSGPReg GetOutGPReg(MIPSOpcode op); 131 bool ReadsFromGPReg(MIPSOpcode op, MIPSGPReg reg); 132 bool IsDelaySlotNiceReg(MIPSOpcode branchOp, MIPSOpcode op, MIPSGPReg reg1, MIPSGPReg reg2 = MIPS_REG_ZERO); 133 bool IsDelaySlotNiceVFPU(MIPSOpcode branchOp, MIPSOpcode op); 134 bool IsDelaySlotNiceFPU(MIPSOpcode branchOp, MIPSOpcode op); 135 bool IsSyscall(MIPSOpcode op); 136 137 bool OpWouldChangeMemory(u32 pc, u32 addr, u32 size); 138 int OpMemoryAccessSize(u32 pc); 139 bool IsOpMemoryWrite(u32 pc); 140 bool OpHasDelaySlot(u32 pc); 141 142 typedef struct { 143 DebugInterface* cpu; 144 u32 opcodeAddress; 145 MIPSOpcode encodedOpcode; 146 147 // shared between branches and conditional moves 148 bool isConditional; 149 bool conditionMet; 150 151 // branches 152 u32 branchTarget; 153 bool isBranch; 154 bool isLinkedBranch; 155 bool isLikelyBranch; 156 bool isBranchToRegister; 157 int branchRegisterNum; 158 159 // data access 160 bool isDataAccess; 161 int dataSize; 162 u32 dataAddress; 163 164 bool hasRelevantAddress; 165 u32 relevantAddress; 166 } MipsOpcodeInfo; 167 168 MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address); 169 170 } // namespace MIPSAnalyst 171