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