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/IRInst.h
Views: 1401
1
#pragma once
2
3
#include <cstdint>
4
#include <vector>
5
#include <utility>
6
7
#include "Common/CommonTypes.h"
8
#include "Core/MIPS/MIPS.h"
9
10
// Basic IR
11
//
12
// This IR refers implicitly to the MIPS register set and is simple to interpret.
13
// To do real compiler things with it and do full-function compilation, it probably
14
// needs to be lifted to a higher IR first, before being lowered onto each target.
15
// But this gets rid of a lot of MIPS idiosyncrasies that makes it tricky, like
16
// delay slots, and is very suitable for translation into other IRs. Can of course
17
// even be directly JIT-ed, but the gains will probably be tiny over our older direct
18
// MIPS->target JITs.
19
20
// Ops beginning with "OI" are specialized for IR Interpreter use. These will not be produced
21
// for the IR JITs.
22
23
enum class IROp : uint8_t {
24
SetConst,
25
SetConstF,
26
27
Mov,
28
29
Add,
30
Sub,
31
Neg,
32
Not,
33
34
And,
35
Or,
36
Xor,
37
38
AddConst,
39
OptAddConst,
40
SubConst,
41
42
AndConst,
43
OrConst,
44
XorConst,
45
OptAndConst,
46
OptOrConst,
47
48
Shl,
49
Shr,
50
Sar,
51
Ror,
52
53
// The shift is stored directly, not in the const table, so Imm instead of Const
54
ShlImm,
55
ShrImm,
56
SarImm,
57
RorImm,
58
59
Slt,
60
SltConst,
61
SltU,
62
SltUConst,
63
64
Clz,
65
66
// Conditional moves
67
MovZ,
68
MovNZ,
69
70
Max,
71
Min,
72
73
// Byte swaps. All CPUs have native ones so worth keeping.
74
BSwap16, // Swaps both the high and low byte pairs.
75
BSwap32,
76
77
// Weird Hi/Lo semantics preserved. Too annoying to do something more generic.
78
MtLo,
79
MtHi,
80
MfLo,
81
MfHi,
82
Mult,
83
MultU,
84
Madd,
85
MaddU,
86
Msub,
87
MsubU,
88
Div,
89
DivU,
90
91
// These take a constant from the pool as an offset.
92
// Loads from a constant address can be represented by using r0.
93
Load8,
94
Load8Ext,
95
Load16,
96
Load16Ext,
97
Load32,
98
Load32Left,
99
Load32Right,
100
Load32Linked,
101
LoadFloat,
102
LoadVec4,
103
104
Store8,
105
Store16,
106
Store32,
107
Store32Left,
108
Store32Right,
109
Store32Conditional,
110
StoreFloat,
111
StoreVec4,
112
113
Ext8to32,
114
Ext16to32,
115
ReverseBits,
116
117
FAdd,
118
FSub,
119
FMul,
120
FDiv,
121
FMin,
122
FMax,
123
124
FMov,
125
FSqrt,
126
FNeg,
127
FAbs,
128
FSign,
129
130
FRound,
131
FTrunc,
132
FCeil,
133
FFloor,
134
135
FCvtWS,
136
FCvtSW,
137
FCvtScaledWS,
138
FCvtScaledSW,
139
140
FMovFromGPR,
141
OptFCvtSWFromGPR,
142
FMovToGPR,
143
OptFMovToGPRShr8,
144
145
FSat0_1,
146
FSatMinus1_1,
147
148
FpCondFromReg,
149
FpCondToReg,
150
FpCtrlFromReg,
151
FpCtrlToReg,
152
VfpuCtrlToReg,
153
154
FCmp,
155
156
FCmovVfpuCC,
157
FCmpVfpuBit,
158
FCmpVfpuAggregate,
159
160
// Rounding Mode
161
RestoreRoundingMode,
162
ApplyRoundingMode,
163
UpdateRoundingMode,
164
165
SetCtrlVFPU,
166
SetCtrlVFPUReg,
167
SetCtrlVFPUFReg,
168
169
// 4-wide instructions to assist SIMD.
170
// Can of course add a pass to break them up if a target does not
171
// support SIMD.
172
Vec4Init,
173
Vec4Shuffle,
174
Vec4Blend,
175
Vec4Mov,
176
Vec4Add,
177
Vec4Sub,
178
Vec4Mul,
179
Vec4Div,
180
Vec4Scale,
181
Vec4Dot,
182
Vec4Neg,
183
Vec4Abs,
184
185
// vx2i
186
Vec2Unpack16To31, // Note that the result is shifted down by 1, hence 31
187
Vec2Unpack16To32,
188
Vec4Unpack8To32,
189
Vec4DuplicateUpperBitsAndShift1, // Bizarro vuc2i behaviour, in an instruction. Split?
190
Vec4ClampToZero,
191
Vec2ClampToZero,
192
Vec4Pack31To8,
193
Vec4Pack32To8,
194
Vec2Pack31To16,
195
Vec2Pack32To16,
196
197
// Slow special functions. Used on singles.
198
FSin,
199
FCos,
200
FRSqrt,
201
FRecip,
202
FAsin,
203
204
// Fake/System instructions
205
Interpret,
206
207
// Emit this before you exit. Semantic is to set the downcount
208
// that will be used at the actual exit.
209
Downcount, // src1 + (src2<<8)
210
211
// End-of-basic-block.
212
ExitToConst, // 0, const, downcount
213
ExitToReg,
214
ExitToConstIfEq, // const, reg1, reg2
215
ExitToConstIfNeq, // const, reg1, reg2
216
ExitToConstIfGtZ, // const, reg1, 0
217
ExitToConstIfGeZ, // const, reg1, 0
218
ExitToConstIfLtZ, // const, reg1, 0
219
ExitToConstIfLeZ, // const, reg1, 0
220
221
ExitToConstIfFpTrue,
222
ExitToConstIfFpFalse,
223
ExitToPC, // Used after a syscall to give us a way to do things before returning.
224
225
Syscall,
226
SetPC, // hack to make syscall returns work
227
SetPCConst, // hack to make replacement know PC
228
CallReplacement,
229
Break,
230
231
// Debugging breakpoints.
232
Breakpoint,
233
MemoryCheck,
234
235
ValidateAddress8,
236
ValidateAddress16,
237
ValidateAddress32,
238
ValidateAddress128,
239
240
// Tracing support.
241
LogIRBlock,
242
243
Nop,
244
Bad,
245
};
246
247
enum IRComparison {
248
Greater,
249
GreaterEqual,
250
Less,
251
LessEqual,
252
Equal,
253
NotEqual,
254
Bad,
255
};
256
257
// Some common vec4 constants.
258
enum class Vec4Init {
259
AllZERO,
260
AllONE,
261
AllMinusONE,
262
Set_1000,
263
Set_0100,
264
Set_0010,
265
Set_0001,
266
};
267
268
enum class IRRoundMode : uint8_t {
269
RINT_0 = 0,
270
CAST_1 = 1,
271
CEIL_2 = 2,
272
FLOOR_3 = 3,
273
};
274
275
// Hm, unused
276
inline IRComparison Invert(IRComparison comp) {
277
switch (comp) {
278
case IRComparison::Equal: return IRComparison::NotEqual;
279
case IRComparison::NotEqual: return IRComparison::Equal;
280
case IRComparison::Greater: return IRComparison::LessEqual;
281
case IRComparison::GreaterEqual: return IRComparison::Less;
282
case IRComparison::Less: return IRComparison::GreaterEqual;
283
case IRComparison::LessEqual: return IRComparison::Greater;
284
default:
285
return IRComparison::Bad;
286
}
287
}
288
289
inline IROp ComparisonToExit(IRComparison comp) {
290
switch (comp) {
291
case IRComparison::Equal: return IROp::ExitToConstIfEq;
292
case IRComparison::NotEqual: return IROp::ExitToConstIfNeq;
293
case IRComparison::Greater: return IROp::ExitToConstIfGtZ;
294
case IRComparison::GreaterEqual: return IROp::ExitToConstIfGeZ;
295
case IRComparison::Less: return IROp::ExitToConstIfLtZ;
296
case IRComparison::LessEqual: return IROp::ExitToConstIfLeZ;
297
default:
298
return IROp::Break;
299
}
300
}
301
302
enum IRFpCompareMode {
303
False = 0,
304
EitherUnordered,
305
EqualOrdered, // eq, seq (equal, ordered)
306
EqualUnordered, // ueq, ngl (equal, unordered)
307
LessOrdered, // olt, lt (less than, ordered)
308
LessUnordered, // ult, nge (less than, unordered)
309
LessEqualOrdered, // ole, le (less equal, ordered)
310
LessEqualUnordered, // ule, ngt (less equal, unordered)
311
};
312
313
typedef u8 IRReg;
314
315
enum : IRReg {
316
IRTEMP_0 = 192,
317
IRTEMP_1,
318
IRTEMP_2,
319
IRTEMP_3,
320
IRTEMP_LHS, // Reserved for use in branches
321
IRTEMP_RHS, // Reserved for use in branches
322
IRTEMP_LR_ADDR, // Reserved for left/right loads and stores.
323
IRTEMP_LR_VALUE, // Reserved for left/right loads and stores.
324
IRTEMP_LR_MASK, // Reserved for left/right loads and stores.
325
IRTEMP_LR_SHIFT, // Reserved for left/right loads and stores.
326
327
IRVTEMP_PFX_S = 224 - 32, // Relative to the FP regs
328
IRVTEMP_PFX_T = 228 - 32,
329
IRVTEMP_PFX_D = 232 - 32,
330
IRVTEMP_0 = 236 - 32,
331
332
// Hacky way to get to other state
333
IRREG_VFPU_CTRL_BASE = 208,
334
IRREG_VFPU_CC = 211,
335
IRREG_LO = 242, // offset of lo in MIPSState / 4
336
IRREG_HI = 243,
337
IRREG_FCR31 = 244,
338
IRREG_FPCOND = 245,
339
IRREG_LLBIT = 250,
340
};
341
342
enum IRFlags {
343
// Uses src3, not dest.
344
IRFLAG_SRC3 = 0x0001,
345
// Uses src3 AND dest (i.e. mutates dest.)
346
IRFLAG_SRC3DST = 0x0002,
347
// Exit instruction (maybe conditional.)
348
IRFLAG_EXIT = 0x0004,
349
// Instruction like Interpret which may read anything, but not an exit.
350
IRFLAG_BARRIER = 0x0008,
351
};
352
353
struct IRMeta {
354
IROp op;
355
const char *name;
356
char types[5]; // GGG
357
u32 flags;
358
};
359
360
// 64 bits.
361
struct IRInst {
362
IROp op;
363
union {
364
IRReg dest;
365
IRReg src3;
366
};
367
IRReg src1;
368
IRReg src2;
369
u32 constant;
370
};
371
372
// Returns the new PC.
373
u32 IRInterpret(MIPSState *ms, const IRInst *inst);
374
375
// Each IR block gets a constant pool.
376
class IRWriter {
377
public:
378
IRWriter &operator =(const IRWriter &w) {
379
insts_ = w.insts_;
380
return *this;
381
}
382
IRWriter &operator =(IRWriter &&w) {
383
insts_ = std::move(w.insts_);
384
return *this;
385
}
386
387
void Write(IROp op, u8 dst = 0, u8 src1 = 0, u8 src2 = 0);
388
void Write(IROp op, IRReg dst, IRReg src1, IRReg src2, uint32_t c) {
389
AddConstant(c);
390
Write(op, dst, src1, src2);
391
}
392
void Write(IRInst inst) {
393
insts_.push_back(inst);
394
}
395
void WriteSetConstant(u8 dst, u32 value);
396
397
int AddConstant(u32 value);
398
int AddConstantFloat(float value);
399
400
void Reserve(size_t s) {
401
insts_.reserve(s);
402
}
403
void Clear() {
404
insts_.clear();
405
}
406
void ReplaceConstant(size_t instNumber, u32 newConstant);
407
408
const std::vector<IRInst> &GetInstructions() const { return insts_; }
409
410
private:
411
std::vector<IRInst> insts_;
412
u32 nextConst_ = 0;
413
};
414
415
struct IROptions {
416
uint32_t disableFlags;
417
bool unalignedLoadStore;
418
bool unalignedLoadStoreVec4;
419
bool preferVec4;
420
bool preferVec4Dot;
421
bool optimizeForInterpreter;
422
};
423
424
const IRMeta *GetIRMeta(IROp op);
425
void DisassembleIR(char *buf, size_t bufsize, IRInst inst);
426
void InitIR();
427
428