-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
Jit.h
277 lines (215 loc) · 8.76 KB
/
Jit.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// ========================
// See comments in Jit.cpp.
// ========================
// Mystery: Capcom vs SNK 800aa278
// CR flags approach:
// * Store that "N+Z flag contains CR0" or "S+Z flag contains CR3".
// * All flag altering instructions flush this
// * A flush simply does a conditional write to the appropriate CRx.
// * If flag available, branch code can become absolutely trivial.
// Settings
// ----------
#pragma once
#include <rangeset/rangesizeset.h>
#include "Common/CommonTypes.h"
#include "Common/x64ABI.h"
#include "Common/x64Emitter.h"
#include "Core/PowerPC/Jit64/JitAsm.h"
#include "Core/PowerPC/Jit64/RegCache/FPURegCache.h"
#include "Core/PowerPC/Jit64/RegCache/GPRRegCache.h"
#include "Core/PowerPC/Jit64/RegCache/JitRegCache.h"
#include "Core/PowerPC/Jit64Common/BlockCache.h"
#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h"
#include "Core/PowerPC/Jit64Common/TrampolineCache.h"
#include "Core/PowerPC/JitCommon/JitBase.h"
#include "Core/PowerPC/JitCommon/JitCache.h"
namespace PPCAnalyst
{
struct CodeBlock;
struct CodeOp;
} // namespace PPCAnalyst
class Jit64 : public JitBase, public QuantizedMemoryRoutines
{
public:
Jit64();
~Jit64() override;
void Init() override;
void Shutdown() override;
bool HandleFault(uintptr_t access_address, SContext* ctx) override;
bool HandleStackFault() override;
bool BackPatch(u32 emAddress, SContext* ctx);
void EnableOptimization();
void EnableBlockLink();
// Jit!
void Jit(u32 em_address) override;
void Jit(u32 em_address, bool clear_cache_and_retry_on_failure);
bool DoJit(u32 em_address, JitBlock* b, u32 nextPC);
// Finds a free memory region and sets the near and far code emitters to point at that region.
// Returns false if no free memory region can be found for either of the two.
bool SetEmitterStateToFreeCodeRegion();
BitSet32 CallerSavedRegistersInUse() const;
BitSet8 ComputeStaticGQRs(const PPCAnalyst::CodeBlock&) const;
void IntializeSpeculativeConstants();
JitBlockCache* GetBlockCache() override { return &blocks; }
void Trace();
void ClearCache() override;
const CommonAsmRoutines* GetAsmRoutines() override { return &asm_routines; }
const char* GetName() const override { return "JIT64"; }
// Run!
void Run() override;
void SingleStep() override;
// Utilities for use by opcodes
void FakeBLCall(u32 after);
void WriteExit(u32 destination, bool bl = false, u32 after = 0);
void JustWriteExit(u32 destination, bool bl, u32 after);
void WriteExitDestInRSCRATCH(bool bl = false, u32 after = 0);
void WriteBLRExit();
void WriteExceptionExit();
void WriteExternalExceptionExit();
void WriteRfiExitDestInRSCRATCH();
void WriteIdleExit(u32 destination);
bool Cleanup();
void GenerateConstantOverflow(bool overflow);
void GenerateConstantOverflow(s64 val);
void GenerateOverflow(Gen::CCFlags cond = Gen::CCFlags::CC_NO);
void FinalizeCarryOverflow(bool oe, bool inv = false);
void FinalizeCarry(Gen::CCFlags cond);
void FinalizeCarry(bool ca);
void ComputeRC(preg_t preg, bool needs_test = true, bool needs_sext = true);
void AndWithMask(Gen::X64Reg reg, u32 mask);
void RotateLeft(int bits, Gen::X64Reg regOp, const Gen::OpArg& arg, u8 rotate);
bool CheckMergedBranch(u32 crf) const;
void DoMergedBranch();
void DoMergedBranchCondition();
void DoMergedBranchImmediate(s64 val);
// Reads a given bit of a given CR register part.
void GetCRFieldBit(int field, int bit, Gen::X64Reg out, bool negate = false);
// Clobbers RDX.
void SetCRFieldBit(int field, int bit, Gen::X64Reg in);
void ClearCRFieldBit(int field, int bit);
void SetCRFieldBit(int field, int bit);
void FixGTBeforeSettingCRFieldBit(Gen::X64Reg reg);
// Generates a branch that will check if a given bit of a CR register part
// is set or not.
Gen::FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set = true);
void SetFPRFIfNeeded(const Gen::OpArg& xmm, bool single);
void FinalizeSingleResult(Gen::X64Reg output, const Gen::OpArg& input, bool packed = true,
bool duplicate = false);
void FinalizeDoubleResult(Gen::X64Reg output, const Gen::OpArg& input);
void HandleNaNs(UGeckoInstruction inst, Gen::X64Reg xmm_out, Gen::X64Reg xmm_in,
Gen::X64Reg clobber);
void MultiplyImmediate(u32 imm, int a, int d, bool overflow);
typedef u32 (*Operation)(u32 a, u32 b);
void regimmop(int d, int a, bool binary, u32 value, Operation doop,
void (Gen::XEmitter::*op)(int, const Gen::OpArg&, const Gen::OpArg&),
bool Rc = false, bool carry = false);
void FloatCompare(UGeckoInstruction inst, bool upper = false);
void UpdateMXCSR();
// OPCODES
using Instruction = void (Jit64::*)(UGeckoInstruction instCode);
void FallBackToInterpreter(UGeckoInstruction _inst);
void DoNothing(UGeckoInstruction _inst);
void HLEFunction(u32 hook_index);
void DynaRunTable4(UGeckoInstruction inst);
void DynaRunTable19(UGeckoInstruction inst);
void DynaRunTable31(UGeckoInstruction inst);
void DynaRunTable59(UGeckoInstruction inst);
void DynaRunTable63(UGeckoInstruction inst);
void addx(UGeckoInstruction inst);
void arithcx(UGeckoInstruction inst);
void mulli(UGeckoInstruction inst);
void mulhwXx(UGeckoInstruction inst);
void mullwx(UGeckoInstruction inst);
void divwux(UGeckoInstruction inst);
void divwx(UGeckoInstruction inst);
void srawix(UGeckoInstruction inst);
void srawx(UGeckoInstruction inst);
void arithXex(UGeckoInstruction inst);
void extsXx(UGeckoInstruction inst);
void sc(UGeckoInstruction _inst);
void rfi(UGeckoInstruction _inst);
void bx(UGeckoInstruction inst);
void bclrx(UGeckoInstruction _inst);
void bcctrx(UGeckoInstruction _inst);
void bcx(UGeckoInstruction inst);
void mtspr(UGeckoInstruction inst);
void mfspr(UGeckoInstruction inst);
void mtmsr(UGeckoInstruction inst);
void mfmsr(UGeckoInstruction inst);
void mftb(UGeckoInstruction inst);
void mtcrf(UGeckoInstruction inst);
void mfcr(UGeckoInstruction inst);
void mcrf(UGeckoInstruction inst);
void mcrxr(UGeckoInstruction inst);
void mcrfs(UGeckoInstruction inst);
void mffsx(UGeckoInstruction inst);
void mtfsb0x(UGeckoInstruction inst);
void mtfsb1x(UGeckoInstruction inst);
void mtfsfix(UGeckoInstruction inst);
void mtfsfx(UGeckoInstruction inst);
void boolX(UGeckoInstruction inst);
void crXXX(UGeckoInstruction inst);
void reg_imm(UGeckoInstruction inst);
void ps_mr(UGeckoInstruction inst);
void ps_mergeXX(UGeckoInstruction inst);
void ps_res(UGeckoInstruction inst);
void ps_rsqrte(UGeckoInstruction inst);
void ps_sum(UGeckoInstruction inst);
void ps_muls(UGeckoInstruction inst);
void ps_cmpXX(UGeckoInstruction inst);
void fp_arith(UGeckoInstruction inst);
void fcmpX(UGeckoInstruction inst);
void fctiwx(UGeckoInstruction inst);
void fmrx(UGeckoInstruction inst);
void frspx(UGeckoInstruction inst);
void frsqrtex(UGeckoInstruction inst);
void fresx(UGeckoInstruction inst);
void cmpXX(UGeckoInstruction inst);
void cntlzwx(UGeckoInstruction inst);
void lfXXX(UGeckoInstruction inst);
void stfXXX(UGeckoInstruction inst);
void stfiwx(UGeckoInstruction inst);
void psq_lXX(UGeckoInstruction inst);
void psq_stXX(UGeckoInstruction inst);
void fmaddXX(UGeckoInstruction inst);
void fsign(UGeckoInstruction inst);
void fselx(UGeckoInstruction inst);
void stX(UGeckoInstruction inst); // stw sth stb
void rlwinmx(UGeckoInstruction inst);
void rlwimix(UGeckoInstruction inst);
void rlwnmx(UGeckoInstruction inst);
void negx(UGeckoInstruction inst);
void slwx(UGeckoInstruction inst);
void srwx(UGeckoInstruction inst);
void dcbt(UGeckoInstruction inst);
void dcbz(UGeckoInstruction inst);
void subfic(UGeckoInstruction inst);
void subfx(UGeckoInstruction inst);
void twX(UGeckoInstruction inst);
void lXXx(UGeckoInstruction inst);
void stXx(UGeckoInstruction inst);
void lmw(UGeckoInstruction inst);
void stmw(UGeckoInstruction inst);
void dcbx(UGeckoInstruction inst);
void eieio(UGeckoInstruction inst);
private:
void CompileInstruction(PPCAnalyst::CodeOp& op);
bool HandleFunctionHooking(u32 address);
void AllocStack();
void FreeStack();
void ResetFreeMemoryRanges();
JitBlockCache blocks{*this};
TrampolineCache trampolines{*this};
GPRRegCache gpr{*this};
FPURegCache fpr{*this};
Jit64AsmRoutineManager asm_routines{*this};
bool m_enable_blr_optimization;
bool m_cleanup_after_stackfault;
u8* m_stack;
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_near;
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_far;
};
void LogGeneratedX86(size_t size, const PPCAnalyst::CodeBuffer& code_buffer, const u8* normalEntry,
const JitBlock* b);