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