mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-10 01:24:41 -06:00
239 lines
6.8 KiB
C++
239 lines
6.8 KiB
C++
#include "util/Zir/Core/IR.h"
|
|
#include "util/Zir/Core/ZpIRDebug.h"
|
|
|
|
#include <cinttypes>
|
|
|
|
namespace ZpIR
|
|
{
|
|
|
|
const char* getOpcodeName(IR::OpCode opcode)
|
|
{
|
|
switch (opcode)
|
|
{
|
|
case IR::OpCode::ADD:
|
|
return "ADD";
|
|
case IR::OpCode::MOV:
|
|
return "MOV";
|
|
case IR::OpCode::MUL:
|
|
return "MUL";
|
|
case IR::OpCode::DIV:
|
|
return "DIV";
|
|
|
|
case IR::OpCode::BITCAST:
|
|
return "BITCAST";
|
|
case IR::OpCode::SWAP_ENDIAN:
|
|
return "SWAP_ENDIAN";
|
|
case IR::OpCode::CONVERT_INT_TO_FLOAT:
|
|
return "CONV_I2F";
|
|
case IR::OpCode::CONVERT_FLOAT_TO_INT:
|
|
return "CONV_F2I";
|
|
|
|
case IR::OpCode::IMPORT_SINGLE:
|
|
return "IMPORT_S";
|
|
case IR::OpCode::EXPORT:
|
|
return "EXPORT";
|
|
case IR::OpCode::IMPORT:
|
|
return "IMPORT";
|
|
default:
|
|
cemu_assert_debug(false);
|
|
return "UKN";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
const char* getTypeName(DataType t)
|
|
{
|
|
switch (t)
|
|
{
|
|
case DataType::S64:
|
|
return "s64";
|
|
case DataType::U64:
|
|
return "u64";
|
|
case DataType::S32:
|
|
return "s32";
|
|
case DataType::U32:
|
|
return "u32";
|
|
case DataType::S16:
|
|
return "s16";
|
|
case DataType::U16:
|
|
return "u16";
|
|
case DataType::S8:
|
|
return "s8";
|
|
case DataType::U8:
|
|
return "u8";
|
|
case DataType::BOOL:
|
|
return "bool";
|
|
case DataType::POINTER:
|
|
return "ptr";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
std::string DebugPrinter::getRegisterName(ZpIRBasicBlock* block, IRReg r)
|
|
{
|
|
std::string s;
|
|
|
|
if ((uint16)r < 0x8000 && m_showPhysicalRegisters)
|
|
{
|
|
auto& reg = block->m_regs[(uint16)r];
|
|
if (!reg.hasAssignedPhysicalRegister())
|
|
return "UNASSIGNED";
|
|
s = m_getPhysicalRegisterNameCustom(block, reg.physicalRegister);
|
|
return s;
|
|
}
|
|
|
|
if ((uint16)r < 0x8000 && m_getRegisterNameCustom)
|
|
{
|
|
return m_getRegisterNameCustom(block, r);
|
|
}
|
|
|
|
if ((uint16)r >= 0x8000)
|
|
{
|
|
auto& reg = block->m_consts[(uint16)r & 0x7FFF];
|
|
switch (reg.type)
|
|
{
|
|
case DataType::POINTER:
|
|
return fmt::format("ptr:{}", reg.value_ptr);
|
|
case DataType::U64:
|
|
{
|
|
if(reg.value_u64 >= 0x1000)
|
|
return fmt::format("u64:0x{0:x}", reg.value_u64);
|
|
return fmt::format("u64:{}", reg.value_u64);
|
|
}
|
|
case DataType::U32:
|
|
return fmt::format("u32:{}", reg.value_u32);
|
|
case DataType::S32:
|
|
return fmt::format("s32:{}", reg.value_u32);
|
|
case DataType::F32:
|
|
return fmt::format("f32:{}", reg.value_f32);
|
|
default:
|
|
break;
|
|
}
|
|
return "ukn_const_type";
|
|
}
|
|
else
|
|
{
|
|
auto& reg = block->m_regs[(uint16)r];
|
|
|
|
const char* regLetter = "r";
|
|
switch (reg.type)
|
|
{
|
|
case DataType::U64:
|
|
regLetter = "uq"; // quad-word
|
|
break;
|
|
case DataType::U32:
|
|
regLetter = "ud"; // double-word
|
|
break;
|
|
case DataType::U16:
|
|
regLetter = "uw"; // word
|
|
break;
|
|
case DataType::U8:
|
|
regLetter = "uc"; // char
|
|
break;
|
|
case DataType::S64:
|
|
regLetter = "sq"; // signed quad-word
|
|
break;
|
|
case DataType::S32:
|
|
regLetter = "sd"; // signed double-word
|
|
break;
|
|
case DataType::S16:
|
|
regLetter = "sw"; // signed word
|
|
break;
|
|
case DataType::S8:
|
|
regLetter = "sc"; // signed char
|
|
break;
|
|
case DataType::F32:
|
|
regLetter = "fv"; // 32bit float
|
|
break;
|
|
case DataType::POINTER:
|
|
regLetter = "ptr";
|
|
break;
|
|
default:
|
|
assert_dbg();
|
|
}
|
|
if (reg.elementCount != 1)
|
|
assert_dbg();
|
|
s = fmt::format("{}{}", regLetter, (uint16)r);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
std::string DebugPrinter::getInstructionHRF(ZpIRBasicBlock* block, IR::__InsBase* cmd)
|
|
{
|
|
if (auto ins = IR::InsRR::getIfForm(cmd))
|
|
{
|
|
return fmt::format("{:<10} {}, {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->rA), getRegisterName(block, ins->rB));
|
|
}
|
|
else if (auto ins = IR::InsRRR::getIfForm(cmd))
|
|
{
|
|
return fmt::format("{:<10} {}, {}, {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->rA), getRegisterName(block, ins->rB), getRegisterName(block, ins->rC));
|
|
}
|
|
else if (auto ins = IR::InsEXPORT::getIfForm(cmd))
|
|
{
|
|
if (ins->count == 4)
|
|
return fmt::format("{:<10} {}, {}, {}, {}, loc: {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), getRegisterName(block, ins->regArray[2]), getRegisterName(block, ins->regArray[3]), ins->exportSymbol);
|
|
else if (ins->count == 3)
|
|
return fmt::format("{:<10} {}, {}, {}, loc: {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), getRegisterName(block, ins->regArray[2]), ins->exportSymbol);
|
|
else if (ins->count == 2)
|
|
return fmt::format("{:<10} {}, {}, loc: {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), ins->exportSymbol);
|
|
else if (ins->count == 1)
|
|
return fmt::format("{:<10} {}, loc: {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), ins->exportSymbol);
|
|
assert_dbg();
|
|
}
|
|
else if (auto ins = IR::InsIMPORT::getIfForm(cmd))
|
|
{
|
|
ShaderSubset::ShaderImportLocation importLocation = ins->importSymbol;
|
|
std::string locDebugName = importLocation.GetDebugName();
|
|
|
|
if (ins->count == 4)
|
|
return fmt::format("{:<10} {}, {}, {}, {}, loc: {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), getRegisterName(block, ins->regArray[2]), getRegisterName(block, ins->regArray[3]), locDebugName);
|
|
else if (ins->count == 3)
|
|
return fmt::format("{:<10} {}, {}, {}, loc: {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), getRegisterName(block, ins->regArray[2]), locDebugName);
|
|
else if (ins->count == 2)
|
|
return fmt::format("{:<10} {}, {}, loc: {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), locDebugName);
|
|
else if (ins->count == 1)
|
|
return fmt::format("{:<10} {}, loc: {}", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), locDebugName);
|
|
assert_dbg();
|
|
}
|
|
else
|
|
assert_dbg();
|
|
return "";
|
|
}
|
|
|
|
void DebugPrinter::debugPrintBlock(ZpIRBasicBlock* block)
|
|
{
|
|
// print name
|
|
printf("IRBasicBlock %" PRIxPTR "\n", (uintptr_t)block);
|
|
// print imports
|
|
printf("Imports:\n");
|
|
for(auto itr : block->m_imports)
|
|
printf(" reg: %s sym:0x%lux\n", getRegisterName(block, itr.reg).c_str(), itr.name);
|
|
// print exports
|
|
printf("Exports:\n");
|
|
for (auto itr : block->m_exports)
|
|
printf(" reg: %s sym:0x%lux\n", getRegisterName(block, itr.reg).c_str(), itr.name);
|
|
// print instructions
|
|
printf("Assembly:\n");
|
|
IR::__InsBase* instruction = block->m_instructionFirst;
|
|
size_t i = 0;
|
|
while(instruction)
|
|
{
|
|
std::string s = getInstructionHRF(block, instruction);
|
|
printf("%04x %s\n", (unsigned int)i, s.c_str());
|
|
i++;
|
|
instruction = instruction->next;
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::debugPrint(ZpIRFunction* irFunction)
|
|
{
|
|
printf("--- Print IR function assembly ---\n");
|
|
for (auto& itr : irFunction->m_basicBlocks)
|
|
{
|
|
debugPrintBlock(itr);
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
}
|