diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp index 3560ce741..fc7292287 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp @@ -136,12 +136,8 @@ DEF_OP(LoadRegister) { const auto OpSize = IROp->Size; if (Op->Class == IR::GPRClass) { - unsigned Reg = Op->Reg == Core::CPUState::PF_AS_GREG ? (StaticRegisters.size() - 2) : - Op->Reg == Core::CPUState::AF_AS_GREG ? (StaticRegisters.size() - 1) : - Op->Reg; - - LOGMAN_THROW_A_FMT(Reg < StaticRegisters.size(), "out of range reg"); - const auto reg = StaticRegisters[Reg]; + LOGMAN_THROW_A_FMT(Op->Reg < StaticRegisters.size(), "out of range reg"); + const auto reg = StaticRegisters[Op->Reg]; if (GetReg(Node).Idx() != reg.Idx()) { if (OpSize == 4) { @@ -170,6 +166,30 @@ DEF_OP(LoadRegister) { } } +DEF_OP(LoadPF) { + const auto reg = StaticRegisters[StaticRegisters.size() - 2]; + + if (GetReg(Node).Idx() != reg.Idx()) { + if (IROp->Size == 4) { + mov(GetReg(Node).W(), reg.W()); + } else { + mov(GetReg(Node).X(), reg.X()); + } + } +} + +DEF_OP(LoadAF) { + const auto reg = StaticRegisters[StaticRegisters.size() - 1]; + + if (GetReg(Node).Idx() != reg.Idx()) { + if (IROp->Size == 4) { + mov(GetReg(Node).W(), reg.W()); + } else { + mov(GetReg(Node).X(), reg.X()); + } + } +} + DEF_OP(StoreRegister) { const auto Op = IROp->C(); @@ -206,6 +226,28 @@ DEF_OP(StoreRegister) { } } +DEF_OP(StorePF) { + const auto Op = IROp->C(); + const auto reg = StaticRegisters[StaticRegisters.size() - 2]; + const auto Src = GetReg(Op->Value.ID()); + + if (Src.Idx() != reg.Idx()) { + // Always use 64-bit, it's faster. Upper bits ignored for 32-bit mode. + mov(ARMEmitter::Size::i64Bit, reg, Src); + } +} + +DEF_OP(StoreAF) { + const auto Op = IROp->C(); + const auto reg = StaticRegisters[StaticRegisters.size() - 1]; + const auto Src = GetReg(Op->Value.ID()); + + if (Src.Idx() != reg.Idx()) { + // Always use 64-bit, it's faster. Upper bits ignored for 32-bit mode. + mov(ARMEmitter::Size::i64Bit, reg, Src); + } +} + DEF_OP(LoadContextIndexed) { const auto Op = IROp->C(); const auto OpSize = IROp->Size; diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index cc020ba7c..40f14fb3b 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -1236,8 +1236,12 @@ public: uint32_t Index = 63 - std::countl_zero(Bits); Ref Value = RegCache.Value[Index]; - if (Index >= GPR0Index && Index <= AFIndex) { + if (Index >= GPR0Index && Index <= GPR15Index) { _StoreRegister(Value, Index - GPR0Index, GPRClass, GPRSize); + } else if (Index == PFIndex) { + _StorePF(Value, GPRSize); + } else if (Index == AFIndex) { + _StoreAF(Value, GPRSize); } else if (Index >= FPR0Index && Index <= FPR15Index) { _StoreRegister(Value, Index - FPR0Index, FPRClass, VectorSize); } else if (Index == DFIndex) { @@ -1896,6 +1900,10 @@ private: if (Size == 8) { RegCache.Partial |= Bit; } + } else if (Index == PFIndex) { + RegCache.Value[Index] = _LoadPF(Size); + } else if (Index == AFIndex) { + RegCache.Value[Index] = _LoadAF(Size); } else { RegCache.Value[Index] = _LoadRegister(Offset, RegClass, Size); } diff --git a/FEXCore/Source/Interface/IR/IR.json b/FEXCore/Source/Interface/IR/IR.json index f9711fa5a..c061f407d 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -366,14 +366,36 @@ "DestSize": "Size" }, + "GPR = LoadPF u8:#Size": { + "Desc": ["Loads raw PF"], + "DestSize": "Size" + }, + + "GPR = LoadAF u8:#Size": { + "Desc": ["Loads raw PF"], + "DestSize": "Size" + }, + "StoreRegister SSA:$Value, u32:$Reg, RegisterClass:$Class, u8:#Size": { - "HasSideEffects": true, + "HasSideEffects": true, "Desc": ["Stores a value to a given register.", "Size must match the execution mode."], "DestSize": "Size", "EmitValidation": [ "WalkFindRegClass($Value) == $Class" ] + }, + + "StorePF GPR:$Value, u8:#Size": { + "HasSideEffects": true, + "Desc": ["Stores raw PF"], + "DestSize": "Size" + }, + + "StoreAF GPR:$Value, u8:#Size": { + "HasSideEffects": true, + "Desc": ["Stores raw AF"], + "DestSize": "Size" } }, "Memory": { diff --git a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index 55d2c3fba..dd98d5826 100644 --- a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -23,8 +23,8 @@ $end_info$ #define FLAG_C (1U << 1) #define FLAG_Z (1U << 2) #define FLAG_N (1U << 3) -#define FLAG_A (1U << 4) -#define FLAG_P (1U << 5) +#define FLAG_P (1U << 4) +#define FLAG_A (1U << 5) #define FLAG_ZCV (FLAG_Z | FLAG_C | FLAG_V) #define FLAG_NZCV (FLAG_N | FLAG_ZCV) @@ -68,10 +68,6 @@ private: bool EliminateDeadCode(IREmitter* IREmit, Ref CodeNode, IROp_Header* IROp); }; -unsigned DeadFlagCalculationEliminination::FlagForReg(unsigned Reg) { - return Reg == Core::CPUState::PF_AS_GREG ? FLAG_P : Reg == Core::CPUState::AF_AS_GREG ? FLAG_A : 0; -}; - unsigned DeadFlagCalculationEliminination::FlagsForCondClassType(CondClassType Cond) { switch (Cond) { case COND_AL: return 0; @@ -233,6 +229,11 @@ FlagInfo DeadFlagCalculationEliminination::Classify(IROp_Header* IROp) { .CanEliminate = true, }; + case OP_LOADPF: return {.Read = FLAG_P}; + case OP_LOADAF: return {.Read = FLAG_A}; + case OP_STOREPF: return {.Write = FLAG_P, .CanEliminate = true}; + case OP_STOREAF: return {.Write = FLAG_A, .CanEliminate = true}; + case OP_NZCVSELECT: case OP_NZCVSELECTINCREMENT: { auto Op = IROp->CW(); @@ -315,29 +316,6 @@ FlagInfo DeadFlagCalculationEliminination::Classify(IROp_Header* IROp) { }; } - case OP_LOADREGISTER: { - auto Op = IROp->CW(); - if (Op->Class != GPRClass) { - break; - } - - return {.Read = FlagForReg(Op->Reg)}; - } - - case OP_STOREREGISTER: { - auto Op = IROp->CW(); - if (Op->Class != GPRClass) { - break; - } - - unsigned Flag = FlagForReg(Op->Reg); - - return { - .Write = Flag, - .CanEliminate = Flag != 0, - }; - } - default: break; } diff --git a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index 48812ab42..0707abf03 100644 --- a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -228,11 +228,14 @@ private: }; Ref DecodeSRANode(const IROp_Header* IROp, Ref Node) { - if (IROp->Op == OP_LOADREGISTER) { + if (IROp->Op == OP_LOADREGISTER || IROp->Op == OP_LOADPF || IROp->Op == OP_LOADAF) { return Node; } else if (IROp->Op == OP_STOREREGISTER) { const IROp_StoreRegister* Op = IROp->C(); return IR->GetNode(Op->Value); + } else if (IROp->Op == OP_STOREPF || IROp->Op == OP_STOREAF) { + const IROp_StorePF* Op = IROp->C(); + return IR->GetNode(Op->Value); } return nullptr; @@ -242,6 +245,8 @@ private: RegisterClassType Class; uint8_t Reg; + uint8_t FlagOffset = Classes[GPRFixedClass.Val].Count - 2; + if (IROp->Op == OP_LOADREGISTER) { const IROp_LoadRegister* Op = IROp->C(); @@ -253,17 +258,15 @@ private: Class = Op->Class; Reg = Op->Reg; + } else if (IROp->Op == OP_LOADPF || IROp->Op == OP_STOREPF) { + return PhysicalRegister {GPRFixedClass, FlagOffset}; + } else if (IROp->Op == OP_LOADAF || IROp->Op == OP_STOREAF) { + return PhysicalRegister {GPRFixedClass, (uint8_t)(FlagOffset + 1)}; } LOGMAN_THROW_A_FMT(Class == GPRClass || Class == FPRClass, "SRA classes"); - uint8_t FlagOffset = Classes[GPRFixedClass.Val].Count - 2; - if (Class == FPRClass) { return PhysicalRegister {FPRFixedClass, Reg}; - } else if (Reg == Core::CPUState::PF_AS_GREG) { - return PhysicalRegister {GPRFixedClass, FlagOffset}; - } else if (Reg == Core::CPUState::AF_AS_GREG) { - return PhysicalRegister {GPRFixedClass, (uint8_t)(FlagOffset + 1)}; } else { return PhysicalRegister {GPRFixedClass, Reg}; }