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.cpp
Views: 1401
1
#include "Common/CommonFuncs.h"
2
#include "Common/Log.h"
3
#include "Core/MIPS/IR/IRInst.h"
4
#include "Core/MIPS/MIPSDebugInterface.h"
5
#include "Core/HLE/ReplaceTables.h"
6
7
// Legend
8
// ======================
9
// _ = ignore
10
// G = GPR register
11
// C = 32-bit constant from array
12
// c = 8-bit constant from array
13
// I = immediate value from instruction
14
// F = FPR register, single
15
// V = FPR register, Vec4. Reg number always divisible by 4.
16
// 2 = FPR register, Vec2 (uncommon)
17
// v = Vec4Init constant, chosen by immediate
18
// s = Shuffle immediate (4 2-bit fields, choosing a xyzw shuffle)
19
// r = Replacement function (in constant field)
20
//
21
// WARNING: The IRJit compiler also uses these letters for semantic information!
22
// So if you add new letters, don't forget to add them to IRNativeRegCacheBase::MappingFromInst.
23
24
static const IRMeta irMeta[] = {
25
{ IROp::Nop, "Nop", "" },
26
{ IROp::SetConst, "SetConst", "GC" },
27
{ IROp::SetConstF, "SetConstF", "FC" },
28
{ IROp::Mov, "Mov", "GG" },
29
{ IROp::Add, "Add", "GGG" },
30
{ IROp::Sub, "Sub", "GGG" },
31
{ IROp::Neg, "Neg", "GG" },
32
{ IROp::Not, "Not", "GG" },
33
{ IROp::And, "And", "GGG" },
34
{ IROp::Or, "Or", "GGG" },
35
{ IROp::Xor, "Xor", "GGG" },
36
{ IROp::AddConst, "AddConst", "GGC" },
37
{ IROp::OptAddConst, "OptAddConst", "GC" },
38
{ IROp::SubConst, "SubConst", "GGC" },
39
{ IROp::AndConst, "AndConst", "GGC" },
40
{ IROp::OrConst, "OrConst", "GGC" },
41
{ IROp::XorConst, "XorConst", "GGC" },
42
{ IROp::OptAndConst, "OptAndConst", "GC" },
43
{ IROp::OptOrConst, "OptOrConst", "GC" },
44
{ IROp::Shl, "Shl", "GGG" },
45
{ IROp::Shr, "Shr", "GGG" },
46
{ IROp::Sar, "Sar", "GGG" },
47
{ IROp::Ror, "Ror", "GGG" },
48
{ IROp::ShlImm, "ShlImm", "GGI" },
49
{ IROp::ShrImm, "ShrImm", "GGI" },
50
{ IROp::SarImm, "SarImm", "GGI" },
51
{ IROp::RorImm, "RorImm", "GGI" },
52
{ IROp::Slt, "Slt", "GGG" },
53
{ IROp::SltConst, "SltConst", "GGC" },
54
{ IROp::SltU, "SltU", "GGG" },
55
{ IROp::SltUConst, "SltUConst", "GGC" },
56
{ IROp::Clz, "Clz", "GG" },
57
{ IROp::MovZ, "MovZ", "GGG", IRFLAG_SRC3DST },
58
{ IROp::MovNZ, "MovNZ", "GGG", IRFLAG_SRC3DST },
59
{ IROp::Max, "Max", "GGG" },
60
{ IROp::Min, "Min", "GGG" },
61
{ IROp::BSwap16, "BSwap16", "GG" },
62
{ IROp::BSwap32, "BSwap32", "GG" },
63
{ IROp::Mult, "Mult", "_GG" },
64
{ IROp::MultU, "MultU", "_GG" },
65
{ IROp::Madd, "Madd", "_GG" },
66
{ IROp::MaddU, "MaddU", "_GG" },
67
{ IROp::Msub, "Msub", "_GG" },
68
{ IROp::MsubU, "MsubU", "_GG" },
69
{ IROp::Div, "Div", "_GG" },
70
{ IROp::DivU, "DivU", "_GG" },
71
{ IROp::MtLo, "MtLo", "_G" },
72
{ IROp::MtHi, "MtHi", "_G" },
73
{ IROp::MfLo, "MfLo", "G" },
74
{ IROp::MfHi, "MfHi", "G" },
75
{ IROp::Ext8to32, "Ext8to32", "GG" },
76
{ IROp::Ext16to32, "Ext16to32", "GG" },
77
{ IROp::ReverseBits, "ReverseBits", "GG" },
78
{ IROp::Load8, "Load8", "GGC" },
79
{ IROp::Load8Ext, "Load8", "GGC" },
80
{ IROp::Load16, "Load16", "GGC" },
81
{ IROp::Load16Ext, "Load16Ext", "GGC" },
82
{ IROp::Load32, "Load32", "GGC" },
83
{ IROp::Load32Left, "Load32Left", "GGC", IRFLAG_SRC3DST },
84
{ IROp::Load32Right, "Load32Right", "GGC", IRFLAG_SRC3DST },
85
{ IROp::Load32Linked, "Load32Linked", "GGC" },
86
{ IROp::LoadFloat, "LoadFloat", "FGC" },
87
{ IROp::LoadVec4, "LoadVec4", "VGC" },
88
{ IROp::Store8, "Store8", "GGC", IRFLAG_SRC3 },
89
{ IROp::Store16, "Store16", "GGC", IRFLAG_SRC3 },
90
{ IROp::Store32, "Store32", "GGC", IRFLAG_SRC3 },
91
{ IROp::Store32Left, "Store32Left", "GGC", IRFLAG_SRC3 },
92
{ IROp::Store32Right, "Store32Right", "GGC", IRFLAG_SRC3 },
93
{ IROp::Store32Conditional, "Store32Conditional", "GGC", IRFLAG_SRC3DST },
94
{ IROp::StoreFloat, "StoreFloat", "FGC", IRFLAG_SRC3 },
95
{ IROp::StoreVec4, "StoreVec4", "VGC", IRFLAG_SRC3 },
96
{ IROp::FAdd, "FAdd", "FFF" },
97
{ IROp::FSub, "FSub", "FFF" },
98
{ IROp::FMul, "FMul", "FFF" },
99
{ IROp::FDiv, "FDiv", "FFF" },
100
{ IROp::FMin, "FMin", "FFF" },
101
{ IROp::FMax, "FMax", "FFF" },
102
{ IROp::FMov, "FMov", "FF" },
103
{ IROp::FSqrt, "FSqrt", "FF" },
104
{ IROp::FSin, "FSin", "FF" },
105
{ IROp::FCos, "FCos", "FF" },
106
{ IROp::FSqrt, "FSqrt", "FF" },
107
{ IROp::FRSqrt, "FRSqrt", "FF" },
108
{ IROp::FRecip, "FRecip", "FF" },
109
{ IROp::FAsin, "FAsin", "FF" },
110
{ IROp::FNeg, "FNeg", "FF" },
111
{ IROp::FSign, "FSign", "FF" },
112
{ IROp::FAbs, "FAbs", "FF" },
113
{ IROp::FRound, "FRound", "FF" },
114
{ IROp::FTrunc, "FTrunc", "FF" },
115
{ IROp::FCeil, "FCeil", "FF" },
116
{ IROp::FFloor, "FFloor", "FF" },
117
{ IROp::FCvtWS, "FCvtWS", "FF" },
118
{ IROp::FCvtSW, "FCvtSW", "FF" },
119
{ IROp::FCvtScaledWS, "FCvtScaledWS", "FFI" },
120
{ IROp::FCvtScaledSW, "FCvtScaledSW", "FFI" },
121
{ IROp::FCmp, "FCmp", "mFF" },
122
{ IROp::FSat0_1, "FSat(0 - 1)", "FF" },
123
{ IROp::FSatMinus1_1, "FSat(-1 - 1)", "FF" },
124
{ IROp::FMovFromGPR, "FMovFromGPR", "FG" },
125
{ IROp::FMovToGPR, "FMovToGPR", "GF" },
126
{ IROp::OptFMovToGPRShr8, "OptFMovToGPRShr8", "GF" },
127
{ IROp::OptFCvtSWFromGPR, "OptFCvtSWFromGPR", "FG" },
128
{ IROp::FpCondFromReg, "FpCondFromReg", "_G" },
129
{ IROp::FpCondToReg, "FpCondToReg", "G" },
130
{ IROp::FpCtrlFromReg, "FpCtrlFromReg", "_G" },
131
{ IROp::FpCtrlToReg, "FpCtrlToReg", "G" },
132
{ IROp::VfpuCtrlToReg, "VfpuCtrlToReg", "GT" },
133
{ IROp::SetCtrlVFPU, "SetCtrlVFPU", "TC" },
134
{ IROp::SetCtrlVFPUReg, "SetCtrlVFPUReg", "TG" },
135
{ IROp::SetCtrlVFPUFReg, "SetCtrlVFPUFReg", "TF" },
136
{ IROp::FCmovVfpuCC, "FCmovVfpuCC", "FFI", IRFLAG_SRC3DST },
137
{ IROp::FCmpVfpuBit, "FCmpVfpuBit", "IFF" },
138
{ IROp::FCmpVfpuAggregate, "FCmpVfpuAggregate", "I" },
139
{ IROp::Vec4Init, "Vec4Init", "Vv" },
140
{ IROp::Vec4Shuffle, "Vec4Shuffle", "VVs" },
141
{ IROp::Vec4Blend, "Vec4Blend", "VVVc" },
142
{ IROp::Vec4Mov, "Vec4Mov", "VV" },
143
{ IROp::Vec4Add, "Vec4Add", "VVV" },
144
{ IROp::Vec4Sub, "Vec4Sub", "VVV" },
145
{ IROp::Vec4Div, "Vec4Div", "VVV" },
146
{ IROp::Vec4Mul, "Vec4Mul", "VVV" },
147
{ IROp::Vec4Scale, "Vec4Scale", "VVF" },
148
{ IROp::Vec4Dot, "Vec4Dot", "FVV" },
149
{ IROp::Vec4Neg, "Vec4Neg", "VV" },
150
{ IROp::Vec4Abs, "Vec4Abs", "VV" },
151
152
// Pack/Unpack
153
{ IROp::Vec2Unpack16To31, "Vec2Unpack16To31", "2F" }, // Note that the result is shifted down by 1, hence 31
154
{ IROp::Vec2Unpack16To32, "Vec2Unpack16To32", "2F" },
155
{ IROp::Vec4Unpack8To32, "Vec4Unpack8To32", "VF" },
156
{ IROp::Vec4DuplicateUpperBitsAndShift1, "Vec4DuplicateUpperBitsAndShift1", "VV" },
157
158
{ IROp::Vec4ClampToZero, "Vec4ClampToZero", "VV" },
159
{ IROp::Vec2ClampToZero, "Vec2ClampToZero", "22" },
160
{ IROp::Vec4Pack32To8, "Vec4Pack32To8", "FV" },
161
{ IROp::Vec4Pack31To8, "Vec4Pack31To8", "FV" },
162
{ IROp::Vec2Pack32To16, "Vec2Pack32To16", "F2" },
163
{ IROp::Vec2Pack31To16, "Vec2Pack31To16", "F2" },
164
165
{ IROp::Interpret, "Interpret", "_C", IRFLAG_BARRIER },
166
{ IROp::Downcount, "Downcount", "_C" },
167
{ IROp::ExitToPC, "ExitToPC", "", IRFLAG_EXIT },
168
{ IROp::ExitToConst, "Exit", "C", IRFLAG_EXIT },
169
{ IROp::ExitToConstIfEq, "ExitIfEq", "CGG", IRFLAG_EXIT },
170
{ IROp::ExitToConstIfNeq, "ExitIfNeq", "CGG", IRFLAG_EXIT },
171
{ IROp::ExitToConstIfGtZ, "ExitIfGtZ", "CG", IRFLAG_EXIT },
172
{ IROp::ExitToConstIfGeZ, "ExitIfGeZ", "CG", IRFLAG_EXIT },
173
{ IROp::ExitToConstIfLeZ, "ExitIfLeZ", "CG", IRFLAG_EXIT },
174
{ IROp::ExitToConstIfLtZ, "ExitIfLtZ", "CG", IRFLAG_EXIT },
175
{ IROp::ExitToReg, "ExitToReg", "_G", IRFLAG_EXIT },
176
{ IROp::Syscall, "Syscall", "_C", IRFLAG_EXIT },
177
{ IROp::Break, "Break", "", IRFLAG_EXIT },
178
{ IROp::SetPC, "SetPC", "_G" },
179
{ IROp::SetPCConst, "SetPC", "_C" },
180
{ IROp::CallReplacement, "CallRepl", "Gr", IRFLAG_BARRIER },
181
{ IROp::Breakpoint, "Breakpoint", "_C", IRFLAG_BARRIER },
182
{ IROp::MemoryCheck, "MemoryCheck", "IGC", IRFLAG_BARRIER },
183
184
{ IROp::ValidateAddress8, "ValidAddr8", "_GC", IRFLAG_BARRIER },
185
{ IROp::ValidateAddress16, "ValidAddr16", "_GC", IRFLAG_BARRIER },
186
{ IROp::ValidateAddress32, "ValidAddr32", "_GC", IRFLAG_BARRIER },
187
{ IROp::ValidateAddress128, "ValidAddr128", "_GC", IRFLAG_BARRIER },
188
189
{ IROp::RestoreRoundingMode, "RestoreRoundingMode", "" },
190
{ IROp::ApplyRoundingMode, "ApplyRoundingMode", "" },
191
{ IROp::UpdateRoundingMode, "UpdateRoundingMode", "" },
192
193
{ IROp::LogIRBlock, "LogIRBlock", "" },
194
};
195
196
const IRMeta *metaIndex[256];
197
198
// Is there a way to constexpr this?
199
void InitIR() {
200
if (metaIndex[0])
201
return;
202
for (size_t i = 0; i < ARRAY_SIZE(irMeta); i++) {
203
metaIndex[(int)irMeta[i].op] = &irMeta[i];
204
}
205
}
206
207
void IRWriter::Write(IROp op, u8 dst, u8 src1, u8 src2) {
208
IRInst inst;
209
inst.op = op;
210
inst.dest = dst;
211
inst.src1 = src1;
212
inst.src2 = src2;
213
inst.constant = nextConst_;
214
insts_.push_back(inst);
215
216
nextConst_ = 0;
217
}
218
219
void IRWriter::WriteSetConstant(u8 dst, u32 value) {
220
Write(IROp::SetConst, dst, AddConstant(value));
221
}
222
223
int IRWriter::AddConstant(u32 value) {
224
nextConst_ = value;
225
return 255;
226
}
227
228
int IRWriter::AddConstantFloat(float value) {
229
u32 val;
230
memcpy(&val, &value, 4);
231
return AddConstant(val);
232
}
233
234
void IRWriter::ReplaceConstant(size_t instNumber, u32 newConstant) {
235
_dbg_assert_(instNumber < insts_.size());
236
insts_[instNumber].constant = newConstant;
237
}
238
239
static std::string GetGPRName(int r) {
240
if (r < 32) {
241
return currentDebugMIPS->GetRegName(0, r);
242
}
243
switch (r) {
244
case IRTEMP_0: return "irtemp0";
245
case IRTEMP_1: return "irtemp1";
246
case IRTEMP_2: return "irtemp2";
247
case IRTEMP_3: return "irtemp3";
248
case IRTEMP_LHS: return "irtemp_lhs";
249
case IRTEMP_RHS: return "irtemp_rhs";
250
case IRTEMP_LR_ADDR: return "irtemp_addr";
251
case IRTEMP_LR_VALUE: return "irtemp_value";
252
case IRTEMP_LR_MASK: return "irtemp_mask";
253
case IRTEMP_LR_SHIFT: return "irtemp_shift";
254
default: return "(unk)";
255
}
256
}
257
258
void DisassembleParam(char *buf, int bufSize, u8 param, char type, u32 constant) {
259
static const char * const vfpuCtrlNames[VFPU_CTRL_MAX] = {
260
"SPFX",
261
"TPFX",
262
"DPFX",
263
"CC",
264
"INF4",
265
"RSV5",
266
"RSV6",
267
"REV",
268
"RCX0",
269
"RCX1",
270
"RCX2",
271
"RCX3",
272
"RCX4",
273
"RCX5",
274
"RCX6",
275
"RCX7",
276
};
277
static const char * const initVec4Names[8] = {
278
"[0 0 0 0]",
279
"[1 1 1 1]",
280
"[-1 -1 -1 -1]",
281
"[1 0 0 0]",
282
"[0 1 0 0]",
283
"[0 0 1 0]",
284
"[0 0 0 1]",
285
};
286
static const char * const xyzw = "xyzw";
287
288
switch (type) {
289
case 'G':
290
snprintf(buf, bufSize, "%s", GetGPRName(param).c_str());
291
break;
292
case 'F':
293
if (param >= 32) {
294
snprintf(buf, bufSize, "vf%d", param - 32);
295
} else {
296
snprintf(buf, bufSize, "f%d", param);
297
}
298
break;
299
case 'V':
300
if (param >= 32) {
301
snprintf(buf, bufSize, "vf%d..vf%d", param - 32, param - 32 + 3);
302
} else {
303
snprintf(buf, bufSize, "f%d..f%d", param, param + 3);
304
}
305
break;
306
case '2':
307
if (param >= 32) {
308
snprintf(buf, bufSize, "vf%d,vf%d", param - 32, param - 32 + 1);
309
} else {
310
snprintf(buf, bufSize, "f%d,f%d", param, param + 1);
311
}
312
break;
313
case 'C':
314
snprintf(buf, bufSize, "0x%08x", constant);
315
break;
316
case 'c':
317
snprintf(buf, bufSize, "0x%02x", constant);
318
break;
319
case 'I':
320
snprintf(buf, bufSize, "0x%02x", param);
321
break;
322
case 'm':
323
snprintf(buf, bufSize, "%d", param);
324
break;
325
case 'T':
326
snprintf(buf, bufSize, "%s", vfpuCtrlNames[param]);
327
break;
328
case 'v':
329
snprintf(buf, bufSize, "%s", initVec4Names[param]);
330
break;
331
case 's':
332
snprintf(buf, bufSize, "%c%c%c%c", xyzw[param & 3], xyzw[(param >> 2) & 3], xyzw[(param >> 4) & 3], xyzw[(param >> 6) & 3]);
333
break;
334
case 'r':
335
{
336
const ReplacementTableEntry *entry = GetReplacementFunc(constant);
337
if (entry) {
338
snprintf(buf, bufSize, "%s", entry->name);
339
} else {
340
snprintf(buf, bufSize, "(unkn. repl %d)", constant);
341
}
342
break;
343
}
344
case '_':
345
case '\0':
346
buf[0] = 0;
347
break;
348
default:
349
snprintf(buf, bufSize, "?");
350
break;
351
}
352
}
353
354
const IRMeta *GetIRMeta(IROp op) {
355
return metaIndex[(int)op];
356
}
357
358
void DisassembleIR(char *buf, size_t bufsize, IRInst inst) {
359
const IRMeta *meta = GetIRMeta(inst.op);
360
if (!meta) {
361
snprintf(buf, bufsize, "Unknown %d", (int)inst.op);
362
return;
363
}
364
char bufDst[16];
365
char bufSrc1[16];
366
char bufSrc2[16];
367
// Only really used for constant.
368
char bufSrc3[16];
369
DisassembleParam(bufDst, sizeof(bufDst) - 2, inst.dest, meta->types[0], inst.constant);
370
DisassembleParam(bufSrc1, sizeof(bufSrc1) - 2, inst.src1, meta->types[1], inst.constant);
371
DisassembleParam(bufSrc2, sizeof(bufSrc2), inst.src2, meta->types[2], inst.constant);
372
DisassembleParam(bufSrc3, sizeof(bufSrc3), inst.src3, meta->types[3], inst.constant);
373
if (meta->types[1] && meta->types[0] != '_') {
374
strcat(bufDst, ", ");
375
}
376
if (meta->types[2] && meta->types[1] != '_') {
377
strcat(bufSrc1, ", ");
378
}
379
if (meta->types[3] && meta->types[2] != '_') {
380
strcat(bufSrc2, ", ");
381
}
382
snprintf(buf, bufsize, "%s %s%s%s%s", meta->name, bufDst, bufSrc1, bufSrc2, bufSrc3);
383
}
384
385