mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-14 12:00:43 +02:00
Changes the IR register class definition to exist in the JSON file. Removes a couple of IR ops that were unused and weren't necessary. Changes the CPUID IR op to the new paired op which improves perf ever so slightly. Changes RA class handling in the RA pass to pull directly from the new generated helper routine until it hits a complex op Still need RA constraints to remove extraneous moves that would crop up
188 lines
5.3 KiB
C++
188 lines
5.3 KiB
C++
#include <FEXCore/IR/IR.h>
|
|
#include <FEXCore/IR/IntrusiveIRList.h>
|
|
#include "LogManager.h"
|
|
|
|
namespace FEXCore::IR {
|
|
#define IROP_GETNAME_IMPL
|
|
#define IROP_GETRAARGS_IMPL
|
|
#define IROP_REG_CLASSES_IMPL
|
|
|
|
#include <FEXCore/IR/IRDefines.inc>
|
|
|
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, uint64_t Arg) {
|
|
*out << "0x" << std::hex << Arg;
|
|
}
|
|
|
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, CondClassType Arg) {
|
|
std::array<std::string, 14> CondNames = {
|
|
"EQ",
|
|
"NEQ",
|
|
"UGE",
|
|
"ULT",
|
|
"MI",
|
|
"PL",
|
|
"VS",
|
|
"VC",
|
|
"UGT",
|
|
"ULE",
|
|
"SGE",
|
|
"SLT",
|
|
"SGT",
|
|
"SLE",
|
|
};
|
|
|
|
*out << CondNames[Arg];
|
|
}
|
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, RegisterClassType Arg) {
|
|
if (Arg == 0)
|
|
*out << "GPR";
|
|
else if (Arg == 1)
|
|
*out << "FPR";
|
|
else if (Arg == 2)
|
|
*out << "GPRPair";
|
|
else
|
|
*out << "Unknown Registerclass " << Arg;
|
|
}
|
|
|
|
static void PrintArg(std::stringstream *out, IRListView<false> const* IR, OrderedNodeWrapper Arg) {
|
|
uintptr_t Data = IR->GetData();
|
|
uintptr_t ListBegin = IR->GetListData();
|
|
|
|
OrderedNode *RealNode = Arg.GetNode(ListBegin);
|
|
auto IROp = RealNode->Op(Data);
|
|
|
|
*out << "%ssa" << std::to_string(Arg.ID()) << " i" << std::dec << (IROp->Size * 8);
|
|
if (IROp->Elements > 1) {
|
|
*out << "v" << std::dec << (uint32_t)IROp->Elements;
|
|
}
|
|
}
|
|
|
|
void Dump(std::stringstream *out, IRListView<false> const* IR) {
|
|
uintptr_t ListBegin = IR->GetListData();
|
|
uintptr_t DataBegin = IR->GetData();
|
|
|
|
auto Begin = IR->begin();
|
|
auto Op = Begin();
|
|
|
|
OrderedNode *RealNode = Op->GetNode(ListBegin);
|
|
auto HeaderOp = RealNode->Op(DataBegin)->CW<FEXCore::IR::IROp_IRHeader>();
|
|
LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
|
|
|
|
OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin);
|
|
int8_t CurrentIndent = 0;
|
|
auto AddIndent = [&out, &CurrentIndent]() {
|
|
for (uint8_t i = 0; i < CurrentIndent; ++i) {
|
|
*out << "\t";
|
|
}
|
|
};
|
|
|
|
++CurrentIndent;
|
|
AddIndent();
|
|
*out << "(%%ssa" << std::to_string(RealNode->Wrapped(ListBegin).ID()) << ") " << "IRHeader ";
|
|
*out << "0x" << std::hex << HeaderOp->Entry << ", ";
|
|
*out << "%%ssa" << HeaderOp->Blocks.ID() << ", ";
|
|
*out << std::dec << HeaderOp->BlockCount << std::endl;
|
|
|
|
while (1) {
|
|
auto BlockIROp = BlockNode->Op(DataBegin)->CW<FEXCore::IR::IROp_CodeBlock>();
|
|
LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
|
|
|
|
// We grab these nodes this way so we can iterate easily
|
|
auto CodeBegin = IR->at(BlockIROp->Begin);
|
|
auto CodeLast = IR->at(BlockIROp->Last);
|
|
|
|
AddIndent();
|
|
*out << "(%%ssa" << std::to_string(BlockNode->Wrapped(ListBegin).ID()) << ") " << "CodeBlock ";
|
|
|
|
*out << "%%ssa" << std::to_string(BlockIROp->Begin.ID()) << ", ";
|
|
*out << "%%ssa" << std::to_string(BlockIROp->Last.ID()) << ", ";
|
|
*out << "%%ssa" << std::to_string(BlockIROp->Next.ID()) << std::endl;
|
|
|
|
++CurrentIndent;
|
|
while (1) {
|
|
OrderedNodeWrapper *CodeOp = CodeBegin();
|
|
OrderedNode *CodeNode = CodeOp->GetNode(ListBegin);
|
|
auto IROp = CodeNode->Op(DataBegin);
|
|
|
|
auto Name = FEXCore::IR::GetName(IROp->Op);
|
|
bool Skip{};
|
|
switch (IROp->Op) {
|
|
case IR::OP_PHIVALUE:
|
|
Skip = true;
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
if (!Skip) {
|
|
AddIndent();
|
|
if (IROp->HasDest) {
|
|
*out << "%ssa" << std::to_string(CodeOp->ID()) << " i" << std::dec << (IROp->Size * 8);
|
|
if (IROp->Elements > 1) {
|
|
*out << "v" << std::dec << (uint32_t)IROp->Elements;
|
|
}
|
|
*out << " = ";
|
|
}
|
|
else {
|
|
*out << "(%%ssa" << std::to_string(CodeOp->ID()) << ") ";
|
|
}
|
|
*out << Name;
|
|
switch (IROp->Op) {
|
|
case IR::OP_BEGINBLOCK:
|
|
*out << " %ssa" << std::to_string(CodeOp->ID());
|
|
break;
|
|
case IR::OP_ENDBLOCK:
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
#define IROP_ARGPRINTER_HELPER
|
|
#include <FEXCore/IR/IRDefines.inc>
|
|
case IR::OP_PHI: {
|
|
auto Op = IROp->C<IR::IROp_Phi>();
|
|
auto NodeBegin = IR->at(Op->PhiBegin);
|
|
*out << " ";
|
|
|
|
while (NodeBegin != NodeBegin.Invalid()) {
|
|
OrderedNodeWrapper *NodeOp = NodeBegin();
|
|
OrderedNode *NodeNode = NodeOp->GetNode(ListBegin);
|
|
auto IRNodeOp = NodeNode->Op(DataBegin)->C<IR::IROp_PhiValue>();
|
|
*out << "[ ";
|
|
PrintArg(out, IR, IRNodeOp->Value);
|
|
*out << ", ";
|
|
PrintArg(out, IR, IRNodeOp->Block);
|
|
*out << " ]";
|
|
|
|
if (IRNodeOp->Next.ID())
|
|
*out << ", ";
|
|
|
|
NodeBegin = IR->at(IRNodeOp->Next);
|
|
}
|
|
break;
|
|
}
|
|
default: *out << "<Unknown Args>"; break;
|
|
}
|
|
|
|
//*out << " (" << std::dec << CodeNode->GetUses() << ")";
|
|
|
|
*out << "\n";
|
|
}
|
|
|
|
// CodeLast is inclusive. So we still need to dump the CodeLast op as well
|
|
if (CodeBegin == CodeLast) {
|
|
break;
|
|
}
|
|
++CodeBegin;
|
|
}
|
|
|
|
CurrentIndent = std::max(0, CurrentIndent - 1);
|
|
|
|
if (BlockIROp->Next.ID() == 0) {
|
|
break;
|
|
} else {
|
|
BlockNode = BlockIROp->Next.GetNode(ListBegin);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|