Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/MIPS/IR/IRJit.h
3188 views
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 <cstring>
21
#include <unordered_map>
22
23
#include "Common/CommonTypes.h"
24
#include "Common/CPUDetect.h"
25
#include "Core/MIPS/JitCommon/JitBlockCache.h"
26
#include "Core/MIPS/JitCommon/JitCommon.h"
27
#include "Core/MIPS/IR/IRRegCache.h"
28
#include "Core/MIPS/IR/IRInst.h"
29
#include "Core/MIPS/IR/IRFrontend.h"
30
#include "Core/MIPS/MIPSVFPUUtils.h"
31
32
#ifndef offsetof
33
#include "stddef.h"
34
#endif
35
36
// Very expensive, time-profiles every block.
37
// Not to be released with this enabled.
38
//
39
// #define IR_PROFILING
40
41
// Try to catch obvious misses of be above rule.
42
#if defined(IR_PROFILING) && defined(GOLD)
43
#error
44
#endif
45
46
namespace MIPSComp {
47
48
// TODO : Use arena allocators. For now let's just malloc.
49
class IRBlock {
50
public:
51
IRBlock() {}
52
IRBlock(u32 emAddr, u32 origSize, int instOffset, u32 numInstructions)
53
: origAddr_(emAddr), origSize_(origSize), arenaOffset_(instOffset), numIRInstructions_(numInstructions) {}
54
IRBlock(IRBlock &&b) noexcept {
55
arenaOffset_ = b.arenaOffset_;
56
hash_ = b.hash_;
57
origAddr_ = b.origAddr_;
58
origSize_ = b.origSize_;
59
origFirstOpcode_ = b.origFirstOpcode_;
60
nativeOffset_ = b.nativeOffset_;
61
numIRInstructions_ = b.numIRInstructions_;
62
b.arenaOffset_ = 0xFFFFFFFF;
63
}
64
65
~IRBlock() {}
66
67
u32 GetIRArenaOffset() const { return arenaOffset_; }
68
int GetNumIRInstructions() const { return numIRInstructions_; }
69
MIPSOpcode GetOriginalFirstOp() const { return origFirstOpcode_; }
70
bool HasOriginalFirstOp() const;
71
bool RestoreOriginalFirstOp(int number);
72
bool IsValid() const { return origAddr_ != 0 && origFirstOpcode_.encoding != 0x68FFFFFF; }
73
void SetNativeOffset(int offset) {
74
nativeOffset_ = offset;
75
}
76
int GetNativeOffset() const {
77
return nativeOffset_;
78
}
79
void UpdateHash() {
80
hash_ = CalculateHash();
81
}
82
bool HashMatches() const {
83
return origAddr_ && hash_ == CalculateHash();
84
}
85
bool OverlapsRange(u32 addr, u32 size) const;
86
87
void GetRange(u32 *start, u32 *size) const {
88
*start = origAddr_;
89
*size = origSize_;
90
}
91
u32 GetOriginalStart() const {
92
return origAddr_;
93
}
94
u64 GetHash() const {
95
return hash_;
96
}
97
98
void Finalize(int number);
99
void Destroy(int number);
100
101
#ifdef IR_PROFILING
102
JitBlockProfileStats profileStats_{};
103
#endif
104
105
private:
106
u64 CalculateHash() const;
107
108
// Offset into the block cache's Arena
109
u32 arenaOffset_ = 0;
110
// Offset into the native code buffer.
111
int nativeOffset_ = -1;
112
u64 hash_ = 0;
113
u32 origAddr_ = 0;
114
u32 origSize_ = 0;
115
MIPSOpcode origFirstOpcode_ = MIPSOpcode(0x68FFFFFF);
116
u32 numIRInstructions_ = 0;
117
};
118
119
class IRBlockCache : public JitBlockCacheDebugInterface {
120
public:
121
IRBlockCache(bool compileToNative);
122
~IRBlockCache() {
123
Clear();
124
}
125
126
void Clear();
127
std::vector<int> FindInvalidatedBlockNumbers(u32 address, u32 length);
128
void FinalizeBlock(int blockNum);
129
int GetNumBlocks() const override { return (int)blocks_.size(); }
130
int AllocateBlock(int emAddr, u32 origSize, const std::vector<IRInst> &inst);
131
IRBlock *GetBlock(int blockNum) {
132
if (blockNum >= 0 && blockNum < (int)blocks_.size()) {
133
return &blocks_[blockNum];
134
} else {
135
return nullptr;
136
}
137
}
138
void RemoveBlockFromPageLookup(int blockNum);
139
int GetBlockNumFromIRArenaOffset(int offset) const;
140
const IRInst *GetBlockInstructionPtr(const IRBlock &block) const {
141
return arena_.data() + block.GetIRArenaOffset();
142
}
143
const IRInst *GetBlockInstructionPtr(int blockNum) const {
144
return arena_.data() + blocks_[blockNum].GetIRArenaOffset();
145
}
146
const IRInst *GetArenaPtr() const {
147
return arena_.data();
148
}
149
bool IsValidBlock(int blockNum) const override {
150
return blockNum >= 0 && blockNum < (int)blocks_.size() && blocks_[blockNum].IsValid();
151
}
152
IRBlock *GetBlockUnchecked(int blockNum) {
153
return &blocks_[blockNum];
154
}
155
const IRBlock *GetBlock(int blockNum) const {
156
if (blockNum >= 0 && blockNum < (int)blocks_.size()) {
157
return &blocks_[blockNum];
158
} else {
159
return nullptr;
160
}
161
}
162
163
int FindPreloadBlock(u32 em_address);
164
165
// "Cookie" means the 24 bits we inject into the first instruction of each block.
166
int FindByCookie(int cookie);
167
168
std::vector<u32> SaveAndClearEmuHackOps();
169
void RestoreSavedEmuHackOps(const std::vector<u32> &saved);
170
171
JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override;
172
JitBlockMeta GetBlockMeta(int blockNum) const override {
173
JitBlockMeta meta{};
174
if (IsValidBlock(blockNum)) {
175
meta.valid = true;
176
blocks_[blockNum].GetRange(&meta.addr, &meta.sizeInBytes);
177
}
178
return meta;
179
}
180
JitBlockProfileStats GetBlockProfileStats(int blockNum) const override {
181
#ifdef IR_PROFILING
182
return blocks_[blockNum].profileStats_;
183
#else
184
return JitBlockProfileStats{};
185
#endif
186
}
187
void ComputeStats(BlockCacheStats &bcStats) const override;
188
int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override;
189
190
bool SupportsProfiling() const override {
191
#ifdef IR_PROFILING
192
return true;
193
#else
194
return false;
195
#endif
196
}
197
198
private:
199
u32 AddressToPage(u32 addr) const;
200
bool compileToNative_;
201
std::vector<IRBlock> blocks_;
202
std::vector<IRInst> arena_;
203
std::unordered_map<u32, std::vector<int>> byPage_;
204
};
205
206
class IRJit : public JitInterface {
207
public:
208
IRJit(MIPSState *mipsState, bool actualJit);
209
~IRJit();
210
211
void DoState(PointerWrap &p) override;
212
213
const JitOptions &GetJitOptions() { return jo; }
214
215
void RunLoopUntil(u64 globalticks) override;
216
217
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
218
219
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
220
// Not using a regular block cache.
221
JitBlockCache *GetBlockCache() override { return nullptr; }
222
JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks_; }
223
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
224
225
std::vector<u32> SaveAndClearEmuHackOps() override { return blocks_.SaveAndClearEmuHackOps(); }
226
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks_.RestoreSavedEmuHackOps(saved); }
227
228
void ClearCache() override;
229
void InvalidateCacheAt(u32 em_address, int length = 4) override;
230
void UpdateFCR31() override;
231
232
bool CodeInRange(const u8 *ptr) const override {
233
return false;
234
}
235
236
const u8 *GetDispatcher() const override { return nullptr; }
237
const u8 *GetCrashHandler() const override { return nullptr; }
238
239
void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override;
240
void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override;
241
242
protected:
243
bool CompileBlock(u32 em_address, std::vector<IRInst> &instructions, u32 &mipsBytes);
244
virtual bool CompileNativeBlock(IRBlockCache *irBlockCache, int block_num) { return true; }
245
virtual void FinalizeNativeBlock(IRBlockCache *irBlockCache, int block_num) {}
246
247
bool compileToNative_;
248
249
JitOptions jo;
250
251
IRFrontend frontend_;
252
IRBlockCache blocks_;
253
254
MIPSState *mips_;
255
256
bool compilerEnabled_ = true;
257
258
// where to write branch-likely trampolines. not used atm
259
// u32 blTrampolines_;
260
// int blTrampolineCount_;
261
};
262
263
} // namespace MIPSComp
264
265