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