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