PPCRec: Initial support for typed registers

This commit is contained in:
Exzap
2023-02-02 17:18:36 +01:00
parent 5d96191e00
commit cb619b143d
12 changed files with 1128 additions and 959 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -26,7 +26,7 @@ bool IMLAnalyzer_IsTightFiniteLoop(IMLSegment* imlSegment)
// for non-BDNZ loops, check for common patterns
// risky approach, look for ADD/SUB operations and assume that potential overflow means finite (does not include r_r_s32 ADD/SUB)
// this catches most loops with load-update and store-update instructions, but also those with decrementing counters
FixedSizeList<sint32, 64, true> list_modifiedRegisters;
FixedSizeList<IMLReg, 64, true> list_modifiedRegisters;
for (const IMLInstruction& instIt : imlSegment->imlList)
{
if (instIt.type == PPCREC_IML_TYPE_R_S32 && (instIt.operation == PPCREC_IML_OP_ADD || instIt.operation == PPCREC_IML_OP_SUB) )
@@ -41,20 +41,22 @@ const char* IMLDebug_GetOpcodeName(const IMLInstruction* iml)
return _tempOpcodename;
}
void IMLDebug_AppendRegisterParam(StringBuf& strOutput, sint32 virtualRegister, bool isLast = false)
void IMLDebug_AppendRegisterParam(StringBuf& strOutput, IMLReg virtualRegister, bool isLast = false)
{
uint32 regId = virtualRegister.GetRegID();
DEBUG_BREAK; // todo (print type)
if (isLast)
{
if (virtualRegister < 10)
strOutput.addFmt("t{} ", virtualRegister);
if (regId < 10)
strOutput.addFmt("t{} ", regId);
else
strOutput.addFmt("t{}", virtualRegister);
strOutput.addFmt("t{}", regId);
return;
}
if (virtualRegister < 10)
strOutput.addFmt("t{} , ", virtualRegister);
if (regId < 10)
strOutput.addFmt("t{} , ", regId);
else
strOutput.addFmt("t{}, ", virtualRegister);
strOutput.addFmt("t{}, ", regId);
}
void IMLDebug_AppendS32Param(StringBuf& strOutput, sint32 val, bool isLast = false)
@@ -147,6 +149,12 @@ std::string IMLDebug_GetConditionName(IMLCondition cond)
return "ukn";
}
std::string IMLDebug_GetRegName(IMLReg r)
{
cemu_assert_unimplemented();
return "";
}
void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool printLivenessRangeInfo)
{
StringBuf strOutput(1024);
@@ -197,7 +205,7 @@ void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool
IMLDebug_AppendRegisterParam(strOutput, inst.op_r_name.regR);
strOutput.addFmt("name_{} (", inst.op_r_name.regR, inst.op_r_name.name);
strOutput.addFmt("name_{} (", inst.op_r_name.regR.GetRegID());
if (inst.op_r_name.name >= PPCREC_NAME_R0 && inst.op_r_name.name < (PPCREC_NAME_R0 + 999))
{
strOutput.addFmt("r{}", inst.op_r_name.name - PPCREC_NAME_R0);
@@ -334,9 +342,9 @@ void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool
IMLDebug_AppendRegisterParam(strOutput, inst.op_storeLoad.registerData);
if (inst.type == PPCREC_IML_TYPE_LOAD_INDEXED || inst.type == PPCREC_IML_TYPE_STORE_INDEXED)
strOutput.addFmt("[t{}+t{}]", inst.op_storeLoad.registerMem, inst.op_storeLoad.registerMem2);
strOutput.addFmt("[t{}+t{}]", inst.op_storeLoad.registerMem.GetRegID(), inst.op_storeLoad.registerMem2.GetRegID());
else
strOutput.addFmt("[t{}+{}]", inst.op_storeLoad.registerMem, inst.op_storeLoad.immS32);
strOutput.addFmt("[t{}+{}]", inst.op_storeLoad.registerMem.GetRegID(), inst.op_storeLoad.immS32);
}
else if (inst.type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)
{
@@ -391,7 +399,7 @@ void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool
}
else if (inst.type == PPCREC_IML_TYPE_FPR_R_NAME)
{
strOutput.addFmt("fpr_t{} = name_{} (", inst.op_r_name.regR, inst.op_r_name.name);
strOutput.addFmt("fpr_t{} = name_{} (", inst.op_r_name.regR.GetRegID(), inst.op_r_name.name);
if (inst.op_r_name.name >= PPCREC_NAME_FPR0 && inst.op_r_name.name < (PPCREC_NAME_FPR0 + 999))
{
strOutput.addFmt("fpr{}", inst.op_r_name.name - PPCREC_NAME_FPR0);
@@ -417,16 +425,16 @@ void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool
}
else
strOutput.add("ukn");
strOutput.addFmt(") = fpr_t{}", inst.op_r_name.regR);
strOutput.addFmt(") = {}", IMLDebug_GetRegName(inst.op_r_name.regR));
}
else if (inst.type == PPCREC_IML_TYPE_FPR_LOAD)
{
strOutput.addFmt("fpr_t{} = ", inst.op_storeLoad.registerData);
strOutput.addFmt("{} = ", IMLDebug_GetRegName(inst.op_storeLoad.registerData));
if (inst.op_storeLoad.flags2.signExtend)
strOutput.add("S");
else
strOutput.add("U");
strOutput.addFmt("{} [t{}+{}] mode {}", inst.op_storeLoad.copyWidth / 8, inst.op_storeLoad.registerMem, inst.op_storeLoad.immS32, inst.op_storeLoad.mode);
strOutput.addFmt("{} [{}+{}] mode {}", inst.op_storeLoad.copyWidth / 8, IMLDebug_GetRegName(inst.op_storeLoad.registerMem), inst.op_storeLoad.immS32, inst.op_storeLoad.mode);
if (inst.op_storeLoad.flags2.notExpanded)
{
strOutput.addFmt(" <No expand>");
@@ -438,23 +446,23 @@ void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool
strOutput.add("S");
else
strOutput.add("U");
strOutput.addFmt("{} [t{}+{}]", inst.op_storeLoad.copyWidth / 8, inst.op_storeLoad.registerMem, inst.op_storeLoad.immS32);
strOutput.addFmt(" = fpr_t{} mode {}", inst.op_storeLoad.registerData, inst.op_storeLoad.mode);
strOutput.addFmt("{} [t{}+{}]", inst.op_storeLoad.copyWidth / 8, inst.op_storeLoad.registerMem.GetRegID(), inst.op_storeLoad.immS32);
strOutput.addFmt(" = {} mode {}", IMLDebug_GetRegName(inst.op_storeLoad.registerData), inst.op_storeLoad.mode);
}
else if (inst.type == PPCREC_IML_TYPE_FPR_R_R)
{
strOutput.addFmt("{:>6} ", IMLDebug_GetOpcodeName(&inst));
strOutput.addFmt("fpr{:02}, fpr{:02}", inst.op_fpr_r_r.regR, inst.op_fpr_r_r.regA);
strOutput.addFmt("{}, {}", IMLDebug_GetRegName(inst.op_fpr_r_r.regR), IMLDebug_GetRegName(inst.op_fpr_r_r.regA));
}
else if (inst.type == PPCREC_IML_TYPE_FPR_R_R_R_R)
{
strOutput.addFmt("{:>6} ", IMLDebug_GetOpcodeName(&inst));
strOutput.addFmt("fpr{:02}, fpr{:02}, fpr{:02}, fpr{:02}", inst.op_fpr_r_r_r_r.regR, inst.op_fpr_r_r_r_r.regA, inst.op_fpr_r_r_r_r.regB, inst.op_fpr_r_r_r_r.regC);
strOutput.addFmt("{}, {}, {}, {}", IMLDebug_GetRegName(inst.op_fpr_r_r_r_r.regR), IMLDebug_GetRegName(inst.op_fpr_r_r_r_r.regA), IMLDebug_GetRegName(inst.op_fpr_r_r_r_r.regB), IMLDebug_GetRegName(inst.op_fpr_r_r_r_r.regC));
}
else if (inst.type == PPCREC_IML_TYPE_FPR_R_R_R)
{
strOutput.addFmt("{:>6} ", IMLDebug_GetOpcodeName(&inst));
strOutput.addFmt("fpr{:02}, fpr{:02}, fpr{:02}", inst.op_fpr_r_r_r.regR, inst.op_fpr_r_r_r.regA, inst.op_fpr_r_r_r.regB);
strOutput.addFmt("{}, {}, {}", IMLDebug_GetRegName(inst.op_fpr_r_r_r.regR), IMLDebug_GetRegName(inst.op_fpr_r_r_r.regA), IMLDebug_GetRegName(inst.op_fpr_r_r_r.regB));
}
else if (inst.type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK)
{
@@ -462,7 +470,7 @@ void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool
}
else if (inst.type == PPCREC_IML_TYPE_CONDITIONAL_R_S32)
{
strOutput.addFmt("t{} ", inst.op_conditional_r_s32.regR);
strOutput.addFmt("{} ", IMLDebug_GetRegName(inst.op_conditional_r_s32.regR));
bool displayAsHex = false;
if (inst.operation == PPCREC_IML_OP_ASSIGN)
{
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,103 @@
#pragma once
using IMLReg = uint8;
inline constexpr IMLReg IMLREG_INVALID = (IMLReg)-1;
using IMLRegID = uint16; // 16 bit ID
// format of IMLReg:
// 0-15 (16 bit) IMLRegID
// 19-23 (5 bit) Offset In elements, for SIMD registers
// 24-27 (4 bit) IMLRegFormat RegFormat
// 28-31 (4 bit) IMLRegFormat BaseFormat
enum class IMLRegFormat : uint8
{
INVALID_FORMAT,
I64,
I32,
I16,
I8,
// I1 ?
F64,
F32
};
class IMLReg
{
public:
IMLReg()
{
m_raw = 0; // 0 is invalid
}
IMLReg(IMLRegFormat baseRegFormat, IMLRegFormat regFormat, uint8 viewOffset, IMLRegID regId)
{
m_raw = 0;
m_raw |= ((uint8)baseRegFormat << 28);
m_raw |= ((uint8)regFormat << 24);
m_raw |= (uint32)regId;
}
IMLReg(IMLReg&& baseReg, IMLRegFormat viewFormat, uint8 viewOffset, IMLRegID regId)
{
DEBUG_BREAK;
//m_raw = 0;
//m_raw |= ((uint8)baseRegFormat << 28);
//m_raw |= ((uint8)viewFormat << 24);
//m_raw |= (uint32)regId;
}
IMLReg(const IMLReg& other) : m_raw(other.m_raw) {}
IMLRegFormat GetBaseFormat() const
{
return (IMLRegFormat)((m_raw >> 28) & 0xF);
}
IMLRegFormat GetRegFormat() const
{
return (IMLRegFormat)((m_raw >> 24) & 0xF);
}
IMLRegID GetRegID() const
{
cemu_assert_debug(GetBaseFormat() != IMLRegFormat::INVALID_FORMAT);
cemu_assert_debug(GetRegFormat() != IMLRegFormat::INVALID_FORMAT);
return (IMLRegID)(m_raw & 0xFFFF);
}
void SetRegID(IMLRegID regId)
{
cemu_assert_debug(regId <= 0xFFFF);
m_raw &= ~0xFFFF;
m_raw |= (uint32)regId;
}
bool IsInvalid() const
{
return GetBaseFormat() == IMLRegFormat::INVALID_FORMAT;
}
bool IsValid() const
{
return GetBaseFormat() != IMLRegFormat::INVALID_FORMAT;
}
bool IsValidAndSameRegID(IMLRegID regId) const
{
return IsValid() && GetRegID() == regId;
}
// risky
bool operator==(const IMLReg& other) const
{
//__debugbreak();
return m_raw == other.m_raw;
}
private:
uint32 m_raw;
};
static const IMLReg IMLREG_INVALID(IMLRegFormat::INVALID_FORMAT, IMLRegFormat::INVALID_FORMAT, 0, 0);
using IMLName = uint32;
@@ -230,6 +326,8 @@ enum
struct IMLUsedRegisters
{
IMLUsedRegisters() {};
// GPR
union
{
@@ -256,59 +354,63 @@ struct IMLUsedRegisters
};
};
bool IsGPRWritten(IMLReg imlReg) const
bool IsBaseGPRWritten(IMLReg imlReg) const
{
cemu_assert_debug(imlReg != IMLREG_INVALID);
return writtenGPR1 == imlReg || writtenGPR2 == imlReg;
cemu_assert_debug(imlReg.IsValid());
auto regId = imlReg.GetRegID();
if (writtenGPR1.IsValid() && writtenGPR1.GetRegID() == regId)
return true;
if (writtenGPR2.IsValid() && writtenGPR2.GetRegID() == regId)
return true;
return false;
}
template<typename Fn>
void ForEachWrittenGPR(Fn F) const
{
if (writtenGPR1 != IMLREG_INVALID)
if (writtenGPR1.IsValid())
F(writtenGPR1);
if (writtenGPR2 != IMLREG_INVALID)
if (writtenGPR2.IsValid())
F(writtenGPR2);
}
template<typename Fn>
void ForEachReadGPR(Fn F) const
{
if (readGPR1 != IMLREG_INVALID)
if (readGPR1.IsValid())
F(readGPR1);
if (readGPR2 != IMLREG_INVALID)
if (readGPR2.IsValid())
F(readGPR2);
if (readGPR3 != IMLREG_INVALID)
if (readGPR3.IsValid())
F(readGPR3);
}
template<typename Fn>
void ForEachAccessedGPR(Fn F) const
{
if (readGPR1 != IMLREG_INVALID)
if (readGPR1.IsValid())
F(readGPR1, false);
if (readGPR2 != IMLREG_INVALID)
if (readGPR2.IsValid())
F(readGPR2, false);
if (readGPR3 != IMLREG_INVALID)
if (readGPR3.IsValid())
F(readGPR3, false);
if (writtenGPR1 != IMLREG_INVALID)
if (writtenGPR1.IsValid())
F(writtenGPR1, true);
if (writtenGPR2 != IMLREG_INVALID)
if (writtenGPR2.IsValid())
F(writtenGPR2, true);
}
bool HasFPRReg(sint16 imlReg) const
bool HasSameBaseFPRRegId(IMLRegID regId) const
{
cemu_assert_debug(imlReg != IMLREG_INVALID);
if (readFPR1 == imlReg)
if (readFPR1.IsValid() && readFPR1.GetRegID() == regId)
return true;
if (readFPR2 == imlReg)
if (readFPR2.IsValid() && readFPR2.GetRegID() == regId)
return true;
if (readFPR3 == imlReg)
if (readFPR3.IsValid() && readFPR3.GetRegID() == regId)
return true;
if (readFPR4 == imlReg)
if (readFPR4.IsValid() && readFPR4.GetRegID() == regId)
return true;
if (writtenFPR1 == imlReg)
if (writtenFPR1.IsValid() && writtenFPR1.GetRegID() == regId)
return true;
return false;
}
@@ -316,6 +418,12 @@ struct IMLUsedRegisters
struct IMLInstruction
{
IMLInstruction() {}
IMLInstruction(const IMLInstruction& other)
{
memcpy(this, &other, sizeof(IMLInstruction));
}
uint8 type;
uint8 operation;
union
@@ -370,6 +478,7 @@ struct IMLInstruction
uint32 param;
uint32 param2;
uint16 paramU16;
IMLReg paramReg;
}op_macro;
struct
{
@@ -446,7 +555,7 @@ struct IMLInstruction
struct
{
// r_s32
uint8 regR;
IMLReg regR;
sint32 immS32;
// condition
uint8 crRegisterIndex;
@@ -479,16 +588,17 @@ struct IMLInstruction
void make_debugbreak(uint32 currentPPCAddress = 0)
{
make_macro(PPCREC_IML_MACRO_DEBUGBREAK, 0, currentPPCAddress, 0);
make_macro(PPCREC_IML_MACRO_DEBUGBREAK, 0, currentPPCAddress, 0, IMLREG_INVALID);
}
void make_macro(uint32 macroId, uint32 param, uint32 param2, uint16 paramU16)
void make_macro(uint32 macroId, uint32 param, uint32 param2, uint16 paramU16, IMLReg regParam)
{
this->type = PPCREC_IML_TYPE_MACRO;
this->operation = macroId;
this->op_macro.param = param;
this->op_macro.param2 = param2;
this->op_macro.paramU16 = paramU16;
this->op_macro.paramReg = regParam;
}
void make_cjump_cycle_check()
@@ -497,85 +607,85 @@ struct IMLInstruction
this->operation = 0;
}
void make_r_r(uint32 operation, uint8 registerResult, uint8 registerA)
void make_r_r(uint32 operation, IMLReg regR, IMLReg regA)
{
this->type = PPCREC_IML_TYPE_R_R;
this->operation = operation;
this->op_r_r.regR = registerResult;
this->op_r_r.regA = registerA;
this->op_r_r.regR = regR;
this->op_r_r.regA = regA;
}
void make_r_s32(uint32 operation, uint8 registerIndex, sint32 immS32)
void make_r_s32(uint32 operation, IMLReg regR, sint32 immS32)
{
this->type = PPCREC_IML_TYPE_R_S32;
this->operation = operation;
this->op_r_immS32.regR = registerIndex;
this->op_r_immS32.regR = regR;
this->op_r_immS32.immS32 = immS32;
}
void make_r_r_r(uint32 operation, uint8 registerResult, uint8 registerA, uint8 registerB)
void make_r_r_r(uint32 operation, IMLReg regR, IMLReg regA, IMLReg regB)
{
this->type = PPCREC_IML_TYPE_R_R_R;
this->operation = operation;
this->op_r_r_r.regR = registerResult;
this->op_r_r_r.regA = registerA;
this->op_r_r_r.regB = registerB;
this->op_r_r_r.regR = regR;
this->op_r_r_r.regA = regA;
this->op_r_r_r.regB = regB;
}
void make_r_r_r_carry(uint32 operation, uint8 registerResult, uint8 registerA, uint8 registerB, uint8 registerCarry)
void make_r_r_r_carry(uint32 operation, IMLReg regR, IMLReg regA, IMLReg regB, IMLReg regCarry)
{
this->type = PPCREC_IML_TYPE_R_R_R_CARRY;
this->operation = operation;
this->op_r_r_r_carry.regR = registerResult;
this->op_r_r_r_carry.regA = registerA;
this->op_r_r_r_carry.regB = registerB;
this->op_r_r_r_carry.regCarry = registerCarry;
this->op_r_r_r_carry.regR = regR;
this->op_r_r_r_carry.regA = regA;
this->op_r_r_r_carry.regB = regB;
this->op_r_r_r_carry.regCarry = regCarry;
}
void make_r_r_s32(uint32 operation, uint8 registerResult, uint8 registerA, sint32 immS32)
void make_r_r_s32(uint32 operation, IMLReg regR, IMLReg regA, sint32 immS32)
{
this->type = PPCREC_IML_TYPE_R_R_S32;
this->operation = operation;
this->op_r_r_s32.regR = registerResult;
this->op_r_r_s32.regA = registerA;
this->op_r_r_s32.regR = regR;
this->op_r_r_s32.regA = regA;
this->op_r_r_s32.immS32 = immS32;
}
void make_r_r_s32_carry(uint32 operation, uint8 registerResult, uint8 registerA, sint32 immS32, uint8 registerCarry)
void make_r_r_s32_carry(uint32 operation, IMLReg regR, IMLReg regA, sint32 immS32, IMLReg regCarry)
{
this->type = PPCREC_IML_TYPE_R_R_S32_CARRY;
this->operation = operation;
this->op_r_r_s32_carry.regR = registerResult;
this->op_r_r_s32_carry.regA = registerA;
this->op_r_r_s32_carry.regR = regR;
this->op_r_r_s32_carry.regA = regA;
this->op_r_r_s32_carry.immS32 = immS32;
this->op_r_r_s32_carry.regCarry = registerCarry;
this->op_r_r_s32_carry.regCarry = regCarry;
}
void make_compare(uint8 registerA, uint8 registerB, uint8 registerResult, IMLCondition cond)
void make_compare(IMLReg regA, IMLReg regB, IMLReg regR, IMLCondition cond)
{
this->type = PPCREC_IML_TYPE_COMPARE;
this->operation = -999;
this->op_compare.regR = registerResult;
this->op_compare.regA = registerA;
this->op_compare.regB = registerB;
this->op_compare.regR = regR;
this->op_compare.regA = regA;
this->op_compare.regB = regB;
this->op_compare.cond = cond;
}
void make_compare_s32(uint8 registerA, sint32 immS32, uint8 registerResult, IMLCondition cond)
void make_compare_s32(IMLReg regA, sint32 immS32, IMLReg regR, IMLCondition cond)
{
this->type = PPCREC_IML_TYPE_COMPARE_S32;
this->operation = -999;
this->op_compare_s32.regR = registerResult;
this->op_compare_s32.regA = registerA;
this->op_compare_s32.regR = regR;
this->op_compare_s32.regA = regA;
this->op_compare_s32.immS32 = immS32;
this->op_compare_s32.cond = cond;
}
void make_conditional_jump(uint8 registerBool, bool mustBeTrue)
void make_conditional_jump(IMLReg regBool, bool mustBeTrue)
{
this->type = PPCREC_IML_TYPE_CONDITIONAL_JUMP;
this->operation = -999;
this->op_conditional_jump.registerBool = registerBool;
this->op_conditional_jump.registerBool = regBool;
this->op_conditional_jump.mustBeTrue = mustBeTrue;
}
@@ -586,12 +696,12 @@ struct IMLInstruction
}
// load from memory
void make_r_memory(uint8 registerDestination, uint8 registerMemory, sint32 immS32, uint32 copyWidth, bool signExtend, bool switchEndian)
void make_r_memory(IMLReg regD, IMLReg regMem, sint32 immS32, uint32 copyWidth, bool signExtend, bool switchEndian)
{
this->type = PPCREC_IML_TYPE_LOAD;
this->operation = 0;
this->op_storeLoad.registerData = registerDestination;
this->op_storeLoad.registerMem = registerMemory;
this->op_storeLoad.registerData = regD;
this->op_storeLoad.registerMem = regMem;
this->op_storeLoad.immS32 = immS32;
this->op_storeLoad.copyWidth = copyWidth;
this->op_storeLoad.flags2.swapEndian = switchEndian;
@@ -599,12 +709,12 @@ struct IMLInstruction
}
// store to memory
void make_memory_r(uint8 registerSource, uint8 registerMemory, sint32 immS32, uint32 copyWidth, bool switchEndian)
void make_memory_r(IMLReg regS, IMLReg regMem, sint32 immS32, uint32 copyWidth, bool switchEndian)
{
this->type = PPCREC_IML_TYPE_STORE;
this->operation = 0;
this->op_storeLoad.registerData = registerSource;
this->op_storeLoad.registerMem = registerMemory;
this->op_storeLoad.registerData = regS;
this->op_storeLoad.registerMem = regMem;
this->op_storeLoad.immS32 = immS32;
this->op_storeLoad.copyWidth = copyWidth;
this->op_storeLoad.flags2.swapEndian = switchEndian;
@@ -633,7 +743,8 @@ struct IMLInstruction
void CheckRegisterUsage(IMLUsedRegisters* registersUsed) const;
void RewriteGPR(const std::unordered_map<IMLReg, IMLReg>& translationTable);
void ReplaceFPRs(sint32 fprRegisterSearched[4], sint32 fprRegisterReplaced[4]);
void ReplaceFPR(sint32 fprRegisterSearched, sint32 fprRegisterReplaced);
void RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& translationTable);
void ReplaceFPRs(IMLReg fprRegisterSearched[4], IMLReg fprRegisterReplaced[4]);
void ReplaceFPR(IMLRegID fprRegisterSearched, IMLRegID fprRegisterReplaced);
};
@@ -8,13 +8,18 @@
bool _RegExceedsFPRSpace(IMLReg r)
{
if (r == IMLREG_INVALID)
if (r.IsInvalid())
return false;
if ((uint32)r >= PPC_X64_FPR_USABLE_REGISTERS)
if (r.GetRegID() >= PPC_X64_FPR_USABLE_REGISTERS)
return true;
return false;
}
IMLReg _FPRRegFromID(IMLRegID regId)
{
return IMLReg(IMLRegFormat::F64, IMLRegFormat::F64, 0, regId);
}
bool PPCRecompiler_reduceNumberOfFPRRegisters(ppcImlGenContext_t* ppcImlGenContext)
{
// only xmm0 to xmm14 may be used, xmm15 is reserved
@@ -48,34 +53,34 @@ bool PPCRecompiler_reduceNumberOfFPRRegisters(ppcImlGenContext_t* ppcImlGenConte
while( true )
{
segIt->imlList[imlIndex].CheckRegisterUsage(&registersUsed);
if(registersUsed.readFPR1 >= PPC_X64_FPR_USABLE_REGISTERS || registersUsed.readFPR2 >= PPC_X64_FPR_USABLE_REGISTERS || registersUsed.readFPR3 >= PPC_X64_FPR_USABLE_REGISTERS || registersUsed.readFPR4 >= PPC_X64_FPR_USABLE_REGISTERS || registersUsed.writtenFPR1 >= PPC_X64_FPR_USABLE_REGISTERS)
if(_RegExceedsFPRSpace(registersUsed.readFPR1) || _RegExceedsFPRSpace(registersUsed.readFPR2) || _RegExceedsFPRSpace(registersUsed.readFPR3) || _RegExceedsFPRSpace(registersUsed.readFPR4) || _RegExceedsFPRSpace(registersUsed.writtenFPR1) )
{
// get index of register to replace
sint32 fprToReplace = -1;
if(_RegExceedsFPRSpace(registersUsed.readFPR1) )
fprToReplace = registersUsed.readFPR1;
fprToReplace = registersUsed.readFPR1.GetRegID();
else if(_RegExceedsFPRSpace(registersUsed.readFPR2) )
fprToReplace = registersUsed.readFPR2;
fprToReplace = registersUsed.readFPR2.GetRegID();
else if (_RegExceedsFPRSpace(registersUsed.readFPR3))
fprToReplace = registersUsed.readFPR3;
fprToReplace = registersUsed.readFPR3.GetRegID();
else if (_RegExceedsFPRSpace(registersUsed.readFPR4))
fprToReplace = registersUsed.readFPR4;
fprToReplace = registersUsed.readFPR4.GetRegID();
else if(_RegExceedsFPRSpace(registersUsed.writtenFPR1) )
fprToReplace = registersUsed.writtenFPR1;
fprToReplace = registersUsed.writtenFPR1.GetRegID();
if (fprToReplace >= 0)
{
// generate mask of useable registers
uint8 useableRegisterMask = 0x7F; // lowest bit is fpr register 0
if (registersUsed.readFPR1 != -1)
useableRegisterMask &= ~(1 << (registersUsed.readFPR1));
if (registersUsed.readFPR2 != -1)
useableRegisterMask &= ~(1 << (registersUsed.readFPR2));
if (registersUsed.readFPR3 != -1)
useableRegisterMask &= ~(1 << (registersUsed.readFPR3));
if (registersUsed.readFPR4 != -1)
useableRegisterMask &= ~(1 << (registersUsed.readFPR4));
if (registersUsed.writtenFPR1 != -1)
useableRegisterMask &= ~(1 << (registersUsed.writtenFPR1));
if (registersUsed.readFPR1.IsValid())
useableRegisterMask &= ~(1 << (registersUsed.readFPR1.GetRegID()));
if (registersUsed.readFPR2.IsValid())
useableRegisterMask &= ~(1 << (registersUsed.readFPR2.GetRegID()));
if (registersUsed.readFPR3.IsValid())
useableRegisterMask &= ~(1 << (registersUsed.readFPR3.GetRegID()));
if (registersUsed.readFPR4.IsValid())
useableRegisterMask &= ~(1 << (registersUsed.readFPR4.GetRegID()));
if (registersUsed.writtenFPR1.IsValid())
useableRegisterMask &= ~(1 << (registersUsed.writtenFPR1.GetRegID()));
// get highest unused register index (0-6 range)
sint32 unusedRegisterIndex = -1;
for (sint32 f = 0; f < PPC_X64_FPR_USABLE_REGISTERS; f++)
@@ -107,7 +112,7 @@ bool PPCRecompiler_reduceNumberOfFPRRegisters(ppcImlGenContext_t* ppcImlGenConte
{
imlInstructionItr->type = PPCREC_IML_TYPE_FPR_NAME_R;
imlInstructionItr->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionItr->op_r_name.regR = unusedRegisterIndex;
imlInstructionItr->op_r_name.regR = _FPRRegFromID(unusedRegisterIndex);
imlInstructionItr->op_r_name.name = ppcImlGenContext->mappedFPRRegister[unusedRegisterIndex];
}
else
@@ -116,14 +121,14 @@ bool PPCRecompiler_reduceNumberOfFPRRegisters(ppcImlGenContext_t* ppcImlGenConte
memset(imlInstructionItr, 0x00, sizeof(IMLInstruction));
imlInstructionItr->type = PPCREC_IML_TYPE_FPR_R_NAME;
imlInstructionItr->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionItr->op_r_name.regR = unusedRegisterIndex;
imlInstructionItr->op_r_name.regR = _FPRRegFromID(unusedRegisterIndex);
imlInstructionItr->op_r_name.name = ppcImlGenContext->mappedFPRRegister[fprToReplace];
// name_gprToReplace = unusedRegister
imlInstructionItr = segIt->imlList.data() + (imlIndex + 3);
memset(imlInstructionItr, 0x00, sizeof(IMLInstruction));
imlInstructionItr->type = PPCREC_IML_TYPE_FPR_NAME_R;
imlInstructionItr->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionItr->op_r_name.regR = unusedRegisterIndex;
imlInstructionItr->op_r_name.regR = _FPRRegFromID(unusedRegisterIndex);
imlInstructionItr->op_r_name.name = ppcImlGenContext->mappedFPRRegister[fprToReplace];
// unusedRegister = name_unusedRegister
imlInstructionItr = segIt->imlList.data() + (imlIndex + 4);
@@ -132,7 +137,7 @@ bool PPCRecompiler_reduceNumberOfFPRRegisters(ppcImlGenContext_t* ppcImlGenConte
{
imlInstructionItr->type = PPCREC_IML_TYPE_FPR_R_NAME;
imlInstructionItr->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionItr->op_r_name.regR = unusedRegisterIndex;
imlInstructionItr->op_r_name.regR = _FPRRegFromID(unusedRegisterIndex);
imlInstructionItr->op_r_name.name = ppcImlGenContext->mappedFPRRegister[unusedRegisterIndex];
}
else
@@ -190,8 +195,8 @@ ppcRecRegisterMapping_t* PPCRecompiler_findUnloadableRegister(ppcRecManageRegist
continue;
if( (unloadLockedMask&(1<<i)) != 0 )
continue;
uint32 virtualReg = rCtx->currentMapping[i].virtualReg;
bool isReserved = instructionUsedRegisters->HasFPRReg(virtualReg);
IMLRegID virtualReg = rCtx->currentMapping[i].virtualReg;
bool isReserved = instructionUsedRegisters->HasSameBaseFPRRegId(virtualReg);
if (isReserved)
continue;
if (rCtx->currentMapping[i].lastUseIndex < unloadIndexLastUse)
@@ -219,22 +224,22 @@ bool PPCRecompiler_manageFPRRegistersForSegment(ppcImlGenContext_t* ppcImlGenCon
if (idxInst.IsSuffixInstruction())
break;
idxInst.CheckRegisterUsage(&registersUsed);
sint32 fprMatch[4]; // should be IMLReg, but this code is being dropped soon anyway
sint32 fprReplace[4];
fprMatch[0] = -1; // should be IMLREG_INVALID
fprMatch[1] = -1;
fprMatch[2] = -1;
fprMatch[3] = -1;
fprReplace[0] = -1;
fprReplace[1] = -1;
fprReplace[2] = -1;
fprReplace[3] = -1;
IMLReg fprMatch[4];
IMLReg fprReplace[4];
fprMatch[0] = IMLREG_INVALID;
fprMatch[1] = IMLREG_INVALID;
fprMatch[2] = IMLREG_INVALID;
fprMatch[3] = IMLREG_INVALID;
fprReplace[0] = IMLREG_INVALID;
fprReplace[1] = IMLREG_INVALID;
fprReplace[2] = IMLREG_INVALID;
fprReplace[3] = IMLREG_INVALID;
// generate a mask of registers that we may not free
sint32 numReplacedOperands = 0;
uint32 unloadLockedMask = 0;
for (sint32 f = 0; f < 5; f++)
{
sint32 virtualFpr;
IMLReg virtualFpr;
if (f == 0)
virtualFpr = registersUsed.readFPR1;
else if (f == 1)
@@ -245,12 +250,14 @@ bool PPCRecompiler_manageFPRRegistersForSegment(ppcImlGenContext_t* ppcImlGenCon
virtualFpr = registersUsed.readFPR4;
else if (f == 4)
virtualFpr = registersUsed.writtenFPR1;
if(virtualFpr == IMLREG_INVALID)
if(virtualFpr.IsInvalid())
continue;
cemu_assert_debug(virtualFpr < 64);
cemu_assert_debug(virtualFpr.GetBaseFormat() == IMLRegFormat::F64);
cemu_assert_debug(virtualFpr.GetRegFormat() == IMLRegFormat::F64);
cemu_assert_debug(virtualFpr.GetRegID() < 64);
// check if this virtual FPR is already loaded in any real register
ppcRecRegisterMapping_t* regMapping;
if (rCtx.ppcRegToMapping[virtualFpr] == -1)
if (rCtx.ppcRegToMapping[virtualFpr.GetRegID()] == -1)
{
// not loaded
// find available register
@@ -269,7 +276,7 @@ bool PPCRecompiler_manageFPRRegistersForSegment(ppcImlGenContext_t* ppcImlGenCon
memset(imlInstructionTemp, 0x00, sizeof(IMLInstruction));
imlInstructionTemp->type = PPCREC_IML_TYPE_FPR_NAME_R;
imlInstructionTemp->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionTemp->op_r_name.regR = (uint8)(unloadRegMapping - rCtx.currentMapping);
imlInstructionTemp->op_r_name.regR = _FPRRegFromID((uint8)(unloadRegMapping - rCtx.currentMapping));
imlInstructionTemp->op_r_name.name = ppcImlGenContext->mappedFPRRegister[unloadRegMapping->virtualReg];
idx++;
// update mapping
@@ -285,18 +292,18 @@ bool PPCRecompiler_manageFPRRegistersForSegment(ppcImlGenContext_t* ppcImlGenCon
memset(imlInstructionTemp, 0x00, sizeof(IMLInstruction));
imlInstructionTemp->type = PPCREC_IML_TYPE_FPR_R_NAME;
imlInstructionTemp->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionTemp->op_r_name.regR = (uint8)(regMapping-rCtx.currentMapping);
imlInstructionTemp->op_r_name.name = ppcImlGenContext->mappedFPRRegister[virtualFpr];
imlInstructionTemp->op_r_name.regR = _FPRRegFromID((uint8)(regMapping-rCtx.currentMapping));
imlInstructionTemp->op_r_name.name = ppcImlGenContext->mappedFPRRegister[virtualFpr.GetRegID()];
idx++;
// update mapping
regMapping->virtualReg = virtualFpr;
rCtx.ppcRegToMapping[virtualFpr] = (sint32)(regMapping - rCtx.currentMapping);
regMapping->virtualReg = virtualFpr.GetRegID();
rCtx.ppcRegToMapping[virtualFpr.GetRegID()] = (sint32)(regMapping - rCtx.currentMapping);
regMapping->lastUseIndex = rCtx.currentUseIndex;
rCtx.currentUseIndex++;
}
else
{
regMapping = rCtx.currentMapping + rCtx.ppcRegToMapping[virtualFpr];
regMapping = rCtx.currentMapping + rCtx.ppcRegToMapping[virtualFpr.GetRegID()];
regMapping->lastUseIndex = rCtx.currentUseIndex;
rCtx.currentUseIndex++;
}
@@ -304,9 +311,9 @@ bool PPCRecompiler_manageFPRRegistersForSegment(ppcImlGenContext_t* ppcImlGenCon
bool entryFound = false;
for (sint32 t = 0; t < numReplacedOperands; t++)
{
if (fprMatch[t] == virtualFpr)
if (fprMatch[t].IsValid() && fprMatch[t].GetRegID() == virtualFpr.GetRegID())
{
cemu_assert_debug(fprReplace[t] == (regMapping - rCtx.currentMapping));
cemu_assert_debug(fprReplace[t] == _FPRRegFromID(regMapping - rCtx.currentMapping));
entryFound = true;
break;
}
@@ -315,7 +322,7 @@ bool PPCRecompiler_manageFPRRegistersForSegment(ppcImlGenContext_t* ppcImlGenCon
{
cemu_assert_debug(numReplacedOperands != 4);
fprMatch[numReplacedOperands] = virtualFpr;
fprReplace[numReplacedOperands] = (sint32)(regMapping - rCtx.currentMapping);
fprReplace[numReplacedOperands] = _FPRRegFromID(regMapping - rCtx.currentMapping);
numReplacedOperands++;
}
}
@@ -345,7 +352,7 @@ bool PPCRecompiler_manageFPRRegistersForSegment(ppcImlGenContext_t* ppcImlGenCon
memset(imlInstructionTemp, 0x00, sizeof(IMLInstruction));
imlInstructionTemp->type = PPCREC_IML_TYPE_FPR_NAME_R;
imlInstructionTemp->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionTemp->op_r_name.regR = i;
imlInstructionTemp->op_r_name.regR = _FPRRegFromID(i);
imlInstructionTemp->op_r_name.name = ppcImlGenContext->mappedFPRRegister[rCtx.currentMapping[i].virtualReg];
idx++;
}
@@ -377,7 +384,7 @@ bool PPCRecompiler_trackRedundantNameLoadInstruction(ppcImlGenContext_t* ppcImlG
imlInstruction->CheckRegisterUsage(&registersUsed);
if( registersUsed.readGPR1 == registerIndex || registersUsed.readGPR2 == registerIndex || registersUsed.readGPR3 == registerIndex )
return false;
if (registersUsed.IsGPRWritten(registerIndex))
if (registersUsed.IsBaseGPRWritten(registerIndex))
return true;
}
// todo: Scan next segment(s)
@@ -389,15 +396,15 @@ bool PPCRecompiler_trackRedundantNameLoadInstruction(ppcImlGenContext_t* ppcImlG
*/
bool PPCRecompiler_trackRedundantFPRNameLoadInstruction(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 startIndex, IMLInstruction* nameStoreInstruction, sint32 scanDepth)
{
sint16 registerIndex = nameStoreInstruction->op_r_name.regR;
IMLRegID regId = nameStoreInstruction->op_r_name.regR.GetRegID();
for(size_t i=startIndex; i<imlSegment->imlList.size(); i++)
{
IMLInstruction* imlInstruction = imlSegment->imlList.data() + i;
IMLUsedRegisters registersUsed;
imlInstruction->CheckRegisterUsage(&registersUsed);
if( registersUsed.readFPR1 == registerIndex || registersUsed.readFPR2 == registerIndex || registersUsed.readFPR3 == registerIndex || registersUsed.readFPR4 == registerIndex)
if( registersUsed.readFPR1.IsValidAndSameRegID(regId) || registersUsed.readFPR2.IsValidAndSameRegID(regId) || registersUsed.readFPR3.IsValidAndSameRegID(regId) || registersUsed.readFPR4.IsValidAndSameRegID(regId))
return false;
if( registersUsed.writtenFPR1 == registerIndex )
if( registersUsed.writtenFPR1.IsValidAndSameRegID(regId) )
return true;
}
// todo: Scan next segment(s)
@@ -409,13 +416,13 @@ bool PPCRecompiler_trackRedundantFPRNameLoadInstruction(ppcImlGenContext_t* ppcI
*/
bool PPCRecompiler_trackRedundantNameStoreInstruction(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 startIndex, IMLInstruction* nameStoreInstruction, sint32 scanDepth)
{
sint16 registerIndex = nameStoreInstruction->op_r_name.regR;
IMLReg regR = nameStoreInstruction->op_r_name.regR;
for(sint32 i=startIndex; i>=0; i--)
{
IMLInstruction* imlInstruction = imlSegment->imlList.data() + i;
IMLUsedRegisters registersUsed;
imlInstruction->CheckRegisterUsage(&registersUsed);
if( registersUsed.IsGPRWritten(registerIndex) )
if( registersUsed.IsBaseGPRWritten(regR) )
{
if( imlSegment->imlList[i].type == PPCREC_IML_TYPE_R_NAME )
return true;
@@ -468,13 +475,13 @@ bool PPCRecompiler_trackOverwrittenNameStoreInstruction(ppcImlGenContext_t* ppcI
*/
bool PPCRecompiler_trackRedundantFPRNameStoreInstruction(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 startIndex, IMLInstruction* nameStoreInstruction, sint32 scanDepth)
{
sint16 registerIndex = nameStoreInstruction->op_r_name.regR;
IMLRegID regId = nameStoreInstruction->op_r_name.regR.GetRegID();
for(sint32 i=startIndex; i>=0; i--)
{
IMLInstruction* imlInstruction = imlSegment->imlList.data() + i;
IMLUsedRegisters registersUsed;
imlInstruction->CheckRegisterUsage(&registersUsed);
if( registersUsed.writtenFPR1 == registerIndex )
if( registersUsed.writtenFPR1.IsValidAndSameRegID(regId))
{
if(imlInstruction->type == PPCREC_IML_TYPE_FPR_R_NAME )
return true;
@@ -485,8 +492,10 @@ bool PPCRecompiler_trackRedundantFPRNameStoreInstruction(ppcImlGenContext_t* ppc
return false;
}
void PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 imlIndexLoad, sint32 fprIndex)
void PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 imlIndexLoad, IMLReg fprReg)
{
IMLRegID fprIndex = fprReg.GetRegID();
IMLInstruction* imlInstructionLoad = imlSegment->imlList.data() + imlIndexLoad;
if (imlInstructionLoad->op_storeLoad.flags2.notExpanded)
return;
@@ -504,7 +513,7 @@ void PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcI
if ((imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE && imlInstruction->op_storeLoad.mode == PPCREC_FPR_ST_MODE_SINGLE_FROM_PS0) ||
(imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE_INDEXED && imlInstruction->op_storeLoad.mode == PPCREC_FPR_ST_MODE_SINGLE_FROM_PS0))
{
if (imlInstruction->op_storeLoad.registerData == fprIndex)
if (imlInstruction->op_storeLoad.registerData.GetRegID() == fprIndex)
{
if (foundMatch == false)
{
@@ -524,15 +533,15 @@ void PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcI
// check if FPR is overwritten (we can actually ignore read operations?)
imlInstruction->CheckRegisterUsage(&registersUsed);
if (registersUsed.writtenFPR1 == fprIndex)
if (registersUsed.writtenFPR1.IsValidAndSameRegID(fprIndex))
break;
if (registersUsed.readFPR1 == fprIndex)
if (registersUsed.readFPR1.IsValidAndSameRegID(fprIndex))
break;
if (registersUsed.readFPR2 == fprIndex)
if (registersUsed.readFPR2.IsValidAndSameRegID(fprIndex))
break;
if (registersUsed.readFPR3 == fprIndex)
if (registersUsed.readFPR3.IsValidAndSameRegID(fprIndex))
break;
if (registersUsed.readFPR4 == fprIndex)
if (registersUsed.readFPR4.IsValidAndSameRegID(fprIndex))
break;
}
@@ -540,7 +549,7 @@ void PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcI
{
// insert expand instruction after store
IMLInstruction* newExpand = PPCRecompiler_insertInstruction(imlSegment, lastStore);
PPCRecompilerImlGen_generateNewInstruction_fpr_r(ppcImlGenContext, newExpand, PPCREC_IML_OP_FPR_EXPAND_BOTTOM32_TO_BOTTOM64_AND_TOP64, fprIndex);
PPCRecompilerImlGen_generateNewInstruction_fpr_r(ppcImlGenContext, newExpand, PPCREC_IML_OP_FPR_EXPAND_BOTTOM32_TO_BOTTOM64_AND_TOP64, _FPRRegFromID(fprIndex));
}
}
@@ -574,8 +583,12 @@ void PPCRecompiler_optimizeDirectFloatCopies(ppcImlGenContext_t* ppcImlGenContex
}
}
void PPCRecompiler_optimizeDirectIntegerCopiesScanForward(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 imlIndexLoad, sint32 gprIndex)
void PPCRecompiler_optimizeDirectIntegerCopiesScanForward(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 imlIndexLoad, IMLReg gprReg)
{
cemu_assert_debug(gprReg.GetBaseFormat() == IMLRegFormat::I64); // todo - proper handling required for non-standard sizes
cemu_assert_debug(gprReg.GetRegFormat() == IMLRegFormat::I32);
IMLRegID gprIndex = gprReg.GetRegID();
IMLInstruction* imlInstructionLoad = imlSegment->imlList.data() + imlIndexLoad;
if ( imlInstructionLoad->op_storeLoad.flags2.swapEndian == false )
return;
@@ -591,9 +604,9 @@ void PPCRecompiler_optimizeDirectIntegerCopiesScanForward(ppcImlGenContext_t* pp
// check if GPR is stored
if ((imlInstruction->type == PPCREC_IML_TYPE_STORE && imlInstruction->op_storeLoad.copyWidth == 32 ) )
{
if (imlInstruction->op_storeLoad.registerMem == gprIndex)
if (imlInstruction->op_storeLoad.registerMem.GetRegID() == gprIndex)
break;
if (imlInstruction->op_storeLoad.registerData == gprIndex)
if (imlInstruction->op_storeLoad.registerData.GetRegID() == gprIndex)
{
IMLInstruction* imlInstructionStore = imlInstruction;
if (foundMatch == false)
@@ -610,18 +623,18 @@ void PPCRecompiler_optimizeDirectIntegerCopiesScanForward(ppcImlGenContext_t* pp
}
// check if GPR is accessed
imlInstruction->CheckRegisterUsage(&registersUsed);
if (registersUsed.readGPR1 == gprIndex ||
registersUsed.readGPR2 == gprIndex ||
registersUsed.readGPR3 == gprIndex)
if (registersUsed.readGPR1.IsValidAndSameRegID(gprIndex) ||
registersUsed.readGPR2.IsValidAndSameRegID(gprIndex) ||
registersUsed.readGPR3.IsValidAndSameRegID(gprIndex))
{
break;
}
if (registersUsed.IsGPRWritten(gprIndex))
if (registersUsed.IsBaseGPRWritten(gprReg))
return; // GPR overwritten, we don't need to byte swap anymore
}
if (foundMatch)
{
PPCRecompiler_insertInstruction(imlSegment, i)->make_r_r(PPCREC_IML_OP_ENDIAN_SWAP, gprIndex, gprIndex);
PPCRecompiler_insertInstruction(imlSegment, i)->make_r_r(PPCREC_IML_OP_ENDIAN_SWAP, gprReg, gprReg);
}
}
@@ -650,15 +663,19 @@ void PPCRecompiler_optimizeDirectIntegerCopies(ppcImlGenContext_t* ppcImlGenCont
}
}
sint32 _getGQRIndexFromRegister(ppcImlGenContext_t* ppcImlGenContext, sint32 registerIndex)
sint32 _getGQRIndexFromRegister(ppcImlGenContext_t* ppcImlGenContext, IMLReg gqrReg)
{
if (registerIndex == PPC_REC_INVALID_REGISTER)
if (gqrReg.IsInvalid())
return -1;
sint32 namedReg = ppcImlGenContext->mappedRegister[registerIndex];
sint32 namedReg = ppcImlGenContext->mappedRegister[gqrReg.GetRegID()];
if (namedReg >= (PPCREC_NAME_SPR0 + SPR_UGQR0) && namedReg <= (PPCREC_NAME_SPR0 + SPR_UGQR7))
{
return namedReg - (PPCREC_NAME_SPR0 + SPR_UGQR0);
}
else
{
cemu_assert_suspicious();
}
return -1;
}
@@ -694,7 +711,7 @@ void PPCRecompiler_optimizePSQLoadAndStore(ppcImlGenContext_t* ppcImlGenContext)
instIt.op_storeLoad.mode != PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1 )
continue;
// get GQR value
cemu_assert_debug(instIt.op_storeLoad.registerGQR != PPC_REC_INVALID_REGISTER);
cemu_assert_debug(instIt.op_storeLoad.registerGQR.IsValid());
sint32 gqrIndex = _getGQRIndexFromRegister(ppcImlGenContext, instIt.op_storeLoad.registerGQR);
cemu_assert(gqrIndex >= 0);
if (ppcImlGenContext->tracking.modifiesGQR[gqrIndex])
@@ -720,7 +737,7 @@ void PPCRecompiler_optimizePSQLoadAndStore(ppcImlGenContext_t* ppcImlGenContext)
else if (formatType == 7)
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_S16_PS0;
if (instIt.op_storeLoad.mode != PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0)
instIt.op_storeLoad.registerGQR = PPC_REC_INVALID_REGISTER;
instIt.op_storeLoad.registerGQR = IMLREG_INVALID;
}
else if (instIt.op_storeLoad.mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1)
{
@@ -735,7 +752,7 @@ void PPCRecompiler_optimizePSQLoadAndStore(ppcImlGenContext_t* ppcImlGenContext)
else if (formatType == 7)
instIt.op_storeLoad.mode = PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1;
if (instIt.op_storeLoad.mode != PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1)
instIt.op_storeLoad.registerGQR = PPC_REC_INVALID_REGISTER;
instIt.op_storeLoad.registerGQR = IMLREG_INVALID;
}
}
else if (instIt.type == PPCREC_IML_TYPE_FPR_STORE || instIt.type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)
@@ -744,7 +761,7 @@ void PPCRecompiler_optimizePSQLoadAndStore(ppcImlGenContext_t* ppcImlGenContext)
instIt.op_storeLoad.mode != PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1)
continue;
// get GQR value
cemu_assert_debug(instIt.op_storeLoad.registerGQR != PPC_REC_INVALID_REGISTER);
cemu_assert_debug(instIt.op_storeLoad.registerGQR.IsValid());
sint32 gqrIndex = _getGQRIndexFromRegister(ppcImlGenContext, instIt.op_storeLoad.registerGQR);
cemu_assert(gqrIndex >= 0 && gqrIndex < 8);
if (ppcImlGenContext->tracking.modifiesGQR[gqrIndex])
@@ -769,7 +786,7 @@ void PPCRecompiler_optimizePSQLoadAndStore(ppcImlGenContext_t* ppcImlGenContext)
else if (formatType == 7)
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_S16_PS0;
if (instIt.op_storeLoad.mode != PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0)
instIt.op_storeLoad.registerGQR = PPC_REC_INVALID_REGISTER;
instIt.op_storeLoad.registerGQR = IMLREG_INVALID;
}
else if (instIt.op_storeLoad.mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1)
{
@@ -784,7 +801,7 @@ void PPCRecompiler_optimizePSQLoadAndStore(ppcImlGenContext_t* ppcImlGenContext)
else if (formatType == 7)
instIt.op_storeLoad.mode = PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1;
if (instIt.op_storeLoad.mode != PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1)
instIt.op_storeLoad.registerGQR = PPC_REC_INVALID_REGISTER;
instIt.op_storeLoad.registerGQR = IMLREG_INVALID;
}
}
}
@@ -123,18 +123,23 @@ void PPCRecRA_identifyLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* iml
typedef struct
{
uint16 registerIndex;
IMLRegID registerIndex;
uint16 registerName;
}raLoadStoreInfo_t;
void PPCRecRA_insertGPRLoadInstruction(IMLSegment* imlSegment, sint32 insertIndex, sint32 registerIndex, sint32 registerName)
IMLReg _MakeNativeGPR(IMLRegID regId)
{
return IMLReg(IMLRegFormat::I64, IMLRegFormat::I64, 0, regId);
}
void PPCRecRA_insertGPRLoadInstruction(IMLSegment* imlSegment, sint32 insertIndex, IMLRegID registerIndex, sint32 registerName)
{
PPCRecompiler_pushBackIMLInstructions(imlSegment, insertIndex, 1);
IMLInstruction* imlInstructionItr = imlSegment->imlList.data() + (insertIndex + 0);
memset(imlInstructionItr, 0x00, sizeof(IMLInstruction));
imlInstructionItr->type = PPCREC_IML_TYPE_R_NAME;
imlInstructionItr->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionItr->op_r_name.regR = registerIndex;
imlInstructionItr->op_r_name.regR = _MakeNativeGPR(registerIndex);
imlInstructionItr->op_r_name.name = registerName;
}
@@ -147,19 +152,19 @@ void PPCRecRA_insertGPRLoadInstructions(IMLSegment* imlSegment, sint32 insertInd
IMLInstruction* imlInstructionItr = imlSegment->imlList.data() + (insertIndex + i);
imlInstructionItr->type = PPCREC_IML_TYPE_R_NAME;
imlInstructionItr->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionItr->op_r_name.regR = (uint8)loadList[i].registerIndex;
imlInstructionItr->op_r_name.regR = _MakeNativeGPR(loadList[i].registerIndex);
imlInstructionItr->op_r_name.name = (uint32)loadList[i].registerName;
}
}
void PPCRecRA_insertGPRStoreInstruction(IMLSegment* imlSegment, sint32 insertIndex, sint32 registerIndex, sint32 registerName)
void PPCRecRA_insertGPRStoreInstruction(IMLSegment* imlSegment, sint32 insertIndex, IMLRegID registerIndex, sint32 registerName)
{
PPCRecompiler_pushBackIMLInstructions(imlSegment, insertIndex, 1);
IMLInstruction* imlInstructionItr = imlSegment->imlList.data() + (insertIndex + 0);
memset(imlInstructionItr, 0x00, sizeof(IMLInstruction));
imlInstructionItr->type = PPCREC_IML_TYPE_NAME_R;
imlInstructionItr->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionItr->op_r_name.regR = registerIndex;
imlInstructionItr->op_r_name.regR = _MakeNativeGPR(registerIndex);
imlInstructionItr->op_r_name.name = registerName;
}
@@ -173,7 +178,7 @@ void PPCRecRA_insertGPRStoreInstructions(IMLSegment* imlSegment, sint32 insertIn
memset(imlInstructionItr, 0x00, sizeof(IMLInstruction));
imlInstructionItr->type = PPCREC_IML_TYPE_NAME_R;
imlInstructionItr->operation = PPCREC_IML_OP_ASSIGN;
imlInstructionItr->op_r_name.regR = (uint8)storeList[i].registerIndex;
imlInstructionItr->op_r_name.regR = _MakeNativeGPR(storeList[i].registerIndex);
imlInstructionItr->op_r_name.name = (uint32)storeList[i].registerName;
}
}
@@ -368,7 +373,7 @@ void _sortSegmentAllSubrangesLinkedList(IMLSegment* imlSegment)
raLivenessSubrange_t* _GetSubrangeByInstructionIndexAndVirtualReg(IMLSegment* imlSegment, IMLReg regToSearch, sint32 instructionIndex)
{
uint32 regId = regToSearch & 0xFF;
uint32 regId = regToSearch.GetRegID();
raLivenessSubrange_t* subrangeItr = imlSegment->raInfo.linkedList_perVirtualGPR[regId];
while (subrangeItr)
{
@@ -828,7 +833,7 @@ void IMLRA_GenerateSegmentInstructions(ppcImlGenContext_t* ppcImlGenContext, IML
sint16 virtualReg2PhysReg[IML_RA_VIRT_REG_COUNT_MAX];
for (sint32 i = 0; i < IML_RA_VIRT_REG_COUNT_MAX; i++)
virtualReg2PhysReg[i] = -1;
std::unordered_map<IMLReg, IMLReg> virt2PhysRegMap; // key = virtual register, value = physical register
std::unordered_map<IMLRegID, IMLRegID> virtId2PhysRegIdMap; // key = virtual register, value = physical register
IMLRALivenessTimeline livenessTimeline;
sint32 index = 0;
sint32 suffixInstructionCount = imlSegment->HasSuffixInstruction() ? 1 : 0;
@@ -850,7 +855,7 @@ void IMLRA_GenerateSegmentInstructions(ppcImlGenContext_t* ppcImlGenContext, IML
assert_dbg();
#endif
virtualReg2PhysReg[subrangeItr->range->virtualRegister] = subrangeItr->range->physicalRegister;
virt2PhysRegMap.insert_or_assign(subrangeItr->range->virtualRegister, subrangeItr->range->physicalRegister);
virtId2PhysRegIdMap.insert_or_assign(subrangeItr->range->virtualRegister, subrangeItr->range->physicalRegister);
}
// next
subrangeItr = subrangeItr->link_segmentSubrangesGPR.next;
@@ -866,7 +871,7 @@ void IMLRA_GenerateSegmentInstructions(ppcImlGenContext_t* ppcImlGenContext, IML
if (virtualReg2PhysReg[expiredRange->range->virtualRegister] == -1)
assert_dbg();
virtualReg2PhysReg[expiredRange->range->virtualRegister] = -1;
virt2PhysRegMap.erase(expiredRange->range->virtualRegister);
virtId2PhysRegIdMap.erase(expiredRange->range->virtualRegister);
// store GPR if required
// special care has to be taken to execute any stores before the suffix instruction since trailing instructions may not get executed
if (expiredRange->hasStore)
@@ -900,13 +905,13 @@ void IMLRA_GenerateSegmentInstructions(ppcImlGenContext_t* ppcImlGenContext, IML
// update translation table
cemu_assert_debug(virtualReg2PhysReg[subrangeItr->range->virtualRegister] == -1);
virtualReg2PhysReg[subrangeItr->range->virtualRegister] = subrangeItr->range->physicalRegister;
virt2PhysRegMap.insert_or_assign(subrangeItr->range->virtualRegister, subrangeItr->range->physicalRegister);
virtId2PhysRegIdMap.insert_or_assign(subrangeItr->range->virtualRegister, subrangeItr->range->physicalRegister);
}
subrangeItr = subrangeItr->link_segmentSubrangesGPR.next;
}
// rewrite registers
if (index < imlSegment->imlList.size())
imlSegment->imlList[index].RewriteGPR(virt2PhysRegMap);
imlSegment->imlList[index].RewriteGPR(virtId2PhysRegIdMap);
// next iml instruction
index++;
}
@@ -919,7 +924,7 @@ void IMLRA_GenerateSegmentInstructions(ppcImlGenContext_t* ppcImlGenContext, IML
// update translation table
cemu_assert_debug(virtualReg2PhysReg[liverange->range->virtualRegister] != -1);
virtualReg2PhysReg[liverange->range->virtualRegister] = -1;
virt2PhysRegMap.erase(liverange->range->virtualRegister);
virtId2PhysRegIdMap.erase(liverange->range->virtualRegister);
// store GPR
if (liverange->hasStore)
{
@@ -951,7 +956,7 @@ void IMLRA_GenerateSegmentInstructions(ppcImlGenContext_t* ppcImlGenContext, IML
// update translation table
cemu_assert_debug(virtualReg2PhysReg[subrangeItr->range->virtualRegister] == -1);
virtualReg2PhysReg[subrangeItr->range->virtualRegister] = subrangeItr->range->physicalRegister;
virt2PhysRegMap.insert_or_assign(subrangeItr->range->virtualRegister, subrangeItr->range->physicalRegister);
virtId2PhysRegIdMap.insert_or_assign(subrangeItr->range->virtualRegister, subrangeItr->range->physicalRegister);
}
// next
subrangeItr = subrangeItr->link_segmentSubrangesGPR.next;
@@ -1063,7 +1068,8 @@ void PPCRecRA_calculateSegmentMinMaxRanges(ppcImlGenContext_t* ppcImlGenContext,
while (index < imlSegment->imlList.size())
{
imlSegment->imlList[index].CheckRegisterUsage(&gprTracking);
gprTracking.ForEachAccessedGPR([&](IMLReg gprId, bool isWritten) {
gprTracking.ForEachAccessedGPR([&](IMLReg gprReg, bool isWritten) {
IMLRegID gprId = gprReg.GetRegID();
cemu_assert_debug(gprId < IML_RA_VIRT_REG_COUNT_MAX);
imlSegment->raDistances.reg[gprId].usageStart = std::min<sint32>(imlSegment->raDistances.reg[gprId].usageStart, index); // index before/at instruction
imlSegment->raDistances.reg[gprId].usageEnd = std::max<sint32>(imlSegment->raDistances.reg[gprId].usageEnd, index + 1); // index after instruction
@@ -1156,7 +1162,8 @@ void PPCRecRA_createSegmentLivenessRanges(ppcImlGenContext_t* ppcImlGenContext,
while (index < imlSegment->imlList.size())
{
imlSegment->imlList[index].CheckRegisterUsage(&gprTracking);
gprTracking.ForEachAccessedGPR([&](IMLReg gprId, bool isWritten) {
gprTracking.ForEachAccessedGPR([&](IMLReg gprReg, bool isWritten) {
IMLRegID gprId = gprReg.GetRegID();
// add location
PPCRecRA_updateOrAddSubrangeLocation(vGPR2Subrange[gprId], index, !isWritten, isWritten);
#ifdef CEMU_DEBUG_ASSERT
@@ -270,9 +270,9 @@ bool PPCRecompiler_ApplyIMLPasses(ppcImlGenContext_t& ppcImlGenContext)
accessedTempReg[4] = registersUsed.writtenFPR1;
for (sint32 f = 0; f < 5; f++)
{
if (accessedTempReg[f] == IMLREG_INVALID)
if (accessedTempReg[f].IsInvalid())
continue;
uint32 regName = ppcImlGenContext.mappedFPRRegister[accessedTempReg[f]];
uint32 regName = ppcImlGenContext.mappedFPRRegister[accessedTempReg[f].GetRegID()];
if (regName >= PPCREC_NAME_FPR0 && regName < PPCREC_NAME_FPR0 + 32)
{
segIt->ppcFPRUsed[regName - PPCREC_NAME_FPR0] = true;
@@ -15,15 +15,15 @@ void PPCRecompilerIml_setSegmentPoint(IMLSegmentPoint* segmentPoint, IMLSegment*
void PPCRecompilerIml_removeSegmentPoint(IMLSegmentPoint* segmentPoint);
// GPR register management
uint32 PPCRecompilerImlGen_loadRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName);
IMLReg PPCRecompilerImlGen_loadRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName);
// FPR register management
uint32 PPCRecompilerImlGen_loadFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName, bool loadNew = false);
uint32 PPCRecompilerImlGen_loadOverwriteFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName);
IMLReg PPCRecompilerImlGen_loadFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName, bool loadNew = false);
IMLReg PPCRecompilerImlGen_loadOverwriteFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName);
// IML instruction generation
void PPCRecompilerImlGen_generateNewInstruction_conditional_r_s32(ppcImlGenContext_t* ppcImlGenContext, IMLInstruction* imlInstruction, uint32 operation, uint8 registerIndex, sint32 immS32, uint32 crRegisterIndex, uint32 crBitIndex, bool bitMustBeSet);
void PPCRecompilerImlGen_generateNewInstruction_fpr_r(ppcImlGenContext_t* ppcImlGenContext, IMLInstruction* imlInstruction, sint32 operation, uint8 registerResult, sint32 crRegister = PPC_REC_INVALID_REGISTER);
void PPCRecompilerImlGen_generateNewInstruction_conditional_r_s32(ppcImlGenContext_t* ppcImlGenContext, IMLInstruction* imlInstruction, uint32 operation, IMLReg registerIndex, sint32 immS32, uint32 crRegisterIndex, uint32 crBitIndex, bool bitMustBeSet);
void PPCRecompilerImlGen_generateNewInstruction_fpr_r(ppcImlGenContext_t* ppcImlGenContext, IMLInstruction* imlInstruction, sint32 operation, IMLReg registerResult);
// IML generation - FPU
bool PPCRecompilerImlGen_LFS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff