dolphin/Source/Core/Core/PowerPC/PPCTables.cpp
Scott Mansell 23b54117cd GetOpInfo: Assert on all invalid Ops.
GetOpInfo was returning null pointers for invalid ops in subtables
instead of asserting an error. This was causing segfaults when the
jit tried to jit invalid code.
2014-09-06 20:09:30 +12:00

251 lines
5.6 KiB
C++

// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <algorithm>
#include <cinttypes>
#include <vector>
#include "Common/Common.h"
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/PPCTables.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/Interpreter/Interpreter_Tables.h"
GekkoOPInfo *m_infoTable[64];
GekkoOPInfo *m_infoTable4[1024];
GekkoOPInfo *m_infoTable19[1024];
GekkoOPInfo *m_infoTable31[1024];
GekkoOPInfo *m_infoTable59[32];
GekkoOPInfo *m_infoTable63[1024];
GekkoOPInfo *m_allInstructions[512];
int m_numInstructions;
const u64 m_crTable[16] =
{
PPCCRToInternal(0x0), PPCCRToInternal(0x1), PPCCRToInternal(0x2), PPCCRToInternal(0x3),
PPCCRToInternal(0x4), PPCCRToInternal(0x5), PPCCRToInternal(0x6), PPCCRToInternal(0x7),
PPCCRToInternal(0x8), PPCCRToInternal(0x9), PPCCRToInternal(0xA), PPCCRToInternal(0xB),
PPCCRToInternal(0xC), PPCCRToInternal(0xD), PPCCRToInternal(0xE), PPCCRToInternal(0xF),
};
GekkoOPInfo *GetOpInfo(UGeckoInstruction _inst)
{
GekkoOPInfo *info = m_infoTable[_inst.OPCD];
if ((info->type & 0xFFFFFF) == OPTYPE_SUBTABLE)
{
int table = info->type>>24;
switch (table)
{
case 4: info = m_infoTable4[_inst.SUBOP10]; break;
case 19: info = m_infoTable19[_inst.SUBOP10]; break;
case 31: info = m_infoTable31[_inst.SUBOP10]; break;
case 59: info = m_infoTable59[_inst.SUBOP5]; break;
case 63: info = m_infoTable63[_inst.SUBOP10]; break;
default:
_assert_msg_(POWERPC,0,"GetOpInfo - invalid subtable op %08x @ %08x", _inst.hex, PC);
return nullptr;
}
}
if ((info->type & 0xFFFFFF) == OPTYPE_INVALID)
{
_assert_msg_(POWERPC,0,"GetOpInfo - invalid op %08x @ %08x", _inst.hex, PC);
return nullptr;
}
return info;
}
Interpreter::_interpreterInstruction GetInterpreterOp(UGeckoInstruction _inst)
{
const GekkoOPInfo *info = m_infoTable[_inst.OPCD];
if ((info->type & 0xFFFFFF) == OPTYPE_SUBTABLE)
{
int table = info->type>>24;
switch (table)
{
case 4: return Interpreter::m_opTable4[_inst.SUBOP10];
case 19: return Interpreter::m_opTable19[_inst.SUBOP10];
case 31: return Interpreter::m_opTable31[_inst.SUBOP10];
case 59: return Interpreter::m_opTable59[_inst.SUBOP5];
case 63: return Interpreter::m_opTable63[_inst.SUBOP10];
default:
_assert_msg_(POWERPC,0,"GetInterpreterOp - invalid subtable op %08x @ %08x", _inst.hex, PC);
return nullptr;
}
}
else
{
if ((info->type & 0xFFFFFF) == OPTYPE_INVALID)
{
_assert_msg_(POWERPC,0,"GetInterpreterOp - invalid op %08x @ %08x", _inst.hex, PC);
return nullptr;
}
return Interpreter::m_opTable[_inst.OPCD];
}
}
namespace PPCTables
{
bool UsesFPU(UGeckoInstruction _inst)
{
switch (_inst.OPCD)
{
case 04: // PS
return _inst.SUBOP10 != 1014;
case 48: // lfs
case 49: // lfsu
case 50: // lfd
case 51: // lfdu
case 52: // stfs
case 53: // stfsu
case 54: // stfd
case 55: // stfdu
case 56: // psq_l
case 57: // psq_lu
case 59: // FPU-sgl
case 60: // psq_st
case 61: // psq_stu
case 63: // FPU-dbl
return true;
case 31:
switch (_inst.SUBOP10)
{
case 535:
case 567:
case 599:
case 631:
case 663:
case 695:
case 727:
case 759:
case 983:
return true;
default:
return false;
}
default:
return false;
}
}
void InitTables(int cpu_core)
{
// Interpreter ALWAYS needs to be initialized
InterpreterTables::InitTables();
switch (cpu_core)
{
case 0:
{
// Interpreter
break;
}
default:
{
JitInterface::InitTables(cpu_core);
break;
}
}
}
#define OPLOG
#define OP_TO_LOG "mtfsb0x"
#ifdef OPLOG
namespace {
std::vector<u32> rsplocations;
}
#endif
const char *GetInstructionName(UGeckoInstruction _inst)
{
const GekkoOPInfo *info = GetOpInfo(_inst);
return info ? info->opname : nullptr;
}
bool IsValidInstruction(UGeckoInstruction _inst)
{
const GekkoOPInfo *info = GetOpInfo(_inst);
return info != nullptr;
}
void CountInstruction(UGeckoInstruction _inst)
{
GekkoOPInfo *info = GetOpInfo(_inst);
if (info)
{
info->runCount++;
}
}
void PrintInstructionRunCounts()
{
typedef std::pair<const char*, u64> OpInfo;
std::vector<OpInfo> temp;
temp.reserve(m_numInstructions);
for (int i = 0; i < m_numInstructions; ++i)
{
GekkoOPInfo *pInst = m_allInstructions[i];
temp.emplace_back(pInst->opname, pInst->runCount);
}
std::sort(temp.begin(), temp.end(),
[](const OpInfo &a, const OpInfo &b)
{
return a.second > b.second;
});
for (auto &inst : temp)
{
if (inst.second == 0)
break;
DEBUG_LOG(POWERPC, "%s : %" PRIu64, inst.first, inst.second);
//PanicAlert("%s : %llu", inst.first, inst.second);
}
}
void LogCompiledInstructions()
{
static unsigned int time = 0;
File::IOFile f(StringFromFormat("%sinst_log%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w");
for (int i = 0; i < m_numInstructions; i++)
{
GekkoOPInfo *pInst = m_allInstructions[i];
if (pInst->compileCount > 0)
{
fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\t%08x\n", pInst->opname,
pInst->compileCount, pInst->runCount, pInst->lastUse);
}
}
f.Open(StringFromFormat("%sinst_not%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w");
for (int i = 0; i < m_numInstructions; i++)
{
GekkoOPInfo *pInst = m_allInstructions[i];
if (pInst->compileCount == 0)
{
fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\n", pInst->opname,
pInst->compileCount, pInst->runCount);
}
}
#ifdef OPLOG
f.Open(StringFromFormat("%s" OP_TO_LOG "_at%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w");
for (auto& rsplocation : rsplocations)
{
fprintf(f.GetHandle(), OP_TO_LOG ": %08x\n", rsplocation);
}
#endif
++time;
}
} // namespace