CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/MIPS/IR/IRJit.h
Views: 1401
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) {
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
123
void Clear();
124
std::vector<int> FindInvalidatedBlockNumbers(u32 address, u32 length);
125
void FinalizeBlock(int blockNum, bool preload = false);
126
int GetNumBlocks() const override { return (int)blocks_.size(); }
127
int AllocateBlock(int emAddr, u32 origSize, const std::vector<IRInst> &inst);
128
IRBlock *GetBlock(int blockNum) {
129
if (blockNum >= 0 && blockNum < (int)blocks_.size()) {
130
return &blocks_[blockNum];
131
} else {
132
return nullptr;
133
}
134
}
135
void RemoveBlockFromPageLookup(int blockNum);
136
int GetBlockNumFromIRArenaOffset(int offset) const;
137
const IRInst *GetBlockInstructionPtr(const IRBlock &block) const {
138
return arena_.data() + block.GetIRArenaOffset();
139
}
140
const IRInst *GetBlockInstructionPtr(int blockNum) const {
141
return arena_.data() + blocks_[blockNum].GetIRArenaOffset();
142
}
143
const IRInst *GetArenaPtr() const {
144
return arena_.data();
145
}
146
bool IsValidBlock(int blockNum) const override {
147
return blockNum >= 0 && blockNum < (int)blocks_.size() && blocks_[blockNum].IsValid();
148
}
149
IRBlock *GetBlockUnchecked(int blockNum) {
150
return &blocks_[blockNum];
151
}
152
const IRBlock *GetBlock(int blockNum) const {
153
if (blockNum >= 0 && blockNum < (int)blocks_.size()) {
154
return &blocks_[blockNum];
155
} else {
156
return nullptr;
157
}
158
}
159
160
int FindPreloadBlock(u32 em_address);
161
162
// "Cookie" means the 24 bits we inject into the first instruction of each block.
163
int FindByCookie(int cookie);
164
165
std::vector<u32> SaveAndClearEmuHackOps();
166
void RestoreSavedEmuHackOps(const std::vector<u32> &saved);
167
168
JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override;
169
JitBlockMeta GetBlockMeta(int blockNum) const override {
170
JitBlockMeta meta{};
171
if (IsValidBlock(blockNum)) {
172
meta.valid = true;
173
blocks_[blockNum].GetRange(&meta.addr, &meta.sizeInBytes);
174
}
175
return meta;
176
}
177
JitBlockProfileStats GetBlockProfileStats(int blockNum) const override {
178
#ifdef IR_PROFILING
179
return blocks_[blockNum].profileStats_;
180
#else
181
return JitBlockProfileStats{};
182
#endif
183
}
184
void ComputeStats(BlockCacheStats &bcStats) const override;
185
int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override;
186
187
bool SupportsProfiling() const override {
188
#ifdef IR_PROFILING
189
return true;
190
#else
191
return false;
192
#endif
193
}
194
195
private:
196
u32 AddressToPage(u32 addr) const;
197
bool compileToNative_;
198
std::vector<IRBlock> blocks_;
199
std::vector<IRInst> arena_;
200
std::unordered_map<u32, std::vector<int>> byPage_;
201
};
202
203
class IRJit : public JitInterface {
204
public:
205
IRJit(MIPSState *mipsState, bool actualJit);
206
~IRJit();
207
208
void DoState(PointerWrap &p) override;
209
210
const JitOptions &GetJitOptions() { return jo; }
211
212
void RunLoopUntil(u64 globalticks) override;
213
214
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
215
void CompileFunction(u32 start_address, u32 length) override;
216
217
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
218
// Not using a regular block cache.
219
JitBlockCache *GetBlockCache() override { return nullptr; }
220
JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks_; }
221
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
222
223
std::vector<u32> SaveAndClearEmuHackOps() override { return blocks_.SaveAndClearEmuHackOps(); }
224
void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks_.RestoreSavedEmuHackOps(saved); }
225
226
void ClearCache() override;
227
void InvalidateCacheAt(u32 em_address, int length = 4) override;
228
void UpdateFCR31() override;
229
230
bool CodeInRange(const u8 *ptr) const override {
231
return false;
232
}
233
234
const u8 *GetDispatcher() const override { return nullptr; }
235
const u8 *GetCrashHandler() const override { return nullptr; }
236
237
void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override;
238
void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override;
239
240
protected:
241
bool CompileBlock(u32 em_address, std::vector<IRInst> &instructions, u32 &mipsBytes, bool preload);
242
virtual bool CompileNativeBlock(IRBlockCache *irBlockCache, int block_num, bool preload) { return true; }
243
virtual void FinalizeNativeBlock(IRBlockCache *irBlockCache, int block_num) {}
244
245
bool compileToNative_;
246
247
JitOptions jo;
248
249
IRFrontend frontend_;
250
IRBlockCache blocks_;
251
252
MIPSState *mips_;
253
254
bool compilerEnabled_ = true;
255
256
// where to write branch-likely trampolines. not used atm
257
// u32 blTrampolines_;
258
// int blTrampolineCount_;
259
};
260
261
} // namespace MIPSComp
262
263